--- /dev/null
+PowerDNS.COM BV and a cast of thousands ;-)
\ No newline at end of file
--- /dev/null
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with this program; if not, write to the Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
\ No newline at end of file
--- /dev/null
+PowerDNS is copyright © 2002-2016 by PowerDNS.COM BV and lots of
+contributors, using the GNU GPLv2 license (see NOTICE for the
+exact license and exception used).
+
+All documentation can be found on http://doc.powerdns.com/
+
+This file may lag behind at times. For most recent updates, always check
+https://doc.powerdns.com/md/changelog/.
+
+Another good place to look for information is:
+https://doc.powerdns.com/md/appendix/compiling-powerdns/
+
+To file bugs, head towards:
+https://github.com/PowerDNS/pdns/issues
+
+But please check if the issue is already reported there first.
+
+SOURCE CODE / GIT
+-----------------
+Source code is available on GitHub:
+
+```
+$ git clone https://github.com/PowerDNS/pdns.git
+```
+
+This repository contains the sources for the PowerDNS Recursor, the PowerDNS
+Authoritative Server, and dnsdist (a powerful DNS loadbalancer). All three can
+be built from this repository. However, all three released separately as .tar.bz2,
+.deb and .rpm.
+
+COMPILING Authoritative Server
+------------------------------
+The PowerDNS Authoritative Server depends on Boost, OpenSSL and requires a
+compiler with C++-2011 support.
+
+On Debian 8.0, the following is useful:
+
+```
+$ apt-get install g++ libboost-all-dev libtool make pkg-config libmysqlclient-dev libssl-dev
+```
+
+When building from git, the following packages are also required: autoconf, automake,
+ragel, bison and flex, then generate the configure file:
+
+```
+$ ./bootstrap
+```
+
+To compile a very clean version, use:
+
+```
+$ ./configure --with-modules="" --without-lua
+$ make
+# make install
+```
+
+This generates a PowerDNS Authoritative Server binary with no modules built in.
+
+When `./configure` is run without `--with-modules`, the bind and gmysql module are
+built-in by default and the pipe-backend is compiled for runtime loading.
+
+To add multiple modules, try:
+
+```
+$ ./configure --with-modules="bind gmysql gpgsql"
+```
+
+Note that you will need the development headers for PostgreSQL as well in this case.
+
+See https://doc.powerdns.com/md/appendix/compiling-powerdns/ for more details.
+
+If you run into C++11-related symbol trouble, please try passing `CPPFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0` (or 1) to `./configure` to make sure you are compatible with the installed dependencies.
+
+COMPILING THE RECURSOR
+----------------------
+See the README in pdns/recursordist.
+
+COMPILING DNSDIST
+----------------------
+See the README in pdns/dnsdistdist.
+
+SOLARIS NOTES
+-------------
+Use a recent gcc. OpenCSW is a good source, as is Solaris 11 IPS.
+
+If you encounter problems with the Solaris make, gmake is advised.
+
+FREEBSD NOTES
+-------------
+You need to compile using gmake - regular make only appears to work, but doesn't in fact. Use gmake, not make.
+
+MAC OS X NOTES
+--------------
+PowerDNS Authoritative Server is available through Homebrew:
+
+```
+$ brew install pdns
+```
+
+If you want to compile yourself, the dependencies can be installed using
+Homebrew:
+
+```
+$ brew install boost lua pkg-config ragel
+```
+
+For PostgreSQL support:
+
+```
+$ brew install postgresql
+```
+
+For MySQL support:
+
+```
+$ brew install mariadb
+```
+
+LINUX NOTES
+-----------
+None really.
--- /dev/null
+SUBDIRS = ext modules codedocs docs
+
+SUBDIRS += pdns
+
+EXTRA_DIST = \
+ INSTALL \
+ NOTICE \
+ README \
+ .version \
+ build-aux/gen-version \
+ codedocs/doxygen.conf \
+ contrib/powerdns.solaris.init.d \
+ pdns/named.conf.parsertest \
+ regression-tests/zones/unit.test
+
+ACLOCAL_AMFLAGS = -I m4
+
+dvi: # do nothing to build dvi
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = .
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/configure $(am__configure_deps) \
+ $(srcdir)/config.h.in AUTHORS COPYING INSTALL NEWS README \
+ build-aux/compile build-aux/config.guess build-aux/config.sub \
+ build-aux/install-sh build-aux/missing build-aux/ltmain.sh \
+ $(top_srcdir)/build-aux/compile \
+ $(top_srcdir)/build-aux/config.guess \
+ $(top_srcdir)/build-aux/config.sub \
+ $(top_srcdir)/build-aux/install-sh \
+ $(top_srcdir)/build-aux/ltmain.sh \
+ $(top_srcdir)/build-aux/missing
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
+ configure.lineno config.status.lineno
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ cscope distdir dist dist-all distcheck
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) \
+ $(LISP)config.h.in
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+CSCOPE = cscope
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+distdir = $(PACKAGE)-$(VERSION)
+top_distdir = $(distdir)
+am__remove_distdir = \
+ if test -d "$(distdir)"; then \
+ find "$(distdir)" -type d ! -perm -200 -exec chmod u+w {} ';' \
+ && rm -rf "$(distdir)" \
+ || { sleep 5 && rm -rf "$(distdir)"; }; \
+ else :; fi
+am__post_remove_distdir = $(am__remove_distdir)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+GZIP_ENV = --best
+DIST_ARCHIVES = $(distdir).tar.bz2
+DIST_TARGETS = dist-bzip2
+distuninstallcheck_listfiles = find . -type f -print
+am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
+ | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
+distcleancheck_listfiles = find . -type f -print
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = ext modules codedocs docs pdns
+EXTRA_DIST = \
+ INSTALL \
+ NOTICE \
+ README \
+ .version \
+ build-aux/gen-version \
+ codedocs/doxygen.conf \
+ contrib/powerdns.solaris.init.d \
+ pdns/named.conf.parsertest \
+ regression-tests/zones/unit.test
+
+ACLOCAL_AMFLAGS = -I m4
+all: config.h
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+am--refresh: Makefile
+ @:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ echo ' cd $(srcdir) && $(AUTOMAKE) --foreign'; \
+ $(am__cd) $(srcdir) && $(AUTOMAKE) --foreign \
+ && exit 0; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ echo ' $(SHELL) ./config.status'; \
+ $(SHELL) ./config.status;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ $(SHELL) ./config.status --recheck
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ $(am__cd) $(srcdir) && $(AUTOCONF)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ $(am__cd) $(srcdir) && $(ACLOCAL) $(ACLOCAL_AMFLAGS)
+$(am__aclocal_m4_deps):
+
+config.h: stamp-h1
+ @test -f $@ || rm -f stamp-h1
+ @test -f $@ || $(MAKE) $(AM_MAKEFLAGS) stamp-h1
+
+stamp-h1: $(srcdir)/config.h.in $(top_builddir)/config.status
+ @rm -f stamp-h1
+ cd $(top_builddir) && $(SHELL) ./config.status config.h
+$(srcdir)/config.h.in: $(am__configure_deps)
+ ($(am__cd) $(top_srcdir) && $(AUTOHEADER))
+ rm -f stamp-h1
+ touch $@
+
+distclean-hdr:
+ -rm -f config.h stamp-h1
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+distclean-libtool:
+ -rm -f libtool config.lt
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscope: cscope.files
+ test ! -s cscope.files \
+ || $(CSCOPE) -b -q $(AM_CSCOPEFLAGS) $(CSCOPEFLAGS) -i cscope.files $(CSCOPE_ARGS)
+clean-cscope:
+ -rm -f cscope.files
+cscope.files: clean-cscope cscopelist
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+ -rm -f cscope.out cscope.in.out cscope.po.out cscope.files
+
+distdir: $(DISTFILES)
+ $(am__remove_distdir)
+ test -d "$(distdir)" || mkdir "$(distdir)"
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+ -test -n "$(am__skip_mode_fix)" \
+ || find "$(distdir)" -type d ! -perm -755 \
+ -exec chmod u+rwx,go+rx {} \; -o \
+ ! -type d ! -perm -444 -links 1 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -400 -exec chmod a+r {} \; -o \
+ ! -type d ! -perm -444 -exec $(install_sh) -c -m a+r {} {} \; \
+ || chmod -R a+r "$(distdir)"
+dist-gzip: distdir
+ tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+ $(am__post_remove_distdir)
+dist-bzip2: distdir
+ tardir=$(distdir) && $(am__tar) | BZIP2=$${BZIP2--9} bzip2 -c >$(distdir).tar.bz2
+ $(am__post_remove_distdir)
+
+dist-lzip: distdir
+ tardir=$(distdir) && $(am__tar) | lzip -c $${LZIP_OPT--9} >$(distdir).tar.lz
+ $(am__post_remove_distdir)
+
+dist-xz: distdir
+ tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
+ $(am__post_remove_distdir)
+
+dist-tarZ: distdir
+ @echo WARNING: "Support for shar distribution archives is" \
+ "deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ tardir=$(distdir) && $(am__tar) | compress -c >$(distdir).tar.Z
+ $(am__post_remove_distdir)
+
+dist-shar: distdir
+ @echo WARNING: "Support for distribution archives compressed with" \
+ "legacy program 'compress' is deprecated." >&2
+ @echo WARNING: "It will be removed altogether in Automake 2.0" >&2
+ shar $(distdir) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).shar.gz
+ $(am__post_remove_distdir)
+
+dist-zip: distdir
+ -rm -f $(distdir).zip
+ zip -rq $(distdir).zip $(distdir)
+ $(am__post_remove_distdir)
+
+dist dist-all:
+ $(MAKE) $(AM_MAKEFLAGS) $(DIST_TARGETS) am__post_remove_distdir='@:'
+ $(am__post_remove_distdir)
+
+# This target untars the dist file and tries a VPATH configuration. Then
+# it guarantees that the distribution is self-contained by making another
+# tarfile.
+distcheck: dist
+ case '$(DIST_ARCHIVES)' in \
+ *.tar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).tar.gz | $(am__untar) ;;\
+ *.tar.bz2*) \
+ bzip2 -dc $(distdir).tar.bz2 | $(am__untar) ;;\
+ *.tar.lz*) \
+ lzip -dc $(distdir).tar.lz | $(am__untar) ;;\
+ *.tar.xz*) \
+ xz -dc $(distdir).tar.xz | $(am__untar) ;;\
+ *.tar.Z*) \
+ uncompress -c $(distdir).tar.Z | $(am__untar) ;;\
+ *.shar.gz*) \
+ GZIP=$(GZIP_ENV) gzip -dc $(distdir).shar.gz | unshar ;;\
+ *.zip*) \
+ unzip $(distdir).zip ;;\
+ esac
+ chmod -R a-w $(distdir)
+ chmod u+w $(distdir)
+ mkdir $(distdir)/_build $(distdir)/_inst
+ chmod a-w $(distdir)
+ test -d $(distdir)/_build || exit 0; \
+ dc_install_base=`$(am__cd) $(distdir)/_inst && pwd | sed -e 's,^[^:\\/]:[\\/],/,'` \
+ && dc_destdir="$${TMPDIR-/tmp}/am-dc-$$$$/" \
+ && am__cwd=`pwd` \
+ && $(am__cd) $(distdir)/_build \
+ && ../configure \
+ $(AM_DISTCHECK_CONFIGURE_FLAGS) \
+ $(DISTCHECK_CONFIGURE_FLAGS) \
+ --srcdir=.. --prefix="$$dc_install_base" \
+ && $(MAKE) $(AM_MAKEFLAGS) \
+ && $(MAKE) $(AM_MAKEFLAGS) dvi \
+ && $(MAKE) $(AM_MAKEFLAGS) check \
+ && $(MAKE) $(AM_MAKEFLAGS) install \
+ && $(MAKE) $(AM_MAKEFLAGS) installcheck \
+ && $(MAKE) $(AM_MAKEFLAGS) uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) distuninstallcheck_dir="$$dc_install_base" \
+ distuninstallcheck \
+ && chmod -R a-w "$$dc_install_base" \
+ && ({ \
+ (cd ../.. && umask 077 && mkdir "$$dc_destdir") \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" install \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" uninstall \
+ && $(MAKE) $(AM_MAKEFLAGS) DESTDIR="$$dc_destdir" \
+ distuninstallcheck_dir="$$dc_destdir" distuninstallcheck; \
+ } || { rm -rf "$$dc_destdir"; exit 1; }) \
+ && rm -rf "$$dc_destdir" \
+ && $(MAKE) $(AM_MAKEFLAGS) dist \
+ && rm -rf $(DIST_ARCHIVES) \
+ && $(MAKE) $(AM_MAKEFLAGS) distcleancheck \
+ && cd "$$am__cwd" \
+ || exit 1
+ $(am__post_remove_distdir)
+ @(echo "$(distdir) archives ready for distribution: "; \
+ list='$(DIST_ARCHIVES)'; for i in $$list; do echo $$i; done) | \
+ sed -e 1h -e 1s/./=/g -e 1p -e 1x -e '$$p' -e '$$x'
+distuninstallcheck:
+ @test -n '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: trying to run $@ with an empty' \
+ '$$(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ $(am__cd) '$(distuninstallcheck_dir)' || { \
+ echo 'ERROR: cannot chdir into $(distuninstallcheck_dir)' >&2; \
+ exit 1; \
+ }; \
+ test `$(am__distuninstallcheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left after uninstall:" ; \
+ if test -n "$(DESTDIR)"; then \
+ echo " (check DESTDIR support)"; \
+ fi ; \
+ $(distuninstallcheck_listfiles) ; \
+ exit 1; } >&2
+distcleancheck: distclean
+ @if test '$(srcdir)' = . ; then \
+ echo "ERROR: distcleancheck can only run from a VPATH build" ; \
+ exit 1 ; \
+ fi
+ @test `$(distcleancheck_listfiles) | wc -l` -eq 0 \
+ || { echo "ERROR: files left in build directory after distclean:" ; \
+ $(distcleancheck_listfiles) ; \
+ exit 1; } >&2
+check-am: all-am
+check: check-recursive
+all-am: Makefile config.h
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-hdr \
+ distclean-libtool distclean-tags
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f $(am__CONFIG_DISTCLEAN_FILES)
+ -rm -rf $(top_srcdir)/autom4te.cache
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) all install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am \
+ am--refresh check check-am clean clean-cscope clean-generic \
+ clean-libtool cscope cscopelist-am ctags ctags-am dist \
+ dist-all dist-bzip2 dist-gzip dist-lzip dist-shar dist-tarZ \
+ dist-xz dist-zip distcheck distclean distclean-generic \
+ distclean-hdr distclean-libtool distclean-tags distcleancheck \
+ distdir distuninstallcheck dvi dvi-am html html-am info \
+ info-am install install-am install-data install-data-am \
+ install-dvi install-dvi-am install-exec install-exec-am \
+ install-html install-html-am install-info install-info-am \
+ install-man install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs installdirs-am maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-am uninstall \
+ uninstall-am
+
+
+dvi: # do nothing to build dvi
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+For news, please see http://www.powerdns.com and http://docs.powerdns.com
--- /dev/null
+This program is free software; you can redistribute it and/or modify
+it under the terms of version 2 of the GNU General Public License as
+published by the Free Software Foundation.
+
+In addition, for the avoidance of any doubt, permission is granted to
+link this program with OpenSSL and to (re)distribute the binaries
+produced as the result of such linking.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program; if not, write to the Free Software
+Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
--- /dev/null
+PowerDNS is copyright © 2002-2016 by PowerDNS.COM BV and lots of
+contributors, using the GNU GPLv2 license (see NOTICE for the
+exact license and exception used).
+
+All documentation can be found on http://doc.powerdns.com/
+
+This file may lag behind at times. For most recent updates, always check
+https://doc.powerdns.com/md/changelog/.
+
+Another good place to look for information is:
+https://doc.powerdns.com/md/appendix/compiling-powerdns/
+
+To file bugs, head towards:
+https://github.com/PowerDNS/pdns/issues
+
+But please check if the issue is already reported there first.
+
+SOURCE CODE / GIT
+-----------------
+Source code is available on GitHub:
+
+```
+$ git clone https://github.com/PowerDNS/pdns.git
+```
+
+This repository contains the sources for the PowerDNS Recursor, the PowerDNS
+Authoritative Server, and dnsdist (a powerful DNS loadbalancer). All three can
+be built from this repository. However, all three released separately as .tar.bz2,
+.deb and .rpm.
+
+COMPILING Authoritative Server
+------------------------------
+The PowerDNS Authoritative Server depends on Boost, OpenSSL and requires a
+compiler with C++-2011 support.
+
+On Debian 8.0, the following is useful:
+
+```
+$ apt-get install g++ libboost-all-dev libtool make pkg-config libmysqlclient-dev libssl-dev
+```
+
+When building from git, the following packages are also required: autoconf, automake,
+ragel, bison and flex, then generate the configure file:
+
+```
+$ ./bootstrap
+```
+
+To compile a very clean version, use:
+
+```
+$ ./configure --with-modules="" --without-lua
+$ make
+# make install
+```
+
+This generates a PowerDNS Authoritative Server binary with no modules built in.
+
+When `./configure` is run without `--with-modules`, the bind and gmysql module are
+built-in by default and the pipe-backend is compiled for runtime loading.
+
+To add multiple modules, try:
+
+```
+$ ./configure --with-modules="bind gmysql gpgsql"
+```
+
+Note that you will need the development headers for PostgreSQL as well in this case.
+
+See https://doc.powerdns.com/md/appendix/compiling-powerdns/ for more details.
+
+If you run into C++11-related symbol trouble, please try passing `CPPFLAGS=-D_GLIBCXX_USE_CXX11_ABI=0` (or 1) to `./configure` to make sure you are compatible with the installed dependencies.
+
+COMPILING THE RECURSOR
+----------------------
+See the README in pdns/recursordist.
+
+COMPILING DNSDIST
+----------------------
+See the README in pdns/dnsdistdist.
+
+SOLARIS NOTES
+-------------
+Use a recent gcc. OpenCSW is a good source, as is Solaris 11 IPS.
+
+If you encounter problems with the Solaris make, gmake is advised.
+
+FREEBSD NOTES
+-------------
+You need to compile using gmake - regular make only appears to work, but doesn't in fact. Use gmake, not make.
+
+MAC OS X NOTES
+--------------
+PowerDNS Authoritative Server is available through Homebrew:
+
+```
+$ brew install pdns
+```
+
+If you want to compile yourself, the dependencies can be installed using
+Homebrew:
+
+```
+$ brew install boost lua pkg-config ragel
+```
+
+For PostgreSQL support:
+
+```
+$ brew install postgresql
+```
+
+For MySQL support:
+
+```
+$ brew install mariadb
+```
+
+LINUX NOTES
+-----------
+None really.
--- /dev/null
+# generated automatically by aclocal 1.14.1 -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+m4_ifndef([AC_CONFIG_MACRO_DIRS], [m4_defun([_AM_CONFIG_MACRO_DIRS], [])m4_defun([AC_CONFIG_MACRO_DIRS], [_AM_CONFIG_MACRO_DIRS($@)])])
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+m4_if(m4_defn([AC_AUTOCONF_VERSION]), [2.69],,
+[m4_warning([this file was generated for autoconf 2.69.
+You have another version of autoconf. It may work, but is not guaranteed to.
+If you have problems, you may need to regenerate the build system entirely.
+To do so, use the procedure documented by the package, typically 'autoreconf'.])])
+
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+# serial 1 (pkg-config-0.24)
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_(PATH|LIBDIR|SYSROOT_DIR|ALLOW_SYSTEM_(CFLAGS|LIBS)))?$])
+m4_pattern_allow([^PKG_CONFIG_(DISABLE_UNINSTALLED|TOP_BUILD_DIR|DEBUG_SPEW)$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])
+AC_ARG_VAR([PKG_CONFIG_PATH], [directories to add to pkg-config's search path])
+AC_ARG_VAR([PKG_CONFIG_LIBDIR], [path overriding pkg-config's built-in search path])
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+# Please remember that m4 expands AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+# only at the first occurence in configure.ac, so if the first place
+# it's called might be skipped (such as if it is within an "if", you
+# have to call PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_default([$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ elif test -n "$PKG_CONFIG"; then
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes ],
+ [pkg_failed=yes])
+ else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $1])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ AC_MSG_RESULT([no])
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$2" 2>&1`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$2" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ m4_default([$4], [AC_MSG_ERROR(
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT])[]dnl
+ ])
+elif test $pkg_failed = untried; then
+ AC_MSG_RESULT([no])
+ m4_default([$4], [AC_MSG_FAILURE(
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.])[]dnl
+ ])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ $3
+fi[]dnl
+])# PKG_CHECK_MODULES
+
+
+# PKG_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable pkgconfigdir as the location where a module
+# should install pkg-config .pc files. By default the directory is
+# $libdir/pkgconfig, but the default can be changed by passing
+# DIRECTORY. The user can override through the --with-pkgconfigdir
+# parameter.
+AC_DEFUN([PKG_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${libdir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([pkgconfigdir],
+ [AS_HELP_STRING([--with-pkgconfigdir], pkg_description)],,
+ [with_pkgconfigdir=]pkg_default)
+AC_SUBST([pkgconfigdir], [$with_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_INSTALLDIR
+
+
+# PKG_NOARCH_INSTALLDIR(DIRECTORY)
+# -------------------------
+# Substitutes the variable noarch_pkgconfigdir as the location where a
+# module should install arch-independent pkg-config .pc files. By
+# default the directory is $datadir/pkgconfig, but the default can be
+# changed by passing DIRECTORY. The user can override through the
+# --with-noarch-pkgconfigdir parameter.
+AC_DEFUN([PKG_NOARCH_INSTALLDIR],
+[m4_pushdef([pkg_default], [m4_default([$1], ['${datadir}/pkgconfig'])])
+m4_pushdef([pkg_description],
+ [pkg-config arch-independent installation directory @<:@]pkg_default[@:>@])
+AC_ARG_WITH([noarch-pkgconfigdir],
+ [AS_HELP_STRING([--with-noarch-pkgconfigdir], pkg_description)],,
+ [with_noarch_pkgconfigdir=]pkg_default)
+AC_SUBST([noarch_pkgconfigdir], [$with_noarch_pkgconfigdir])
+m4_popdef([pkg_default])
+m4_popdef([pkg_description])
+]) dnl PKG_NOARCH_INSTALLDIR
+
+
+# PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# -------------------------------------------
+# Retrieves the value of the pkg-config variable for the given module.
+AC_DEFUN([PKG_CHECK_VAR],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl
+
+_PKG_CONFIG([$1], [variable="][$3]["], [$2])
+AS_VAR_COPY([$1], [pkg_cv_][$1])
+
+AS_VAR_IF([$1], [""], [$5], [$4])dnl
+])# PKG_CHECK_VAR
+
+# Copyright (C) 2002-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_AUTOMAKE_VERSION(VERSION)
+# ----------------------------
+# Automake X.Y traces this macro to ensure aclocal.m4 has been
+# generated from the m4 files accompanying Automake X.Y.
+# (This private macro should not be called outside this file.)
+AC_DEFUN([AM_AUTOMAKE_VERSION],
+[am__api_version='1.14'
+dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
+dnl require some minimum version. Point them to the right macro.
+m4_if([$1], [1.14.1], [],
+ [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
+])
+
+# _AM_AUTOCONF_VERSION(VERSION)
+# -----------------------------
+# aclocal traces this macro to find the Autoconf version.
+# This is a private macro too. Using m4_define simplifies
+# the logic in aclocal, which can simply ignore this definition.
+m4_define([_AM_AUTOCONF_VERSION], [])
+
+# AM_SET_CURRENT_AUTOMAKE_VERSION
+# -------------------------------
+# Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
+# This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
+AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
+[AM_AUTOMAKE_VERSION([1.14.1])dnl
+m4_ifndef([AC_AUTOCONF_VERSION],
+ [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
+_AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
+
+# AM_AUX_DIR_EXPAND -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# For projects using AC_CONFIG_AUX_DIR([foo]), Autoconf sets
+# $ac_aux_dir to '$srcdir/foo'. In other projects, it is set to
+# '$srcdir', '$srcdir/..', or '$srcdir/../..'.
+#
+# Of course, Automake must honor this variable whenever it calls a
+# tool from the auxiliary directory. The problem is that $srcdir (and
+# therefore $ac_aux_dir as well) can be either absolute or relative,
+# depending on how configure is run. This is pretty annoying, since
+# it makes $ac_aux_dir quite unusable in subdirectories: in the top
+# source directory, any form will work fine, but in subdirectories a
+# relative path needs to be adjusted first.
+#
+# $ac_aux_dir/missing
+# fails when called from a subdirectory if $ac_aux_dir is relative
+# $top_srcdir/$ac_aux_dir/missing
+# fails if $ac_aux_dir is absolute,
+# fails when called from a subdirectory in a VPATH build with
+# a relative $ac_aux_dir
+#
+# The reason of the latter failure is that $top_srcdir and $ac_aux_dir
+# are both prefixed by $srcdir. In an in-source build this is usually
+# harmless because $srcdir is '.', but things will broke when you
+# start a VPATH build or use an absolute $srcdir.
+#
+# So we could use something similar to $top_srcdir/$ac_aux_dir/missing,
+# iff we strip the leading $srcdir from $ac_aux_dir. That would be:
+# am_aux_dir='\$(top_srcdir)/'`expr "$ac_aux_dir" : "$srcdir//*\(.*\)"`
+# and then we would define $MISSING as
+# MISSING="\${SHELL} $am_aux_dir/missing"
+# This will work as long as MISSING is not called from configure, because
+# unfortunately $(top_srcdir) has no meaning in configure.
+# However there are other variables, like CC, which are often used in
+# configure, and could therefore not use this "fixed" $ac_aux_dir.
+#
+# Another solution, used here, is to always expand $ac_aux_dir to an
+# absolute PATH. The drawback is that using absolute paths prevent a
+# configured tree to be moved without reconfiguration.
+
+AC_DEFUN([AM_AUX_DIR_EXPAND],
+[AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+])
+
+# AM_COND_IF -*- Autoconf -*-
+
+# Copyright (C) 2008-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_COND_IF
+# _AM_COND_ELSE
+# _AM_COND_ENDIF
+# --------------
+# These macros are only used for tracing.
+m4_define([_AM_COND_IF])
+m4_define([_AM_COND_ELSE])
+m4_define([_AM_COND_ENDIF])
+
+# AM_COND_IF(COND, [IF-TRUE], [IF-FALSE])
+# ---------------------------------------
+# If the shell condition COND is true, execute IF-TRUE, otherwise execute
+# IF-FALSE. Allow automake to learn about conditional instantiating macros
+# (the AC_CONFIG_FOOS).
+AC_DEFUN([AM_COND_IF],
+[m4_ifndef([_AM_COND_VALUE_$1],
+ [m4_fatal([$0: no such condition "$1"])])dnl
+_AM_COND_IF([$1])dnl
+if test -z "$$1_TRUE"; then :
+ m4_n([$2])[]dnl
+m4_ifval([$3],
+[_AM_COND_ELSE([$1])dnl
+else
+ $3
+])dnl
+_AM_COND_ENDIF([$1])dnl
+fi[]dnl
+])
+
+# AM_CONDITIONAL -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_CONDITIONAL(NAME, SHELL-CONDITION)
+# -------------------------------------
+# Define a conditional.
+AC_DEFUN([AM_CONDITIONAL],
+[AC_PREREQ([2.52])dnl
+ m4_if([$1], [TRUE], [AC_FATAL([$0: invalid condition: $1])],
+ [$1], [FALSE], [AC_FATAL([$0: invalid condition: $1])])dnl
+AC_SUBST([$1_TRUE])dnl
+AC_SUBST([$1_FALSE])dnl
+_AM_SUBST_NOTMAKE([$1_TRUE])dnl
+_AM_SUBST_NOTMAKE([$1_FALSE])dnl
+m4_define([_AM_COND_VALUE_$1], [$2])dnl
+if $2; then
+ $1_TRUE=
+ $1_FALSE='#'
+else
+ $1_TRUE='#'
+ $1_FALSE=
+fi
+AC_CONFIG_COMMANDS_PRE(
+[if test -z "${$1_TRUE}" && test -z "${$1_FALSE}"; then
+ AC_MSG_ERROR([[conditional "$1" was never defined.
+Usually this means the macro was only invoked conditionally.]])
+fi])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# There are a few dirty hacks below to avoid letting 'AC_PROG_CC' be
+# written in clear, in which case automake, when reading aclocal.m4,
+# will think it sees a *use*, and therefore will trigger all it's
+# C support machinery. Also note that it means that autoscan, seeing
+# CC etc. in the Makefile, will ask for an AC_PROG_CC use...
+
+
+# _AM_DEPENDENCIES(NAME)
+# ----------------------
+# See how the compiler implements dependency checking.
+# NAME is "CC", "CXX", "OBJC", "OBJCXX", "UPC", or "GJC".
+# We try a few techniques and use that to set a single cache variable.
+#
+# We don't AC_REQUIRE the corresponding AC_PROG_CC since the latter was
+# modified to invoke _AM_DEPENDENCIES(CC); we would have a circular
+# dependency, and given that the user is not expected to run this macro,
+# just rely on AC_PROG_CC.
+AC_DEFUN([_AM_DEPENDENCIES],
+[AC_REQUIRE([AM_SET_DEPDIR])dnl
+AC_REQUIRE([AM_OUTPUT_DEPENDENCY_COMMANDS])dnl
+AC_REQUIRE([AM_MAKE_INCLUDE])dnl
+AC_REQUIRE([AM_DEP_TRACK])dnl
+
+m4_if([$1], [CC], [depcc="$CC" am_compiler_list=],
+ [$1], [CXX], [depcc="$CXX" am_compiler_list=],
+ [$1], [OBJC], [depcc="$OBJC" am_compiler_list='gcc3 gcc'],
+ [$1], [OBJCXX], [depcc="$OBJCXX" am_compiler_list='gcc3 gcc'],
+ [$1], [UPC], [depcc="$UPC" am_compiler_list=],
+ [$1], [GCJ], [depcc="$GCJ" am_compiler_list='gcc3 gcc'],
+ [depcc="$$1" am_compiler_list=])
+
+AC_CACHE_CHECK([dependency style of $depcc],
+ [am_cv_$1_dependencies_compiler_type],
+[if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_$1_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n ['s/^#*\([a-zA-Z0-9]*\))$/\1/p'] < ./depcomp`
+ fi
+ am__universal=false
+ m4_case([$1], [CC],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac],
+ [CXX],
+ [case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac])
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_$1_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_$1_dependencies_compiler_type=none
+fi
+])
+AC_SUBST([$1DEPMODE], [depmode=$am_cv_$1_dependencies_compiler_type])
+AM_CONDITIONAL([am__fastdep$1], [
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_$1_dependencies_compiler_type" = gcc3])
+])
+
+
+# AM_SET_DEPDIR
+# -------------
+# Choose a directory name for dependency files.
+# This macro is AC_REQUIREd in _AM_DEPENDENCIES.
+AC_DEFUN([AM_SET_DEPDIR],
+[AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+AC_SUBST([DEPDIR], ["${am__leading_dot}deps"])dnl
+])
+
+
+# AM_DEP_TRACK
+# ------------
+AC_DEFUN([AM_DEP_TRACK],
+[AC_ARG_ENABLE([dependency-tracking], [dnl
+AS_HELP_STRING(
+ [--enable-dependency-tracking],
+ [do not reject slow dependency extractors])
+AS_HELP_STRING(
+ [--disable-dependency-tracking],
+ [speeds up one-time build])])
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+AM_CONDITIONAL([AMDEP], [test "x$enable_dependency_tracking" != xno])
+AC_SUBST([AMDEPBACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AMDEPBACKSLASH])dnl
+AC_SUBST([am__nodep])dnl
+_AM_SUBST_NOTMAKE([am__nodep])dnl
+])
+
+# Generate code to set up dependency tracking. -*- Autoconf -*-
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+
+# _AM_OUTPUT_DEPENDENCY_COMMANDS
+# ------------------------------
+AC_DEFUN([_AM_OUTPUT_DEPENDENCY_COMMANDS],
+[{
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`AS_DIRNAME("$mf")`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`AS_DIRNAME(["$file"])`
+ AS_MKDIR_P([$dirpart/$fdir])
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+])# _AM_OUTPUT_DEPENDENCY_COMMANDS
+
+
+# AM_OUTPUT_DEPENDENCY_COMMANDS
+# -----------------------------
+# This macro should only be invoked once -- use via AC_REQUIRE.
+#
+# This code is only required when automatic dependency tracking
+# is enabled. FIXME. This creates each '.P' file that we will
+# need in order to bootstrap the dependency handling code.
+AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
+[AC_CONFIG_COMMANDS([depfiles],
+ [test x"$AMDEP_TRUE" != x"" || _AM_OUTPUT_DEPENDENCY_COMMANDS],
+ [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
+])
+
+# Do all the work for Automake. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This macro actually does too much. Some checks are only needed if
+# your package does certain things. But this isn't really a big deal.
+
+dnl Redefine AC_PROG_CC to automatically invoke _AM_PROG_CC_C_O.
+m4_define([AC_PROG_CC],
+m4_defn([AC_PROG_CC])
+[_AM_PROG_CC_C_O
+])
+
+# AM_INIT_AUTOMAKE(PACKAGE, VERSION, [NO-DEFINE])
+# AM_INIT_AUTOMAKE([OPTIONS])
+# -----------------------------------------------
+# The call with PACKAGE and VERSION arguments is the old style
+# call (pre autoconf-2.50), which is being phased out. PACKAGE
+# and VERSION should now be passed to AC_INIT and removed from
+# the call to AM_INIT_AUTOMAKE.
+# We support both call styles for the transition. After
+# the next Automake release, Autoconf can make the AC_INIT
+# arguments mandatory, and then we can depend on a new Autoconf
+# release and drop the old call support.
+AC_DEFUN([AM_INIT_AUTOMAKE],
+[AC_PREREQ([2.65])dnl
+dnl Autoconf wants to disallow AM_ names. We explicitly allow
+dnl the ones we care about.
+m4_pattern_allow([^AM_[A-Z]+FLAGS$])dnl
+AC_REQUIRE([AM_SET_CURRENT_AUTOMAKE_VERSION])dnl
+AC_REQUIRE([AC_PROG_INSTALL])dnl
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ AC_SUBST([am__isrc], [' -I$(srcdir)'])_AM_SUBST_NOTMAKE([am__isrc])dnl
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ AC_MSG_ERROR([source directory already configured; run "make distclean" there first])
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+AC_SUBST([CYGPATH_W])
+
+# Define the identity of the package.
+dnl Distinguish between old-style and new-style calls.
+m4_ifval([$2],
+[AC_DIAGNOSE([obsolete],
+ [$0: two- and three-arguments forms are deprecated.])
+m4_ifval([$3], [_AM_SET_OPTION([no-define])])dnl
+ AC_SUBST([PACKAGE], [$1])dnl
+ AC_SUBST([VERSION], [$2])],
+[_AM_SET_OPTIONS([$1])dnl
+dnl Diagnose old-style AC_INIT with new-style AM_AUTOMAKE_INIT.
+m4_if(
+ m4_ifdef([AC_PACKAGE_NAME], [ok]):m4_ifdef([AC_PACKAGE_VERSION], [ok]),
+ [ok:ok],,
+ [m4_fatal([AC_INIT should be called with package and version arguments])])dnl
+ AC_SUBST([PACKAGE], ['AC_PACKAGE_TARNAME'])dnl
+ AC_SUBST([VERSION], ['AC_PACKAGE_VERSION'])])dnl
+
+_AM_IF_OPTION([no-define],,
+[AC_DEFINE_UNQUOTED([PACKAGE], ["$PACKAGE"], [Name of package])
+ AC_DEFINE_UNQUOTED([VERSION], ["$VERSION"], [Version number of package])])dnl
+
+# Some tools Automake needs.
+AC_REQUIRE([AM_SANITY_CHECK])dnl
+AC_REQUIRE([AC_ARG_PROGRAM])dnl
+AM_MISSING_PROG([ACLOCAL], [aclocal-${am__api_version}])
+AM_MISSING_PROG([AUTOCONF], [autoconf])
+AM_MISSING_PROG([AUTOMAKE], [automake-${am__api_version}])
+AM_MISSING_PROG([AUTOHEADER], [autoheader])
+AM_MISSING_PROG([MAKEINFO], [makeinfo])
+AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+AC_REQUIRE([AM_PROG_INSTALL_STRIP])dnl
+AC_REQUIRE([AC_PROG_MKDIR_P])dnl
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+AC_SUBST([mkdir_p], ['$(MKDIR_P)'])
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([AC_PROG_MAKE_SET])dnl
+AC_REQUIRE([AM_SET_LEADING_DOT])dnl
+_AM_IF_OPTION([tar-ustar], [_AM_PROG_TAR([ustar])],
+ [_AM_IF_OPTION([tar-pax], [_AM_PROG_TAR([pax])],
+ [_AM_PROG_TAR([v7])])])
+_AM_IF_OPTION([no-dependencies],,
+[AC_PROVIDE_IFELSE([AC_PROG_CC],
+ [_AM_DEPENDENCIES([CC])],
+ [m4_define([AC_PROG_CC],
+ m4_defn([AC_PROG_CC])[_AM_DEPENDENCIES([CC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [_AM_DEPENDENCIES([CXX])],
+ [m4_define([AC_PROG_CXX],
+ m4_defn([AC_PROG_CXX])[_AM_DEPENDENCIES([CXX])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJC],
+ [_AM_DEPENDENCIES([OBJC])],
+ [m4_define([AC_PROG_OBJC],
+ m4_defn([AC_PROG_OBJC])[_AM_DEPENDENCIES([OBJC])])])dnl
+AC_PROVIDE_IFELSE([AC_PROG_OBJCXX],
+ [_AM_DEPENDENCIES([OBJCXX])],
+ [m4_define([AC_PROG_OBJCXX],
+ m4_defn([AC_PROG_OBJCXX])[_AM_DEPENDENCIES([OBJCXX])])])dnl
+])
+AC_REQUIRE([AM_SILENT_RULES])dnl
+dnl The testsuite driver may need to know about EXEEXT, so add the
+dnl 'am__EXEEXT' conditional if _AM_COMPILER_EXEEXT was seen. This
+dnl macro is hooked onto _AC_COMPILER_EXEEXT early, see below.
+AC_CONFIG_COMMANDS_PRE(dnl
+[m4_provide_if([_AM_COMPILER_EXEEXT],
+ [AM_CONDITIONAL([am__EXEEXT], [test -n "$EXEEXT"])])])dnl
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ AC_MSG_ERROR([Your 'rm' program is bad, sorry.])
+ fi
+fi
+])
+
+dnl Hook into '_AC_COMPILER_EXEEXT' early to learn its expansion. Do not
+dnl add the conditional right here, as _AC_COMPILER_EXEEXT may be further
+dnl mangled by Autoconf and run in a shell conditional statement.
+m4_define([_AC_COMPILER_EXEEXT],
+m4_defn([_AC_COMPILER_EXEEXT])[m4_provide([_AM_COMPILER_EXEEXT])])
+
+# When config.status generates a header, we must update the stamp-h file.
+# This file resides in the same directory as the config header
+# that is generated. The stamp files are numbered to have different names.
+
+# Autoconf calls _AC_AM_CONFIG_HEADER_HOOK (when defined) in the
+# loop where config.status creates the headers, so we can generate
+# our stamp files there.
+AC_DEFUN([_AC_AM_CONFIG_HEADER_HOOK],
+[# Compute $1's index in $config_headers.
+_am_arg=$1
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`AS_DIRNAME(["$_am_arg"])`/stamp-h[]$_am_stamp_count])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_SH
+# ------------------
+# Define $install_sh.
+AC_DEFUN([AM_PROG_INSTALL_SH],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+AC_SUBST([install_sh])])
+
+# Copyright (C) 2003-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# Check whether the underlying file-system supports filenames
+# with a leading dot. For instance MS-DOS doesn't.
+AC_DEFUN([AM_SET_LEADING_DOT],
+[rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+AC_SUBST([am__leading_dot])])
+
+# Check to see how 'make' treats includes. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MAKE_INCLUDE()
+# -----------------
+# Check to see how make treats includes.
+AC_DEFUN([AM_MAKE_INCLUDE],
+[am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+AC_MSG_CHECKING([for style of include used by $am_make])
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+AC_SUBST([am__include])
+AC_SUBST([am__quote])
+AC_MSG_RESULT([$_am_result])
+rm -f confinc confmf
+])
+
+# Fake the existence of programs that GNU maintainers use. -*- Autoconf -*-
+
+# Copyright (C) 1997-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_MISSING_PROG(NAME, PROGRAM)
+# ------------------------------
+AC_DEFUN([AM_MISSING_PROG],
+[AC_REQUIRE([AM_MISSING_HAS_RUN])
+$1=${$1-"${am_missing_run}$2"}
+AC_SUBST($1)])
+
+# AM_MISSING_HAS_RUN
+# ------------------
+# Define MISSING if not defined so far and test if it is modern enough.
+# If it is, set am_missing_run to use it, otherwise, to nothing.
+AC_DEFUN([AM_MISSING_HAS_RUN],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([missing])dnl
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ AC_MSG_WARN(['missing' script is too old or missing])
+fi
+])
+
+# Helper functions for option handling. -*- Autoconf -*-
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_MANGLE_OPTION(NAME)
+# -----------------------
+AC_DEFUN([_AM_MANGLE_OPTION],
+[[_AM_OPTION_]m4_bpatsubst($1, [[^a-zA-Z0-9_]], [_])])
+
+# _AM_SET_OPTION(NAME)
+# --------------------
+# Set option NAME. Presently that only means defining a flag for this option.
+AC_DEFUN([_AM_SET_OPTION],
+[m4_define(_AM_MANGLE_OPTION([$1]), [1])])
+
+# _AM_SET_OPTIONS(OPTIONS)
+# ------------------------
+# OPTIONS is a space-separated list of Automake options.
+AC_DEFUN([_AM_SET_OPTIONS],
+[m4_foreach_w([_AM_Option], [$1], [_AM_SET_OPTION(_AM_Option)])])
+
+# _AM_IF_OPTION(OPTION, IF-SET, [IF-NOT-SET])
+# -------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+AC_DEFUN([_AM_IF_OPTION],
+[m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_CC_C_O
+# ---------------
+# Like AC_PROG_CC_C_O, but changed for automake. We rewrite AC_PROG_CC
+# to automatically call this.
+AC_DEFUN([_AM_PROG_CC_C_O],
+[AC_REQUIRE([AM_AUX_DIR_EXPAND])dnl
+AC_REQUIRE_AUX_FILE([compile])dnl
+AC_LANG_PUSH([C])dnl
+AC_CACHE_CHECK(
+ [whether $CC understands -c and -o together],
+ [am_cv_prog_cc_c_o],
+ [AC_LANG_CONFTEST([AC_LANG_PROGRAM([])])
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if AM_RUN_LOG([$CC -c conftest.$ac_ext -o conftest2.$ac_objext]) \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i])
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+AC_LANG_POP([C])])
+
+# For backward compatibility.
+AC_DEFUN_ONCE([AM_PROG_CC_C_O], [AC_REQUIRE([AC_PROG_CC])])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+ ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ (exit $ac_status); }])
+
+# Check to make sure that the build environment is sane. -*- Autoconf -*-
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SANITY_CHECK
+# ---------------
+AC_DEFUN([AM_SANITY_CHECK],
+[AC_MSG_CHECKING([whether build environment is sane])
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[[\\\"\#\$\&\'\`$am_lf]]*)
+ AC_MSG_ERROR([unsafe absolute working directory name]);;
+esac
+case $srcdir in
+ *[[\\\"\#\$\&\'\`$am_lf\ \ ]]*)
+ AC_MSG_ERROR([unsafe srcdir value: '$srcdir']);;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$[*]" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$[*]" != "X $srcdir/configure conftest.file" \
+ && test "$[*]" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ AC_MSG_ERROR([ls -t appears to fail. Make sure there is not a broken
+ alias in your environment])
+ fi
+ if test "$[2]" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$[2]" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ AC_MSG_ERROR([newly created file is older than distributed files!
+Check your system clock])
+fi
+AC_MSG_RESULT([yes])
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+AC_CONFIG_COMMANDS_PRE(
+ [AC_MSG_CHECKING([that generated files are newer than configure])
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ AC_MSG_RESULT([done])])
+rm -f conftest.file
+])
+
+# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_SILENT_RULES([DEFAULT])
+# --------------------------
+# Enable less verbose build rules; with the default set to DEFAULT
+# ("yes" being less verbose, "no" or empty being verbose).
+AC_DEFUN([AM_SILENT_RULES],
+[AC_ARG_ENABLE([silent-rules], [dnl
+AS_HELP_STRING(
+ [--enable-silent-rules],
+ [less verbose build output (undo: "make V=1")])
+AS_HELP_STRING(
+ [--disable-silent-rules],
+ [verbose build output (undo: "make V=0")])dnl
+])
+case $enable_silent_rules in @%:@ (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=m4_if([$1], [yes], [0], [1]);;
+esac
+dnl
+dnl A few 'make' implementations (e.g., NonStop OS and NextStep)
+dnl do not support nested variable expansions.
+dnl See automake bug#9928 and bug#10237.
+am_make=${MAKE-make}
+AC_CACHE_CHECK([whether $am_make supports nested variables],
+ [am_cv_make_support_nested_variables],
+ [if AS_ECHO([['TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit']]) | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi])
+if test $am_cv_make_support_nested_variables = yes; then
+ dnl Using '$V' instead of '$(V)' breaks IRIX make.
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AC_SUBST([AM_V])dnl
+AM_SUBST_NOTMAKE([AM_V])dnl
+AC_SUBST([AM_DEFAULT_V])dnl
+AM_SUBST_NOTMAKE([AM_DEFAULT_V])dnl
+AC_SUBST([AM_DEFAULT_VERBOSITY])dnl
+AM_BACKSLASH='\'
+AC_SUBST([AM_BACKSLASH])dnl
+_AM_SUBST_NOTMAKE([AM_BACKSLASH])dnl
+])
+
+# Copyright (C) 2001-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# AM_PROG_INSTALL_STRIP
+# ---------------------
+# One issue with vendor 'install' (even GNU) is that you can't
+# specify the program used to strip binaries. This is especially
+# annoying in cross-compiling environments, where the build's strip
+# is unlikely to handle the host's binaries.
+# Fortunately install-sh will honor a STRIPPROG variable, so we
+# always use install-sh in "make install-strip", and initialize
+# STRIPPROG with the value of the STRIP variable (set by the user).
+AC_DEFUN([AM_PROG_INSTALL_STRIP],
+[AC_REQUIRE([AM_PROG_INSTALL_SH])dnl
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+dnl Don't test for $cross_compiling = yes, because it might be 'maybe'.
+if test "$cross_compiling" != no; then
+ AC_CHECK_TOOL([STRIP], [strip], :)
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+AC_SUBST([INSTALL_STRIP_PROGRAM])])
+
+# Copyright (C) 2006-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_SUBST_NOTMAKE(VARIABLE)
+# ---------------------------
+# Prevent Automake from outputting VARIABLE = @VARIABLE@ in Makefile.in.
+# This macro is traced by Automake.
+AC_DEFUN([_AM_SUBST_NOTMAKE])
+
+# AM_SUBST_NOTMAKE(VARIABLE)
+# --------------------------
+# Public sister of _AM_SUBST_NOTMAKE.
+AC_DEFUN([AM_SUBST_NOTMAKE], [_AM_SUBST_NOTMAKE($@)])
+
+# Check how to create a tarball. -*- Autoconf -*-
+
+# Copyright (C) 2004-2013 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# _AM_PROG_TAR(FORMAT)
+# --------------------
+# Check how to create a tarball in format FORMAT.
+# FORMAT should be one of 'v7', 'ustar', or 'pax'.
+#
+# Substitute a variable $(am__tar) that is a command
+# writing to stdout a FORMAT-tarball containing the directory
+# $tardir.
+# tardir=directory && $(am__tar) > result.tar
+#
+# Substitute a variable $(am__untar) that extract such
+# a tarball read from stdin.
+# $(am__untar) < result.tar
+#
+AC_DEFUN([_AM_PROG_TAR],
+[# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AC_SUBST([AMTAR], ['$${TAR-tar}'])
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar m4_if([$1], [ustar], [plaintar]) pax cpio none'
+
+m4_if([$1], [v7],
+ [am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'],
+
+ [m4_case([$1],
+ [ustar],
+ [# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ AC_MSG_CHECKING([whether UID '$am_uid' is supported by ustar format])
+ if test $am_uid -le $am_max_uid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi
+ AC_MSG_CHECKING([whether GID '$am_gid' is supported by ustar format])
+ if test $am_gid -le $am_max_gid; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ _am_tools=none
+ fi],
+
+ [pax],
+ [],
+
+ [m4_fatal([Unknown tar format])])
+
+ AC_MSG_CHECKING([how to create a $1 tar archive])
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_$1-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ AM_RUN_LOG([$_am_tar --version]) && break
+ done
+ am__tar="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=m4_if([$1], [pax], [posix], [$1]) -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x $1 -w "$$tardir"'
+ am__tar_='pax -L -x $1 -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H $1 -L'
+ am__tar_='find "$tardir" -print | cpio -o -H $1 -L'
+ am__untar='cpio -i -H $1 -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_$1}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ AM_RUN_LOG([tardir=conftest.dir && eval $am__tar_ >conftest.tar])
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ AM_RUN_LOG([$am__untar <conftest.tar])
+ AM_RUN_LOG([cat conftest.dir/file])
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ AC_CACHE_VAL([am_cv_prog_tar_$1], [am_cv_prog_tar_$1=$_am_tool])
+ AC_MSG_RESULT([$am_cv_prog_tar_$1])])
+
+AC_SUBST([am__tar])
+AC_SUBST([am__untar])
+]) # _AM_PROG_TAR
+
+m4_include([m4/ax_arg_default_enable_disable.m4])
+m4_include([m4/ax_check_link_flag.m4])
+m4_include([m4/ax_cxx_compile_stdcxx_11.m4])
+m4_include([m4/boost.m4])
+m4_include([m4/libtool.m4])
+m4_include([m4/ltoptions.m4])
+m4_include([m4/ltsugar.m4])
+m4_include([m4/ltversion.m4])
+m4_include([m4/lt~obsolete.m4])
+m4_include([m4/pdns_check_bison.m4])
+m4_include([m4/pdns_check_cdb.m4])
+m4_include([m4/pdns_check_clock_gettime.m4])
+m4_include([m4/pdns_check_curl_program.m4])
+m4_include([m4/pdns_check_flex.m4])
+m4_include([m4/pdns_check_ldap.m4])
+m4_include([m4/pdns_check_libcrypto.m4])
+m4_include([m4/pdns_check_libcrypto_ecdsa.m4])
+m4_include([m4/pdns_check_libdecaf.m4])
+m4_include([m4/pdns_check_libsodium.m4])
+m4_include([m4/pdns_check_lua_hpp.m4])
+m4_include([m4/pdns_check_network_libs.m4])
+m4_include([m4/pdns_check_opendbx.m4])
+m4_include([m4/pdns_check_os.m4])
+m4_include([m4/pdns_check_pandoc.m4])
+m4_include([m4/pdns_check_ragel.m4])
+m4_include([m4/pdns_check_sqlite3.m4])
+m4_include([m4/pdns_d_fortify_source.m4])
+m4_include([m4/pdns_enable_botan.m4])
+m4_include([m4/pdns_enable_coverage.m4])
+m4_include([m4/pdns_enable_gss_tsig.m4])
+m4_include([m4/pdns_enable_malloc_trace.m4])
+m4_include([m4/pdns_enable_p11kit.m4])
+m4_include([m4/pdns_enable_remotebackend_zeromq.m4])
+m4_include([m4/pdns_enable_reproducible.m4])
+m4_include([m4/pdns_enable_sanitizers.m4])
+m4_include([m4/pdns_enable_unit_tests.m4])
+m4_include([m4/pdns_enable_verbose_logging.m4])
+m4_include([m4/pdns_from_git.m4])
+m4_include([m4/pdns_param_ssp_buffer_size.m4])
+m4_include([m4/pdns_pie.m4])
+m4_include([m4/pdns_relro.m4])
+m4_include([m4/pdns_stack_protector.m4])
+m4_include([m4/pdns_with_geo.m4])
+m4_include([m4/pdns_with_lua.m4])
+m4_include([m4/pdns_with_luajit.m4])
+m4_include([m4/pdns_with_mysql.m4])
+m4_include([m4/pdns_with_oracle.m4])
+m4_include([m4/pdns_with_postgresql.m4])
+m4_include([m4/pdns_with_protobuf.m4])
+m4_include([m4/pdns_with_sqlite3.m4])
+m4_include([m4/pdns_with_unixodbc.m4])
+m4_include([m4/systemd.m4])
+m4_include([m4/tm-gmtoff.m4])
+m4_include([m4/warnings.m4])
--- /dev/null
+#! /bin/sh
+# Wrapper for compilers which do not understand '-c -o'.
+
+scriptversion=2012-10-14.11; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+nl='
+'
+
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent tools from complaining about whitespace usage.
+IFS=" "" $nl"
+
+file_conv=
+
+# func_file_conv build_file lazy
+# Convert a $build file to $host form and store it in $file
+# Currently only supports Windows hosts. If the determined conversion
+# type is listed in (the comma separated) LAZY, no conversion will
+# take place.
+func_file_conv ()
+{
+ file=$1
+ case $file in
+ / | /[!/]*) # absolute file, and not a UNC file
+ if test -z "$file_conv"; then
+ # lazily determine how to convert abs files
+ case `uname -s` in
+ MINGW*)
+ file_conv=mingw
+ ;;
+ CYGWIN*)
+ file_conv=cygwin
+ ;;
+ *)
+ file_conv=wine
+ ;;
+ esac
+ fi
+ case $file_conv/,$2, in
+ *,$file_conv,*)
+ ;;
+ mingw/*)
+ file=`cmd //C echo "$file " | sed -e 's/"\(.*\) " *$/\1/'`
+ ;;
+ cygwin/*)
+ file=`cygpath -m "$file" || echo "$file"`
+ ;;
+ wine/*)
+ file=`winepath -w "$file" || echo "$file"`
+ ;;
+ esac
+ ;;
+ esac
+}
+
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+ func_file_conv "$1"
+ if test -z "$lib_path"; then
+ lib_path=$file
+ else
+ lib_path="$lib_path;$file"
+ fi
+ linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+ lib=$1
+ found=no
+ save_IFS=$IFS
+ IFS=';'
+ for dir in $lib_path $LIB
+ do
+ IFS=$save_IFS
+ if $shared && test -f "$dir/$lib.dll.lib"; then
+ found=yes
+ lib=$dir/$lib.dll.lib
+ break
+ fi
+ if test -f "$dir/$lib.lib"; then
+ found=yes
+ lib=$dir/$lib.lib
+ break
+ fi
+ if test -f "$dir/lib$lib.a"; then
+ found=yes
+ lib=$dir/lib$lib.a
+ break
+ fi
+ done
+ IFS=$save_IFS
+
+ if test "$found" != yes; then
+ lib=$lib.lib
+ fi
+}
+
+# func_cl_wrapper cl arg...
+# Adjust compile command to suit cl
+func_cl_wrapper ()
+{
+ # Assume a capable shell
+ lib_path=
+ shared=:
+ linker_opts=
+ for arg
+ do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ eat=1
+ case $2 in
+ *.o | *.[oO][bB][jJ])
+ func_file_conv "$2"
+ set x "$@" -Fo"$file"
+ shift
+ ;;
+ *)
+ func_file_conv "$2"
+ set x "$@" -Fe"$file"
+ shift
+ ;;
+ esac
+ ;;
+ -I)
+ eat=1
+ func_file_conv "$2" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -I*)
+ func_file_conv "${1#-I}" mingw
+ set x "$@" -I"$file"
+ shift
+ ;;
+ -l)
+ eat=1
+ func_cl_dashl "$2"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -l*)
+ func_cl_dashl "${1#-l}"
+ set x "$@" "$lib"
+ shift
+ ;;
+ -L)
+ eat=1
+ func_cl_dashL "$2"
+ ;;
+ -L*)
+ func_cl_dashL "${1#-L}"
+ ;;
+ -static)
+ shared=false
+ ;;
+ -Wl,*)
+ arg=${1#-Wl,}
+ save_ifs="$IFS"; IFS=','
+ for flag in $arg; do
+ IFS="$save_ifs"
+ linker_opts="$linker_opts $flag"
+ done
+ IFS="$save_ifs"
+ ;;
+ -Xlinker)
+ eat=1
+ linker_opts="$linker_opts $2"
+ ;;
+ -*)
+ set x "$@" "$1"
+ shift
+ ;;
+ *.cc | *.CC | *.cxx | *.CXX | *.[cC]++)
+ func_file_conv "$1"
+ set x "$@" -Tp"$file"
+ shift
+ ;;
+ *.c | *.cpp | *.CPP | *.lib | *.LIB | *.Lib | *.OBJ | *.obj | *.[oO])
+ func_file_conv "$1" mingw
+ set x "$@" "$file"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+ done
+ if test -n "$linker_opts"; then
+ linker_opts="-link$linker_opts"
+ fi
+ exec "$@" $linker_opts
+ exit 1
+}
+
+eat=
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: compile [--help] [--version] PROGRAM [ARGS]
+
+Wrapper for compilers which do not understand '-c -o'.
+Remove '-o dest.o' from ARGS, run PROGRAM with the remaining
+arguments, and rename the output as expected.
+
+If you are trying to build a whole package this is not the
+right script to run: please start by reading the file 'INSTALL'.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "compile $scriptversion"
+ exit $?
+ ;;
+ cl | *[/\\]cl | cl.exe | *[/\\]cl.exe )
+ func_cl_wrapper "$@" # Doesn't return...
+ ;;
+esac
+
+ofile=
+cfile=
+
+for arg
+do
+ if test -n "$eat"; then
+ eat=
+ else
+ case $1 in
+ -o)
+ # configure might choose to run compile as 'compile cc -o foo foo.c'.
+ # So we strip '-o arg' only if arg is an object.
+ eat=1
+ case $2 in
+ *.o | *.obj)
+ ofile=$2
+ ;;
+ *)
+ set x "$@" -o "$2"
+ shift
+ ;;
+ esac
+ ;;
+ *.c)
+ cfile=$1
+ set x "$@" "$1"
+ shift
+ ;;
+ *)
+ set x "$@" "$1"
+ shift
+ ;;
+ esac
+ fi
+ shift
+done
+
+if test -z "$ofile" || test -z "$cfile"; then
+ # If no '-o' option was seen then we might have been invoked from a
+ # pattern rule where we don't need one. That is ok -- this is a
+ # normal compilation that the losing compiler can handle. If no
+ # '.c' file was seen then we are probably linking. That is also
+ # ok.
+ exec "$@"
+fi
+
+# Name of file we expect compiler to create.
+cofile=`echo "$cfile" | sed 's|^.*[\\/]||; s|^[a-zA-Z]:||; s/\.c$/.o/'`
+
+# Create the lock directory.
+# Note: use '[/\\:.-]' here to ensure that we don't use the same name
+# that we are using for the .o file. Also, base the name on the expected
+# object file name, since that is what matters with a parallel build.
+lockdir=`echo "$cofile" | sed -e 's|[/\\:.-]|_|g'`.d
+while true; do
+ if mkdir "$lockdir" >/dev/null 2>&1; then
+ break
+ fi
+ sleep 1
+done
+# FIXME: race condition here if user kills between mkdir and trap.
+trap "rmdir '$lockdir'; exit 1" 1 2 15
+
+# Run the compile.
+"$@"
+ret=$?
+
+if test -f "$cofile"; then
+ test "$cofile" = "$ofile" || mv "$cofile" "$ofile"
+elif test -f "${cofile}bj"; then
+ test "${cofile}bj" = "$ofile" || mv "${cofile}bj" "$ofile"
+fi
+
+rmdir "$lockdir"
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+#! /bin/sh
+# Attempt to guess a canonical system name.
+# Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-03-23'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+#
+# Originally written by Per Bothner.
+#
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+#
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION]
+
+Output the configuration name of the system \`$me' is run on.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.guess ($timestamp)
+
+Originally written by Per Bothner.
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help" >&2
+ exit 1 ;;
+ * )
+ break ;;
+ esac
+done
+
+if test $# != 0; then
+ echo "$me: too many arguments$help" >&2
+ exit 1
+fi
+
+trap 'exit 1' 1 2 15
+
+# CC_FOR_BUILD -- compiler used by this script. Note that the use of a
+# compiler to aid in system detection is discouraged as it requires
+# temporary files to be created and, as you can see below, it is a
+# headache to deal with in a portable fashion.
+
+# Historically, `CC_FOR_BUILD' used to be named `HOST_CC'. We still
+# use `HOST_CC' if defined, but it is deprecated.
+
+# Portable tmp directory creation inspired by the Autoconf team.
+
+set_cc_for_build='
+trap "exitcode=\$?; (rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null) && exit \$exitcode" 0 ;
+trap "rm -f \$tmpfiles 2>/dev/null; rmdir \$tmp 2>/dev/null; exit 1" 1 2 13 15 ;
+: ${TMPDIR=/tmp} ;
+ { tmp=`(umask 077 && mktemp -d "$TMPDIR/cgXXXXXX") 2>/dev/null` && test -n "$tmp" && test -d "$tmp" ; } ||
+ { test -n "$RANDOM" && tmp=$TMPDIR/cg$$-$RANDOM && (umask 077 && mkdir $tmp) ; } ||
+ { tmp=$TMPDIR/cg-$$ && (umask 077 && mkdir $tmp) && echo "Warning: creating insecure temp directory" >&2 ; } ||
+ { echo "$me: cannot create a temporary directory in $TMPDIR" >&2 ; exit 1 ; } ;
+dummy=$tmp/dummy ;
+tmpfiles="$dummy.c $dummy.o $dummy.rel $dummy" ;
+case $CC_FOR_BUILD,$HOST_CC,$CC in
+ ,,) echo "int x;" > $dummy.c ;
+ for c in cc gcc c89 c99 ; do
+ if ($c -c -o $dummy.o $dummy.c) >/dev/null 2>&1 ; then
+ CC_FOR_BUILD="$c"; break ;
+ fi ;
+ done ;
+ if test x"$CC_FOR_BUILD" = x ; then
+ CC_FOR_BUILD=no_compiler_found ;
+ fi
+ ;;
+ ,,*) CC_FOR_BUILD=$CC ;;
+ ,*,*) CC_FOR_BUILD=$HOST_CC ;;
+esac ; set_cc_for_build= ;'
+
+# This is needed to find uname on a Pyramid OSx when run in the BSD universe.
+# (ghazi@noc.rutgers.edu 1994-08-24)
+if (test -f /.attbin/uname) >/dev/null 2>&1 ; then
+ PATH=$PATH:/.attbin ; export PATH
+fi
+
+UNAME_MACHINE=`(uname -m) 2>/dev/null` || UNAME_MACHINE=unknown
+UNAME_RELEASE=`(uname -r) 2>/dev/null` || UNAME_RELEASE=unknown
+UNAME_SYSTEM=`(uname -s) 2>/dev/null` || UNAME_SYSTEM=unknown
+UNAME_VERSION=`(uname -v) 2>/dev/null` || UNAME_VERSION=unknown
+
+case "${UNAME_SYSTEM}" in
+Linux|GNU|GNU/*)
+ # If the system lacks a compiler, then just pick glibc.
+ # We could probably try harder.
+ LIBC=gnu
+
+ eval $set_cc_for_build
+ cat <<-EOF > $dummy.c
+ #include <features.h>
+ #if defined(__UCLIBC__)
+ LIBC=uclibc
+ #elif defined(__dietlibc__)
+ LIBC=dietlibc
+ #else
+ LIBC=gnu
+ #endif
+ EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^LIBC' | sed 's, ,,g'`
+ ;;
+esac
+
+# Note: order is significant - the case branches are not exclusive.
+
+case "${UNAME_MACHINE}:${UNAME_SYSTEM}:${UNAME_RELEASE}:${UNAME_VERSION}" in
+ *:NetBSD:*:*)
+ # NetBSD (nbsd) targets should (where applicable) match one or
+ # more of the tuples: *-*-netbsdelf*, *-*-netbsdaout*,
+ # *-*-netbsdecoff* and *-*-netbsd*. For targets that recently
+ # switched to ELF, *-*-netbsd* would select the old
+ # object file format. This provides both forward
+ # compatibility and a consistent mechanism for selecting the
+ # object file format.
+ #
+ # Note: NetBSD doesn't particularly care about the vendor
+ # portion of the name. We always set it to "unknown".
+ sysctl="sysctl -n hw.machine_arch"
+ UNAME_MACHINE_ARCH=`(/sbin/$sysctl 2>/dev/null || \
+ /usr/sbin/$sysctl 2>/dev/null || echo unknown)`
+ case "${UNAME_MACHINE_ARCH}" in
+ armeb) machine=armeb-unknown ;;
+ arm*) machine=arm-unknown ;;
+ sh3el) machine=shl-unknown ;;
+ sh3eb) machine=sh-unknown ;;
+ sh5el) machine=sh5le-unknown ;;
+ *) machine=${UNAME_MACHINE_ARCH}-unknown ;;
+ esac
+ # The Operating System including object format, if it has switched
+ # to ELF recently, or will in the future.
+ case "${UNAME_MACHINE_ARCH}" in
+ arm*|i386|m68k|ns32k|sh3*|sparc|vax)
+ eval $set_cc_for_build
+ if echo __ELF__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ELF__
+ then
+ # Once all utilities can be ECOFF (netbsdecoff) or a.out (netbsdaout).
+ # Return netbsd for either. FIX?
+ os=netbsd
+ else
+ os=netbsdelf
+ fi
+ ;;
+ *)
+ os=netbsd
+ ;;
+ esac
+ # The OS release
+ # Debian GNU/NetBSD machines have a different userland, and
+ # thus, need a distinct triplet. However, they do not need
+ # kernel version information, so it can be replaced with a
+ # suitable tag, in the style of linux-gnu.
+ case "${UNAME_VERSION}" in
+ Debian*)
+ release='-gnu'
+ ;;
+ *)
+ release=`echo ${UNAME_RELEASE}|sed -e 's/[-_].*/\./'`
+ ;;
+ esac
+ # Since CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM:
+ # contains redundant information, the shorter form:
+ # CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM is used.
+ echo "${machine}-${os}${release}"
+ exit ;;
+ *:Bitrig:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/Bitrig.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-bitrig${UNAME_RELEASE}
+ exit ;;
+ *:OpenBSD:*:*)
+ UNAME_MACHINE_ARCH=`arch | sed 's/OpenBSD.//'`
+ echo ${UNAME_MACHINE_ARCH}-unknown-openbsd${UNAME_RELEASE}
+ exit ;;
+ *:ekkoBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-ekkobsd${UNAME_RELEASE}
+ exit ;;
+ *:SolidBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-solidbsd${UNAME_RELEASE}
+ exit ;;
+ macppc:MirBSD:*:*)
+ echo powerpc-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ *:MirBSD:*:*)
+ echo ${UNAME_MACHINE}-unknown-mirbsd${UNAME_RELEASE}
+ exit ;;
+ alpha:OSF1:*:*)
+ case $UNAME_RELEASE in
+ *4.0)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $3}'`
+ ;;
+ *5.*)
+ UNAME_RELEASE=`/usr/sbin/sizer -v | awk '{print $4}'`
+ ;;
+ esac
+ # According to Compaq, /usr/sbin/psrinfo has been available on
+ # OSF/1 and Tru64 systems produced since 1995. I hope that
+ # covers most systems running today. This code pipes the CPU
+ # types through head -n 1, so we only detect the type of CPU 0.
+ ALPHA_CPU_TYPE=`/usr/sbin/psrinfo -v | sed -n -e 's/^ The alpha \(.*\) processor.*$/\1/p' | head -n 1`
+ case "$ALPHA_CPU_TYPE" in
+ "EV4 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "EV4.5 (21064)")
+ UNAME_MACHINE="alpha" ;;
+ "LCA4 (21066/21068)")
+ UNAME_MACHINE="alpha" ;;
+ "EV5 (21164)")
+ UNAME_MACHINE="alphaev5" ;;
+ "EV5.6 (21164A)")
+ UNAME_MACHINE="alphaev56" ;;
+ "EV5.6 (21164PC)")
+ UNAME_MACHINE="alphapca56" ;;
+ "EV5.7 (21164PC)")
+ UNAME_MACHINE="alphapca57" ;;
+ "EV6 (21264)")
+ UNAME_MACHINE="alphaev6" ;;
+ "EV6.7 (21264A)")
+ UNAME_MACHINE="alphaev67" ;;
+ "EV6.8CB (21264C)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8AL (21264B)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.8CX (21264D)")
+ UNAME_MACHINE="alphaev68" ;;
+ "EV6.9A (21264/EV69A)")
+ UNAME_MACHINE="alphaev69" ;;
+ "EV7 (21364)")
+ UNAME_MACHINE="alphaev7" ;;
+ "EV7.9 (21364A)")
+ UNAME_MACHINE="alphaev79" ;;
+ esac
+ # A Pn.n version is a patched version.
+ # A Vn.n version is a released version.
+ # A Tn.n version is a released field test version.
+ # A Xn.n version is an unreleased experimental baselevel.
+ # 1.2 uses "1.2" for uname -r.
+ echo ${UNAME_MACHINE}-dec-osf`echo ${UNAME_RELEASE} | sed -e 's/^[PVTX]//' | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ # Reset EXIT trap before exiting to avoid spurious non-zero exit code.
+ exitcode=$?
+ trap '' 0
+ exit $exitcode ;;
+ Alpha\ *:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # Should we change UNAME_MACHINE based on the output of uname instead
+ # of the specific Alpha model?
+ echo alpha-pc-interix
+ exit ;;
+ 21064:Windows_NT:50:3)
+ echo alpha-dec-winnt3.5
+ exit ;;
+ Amiga*:UNIX_System_V:4.0:*)
+ echo m68k-unknown-sysv4
+ exit ;;
+ *:[Aa]miga[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-amigaos
+ exit ;;
+ *:[Mm]orph[Oo][Ss]:*:*)
+ echo ${UNAME_MACHINE}-unknown-morphos
+ exit ;;
+ *:OS/390:*:*)
+ echo i370-ibm-openedition
+ exit ;;
+ *:z/VM:*:*)
+ echo s390-ibm-zvmoe
+ exit ;;
+ *:OS400:*:*)
+ echo powerpc-ibm-os400
+ exit ;;
+ arm:RISC*:1.[012]*:*|arm:riscix:1.[012]*:*)
+ echo arm-acorn-riscix${UNAME_RELEASE}
+ exit ;;
+ arm*:riscos:*:*|arm*:RISCOS:*:*)
+ echo arm-unknown-riscos
+ exit ;;
+ SR2?01:HI-UX/MPP:*:* | SR8000:HI-UX/MPP:*:*)
+ echo hppa1.1-hitachi-hiuxmpp
+ exit ;;
+ Pyramid*:OSx*:*:* | MIS*:OSx*:*:* | MIS*:SMP_DC-OSx*:*:*)
+ # akee@wpdis03.wpafb.af.mil (Earle F. Ake) contributed MIS and NILE.
+ if test "`(/bin/universe) 2>/dev/null`" = att ; then
+ echo pyramid-pyramid-sysv3
+ else
+ echo pyramid-pyramid-bsd
+ fi
+ exit ;;
+ NILE*:*:*:dcosx)
+ echo pyramid-pyramid-svr4
+ exit ;;
+ DRS?6000:unix:4.0:6*)
+ echo sparc-icl-nx6
+ exit ;;
+ DRS?6000:UNIX_SV:4.2*:7* | DRS?6000:isis:4.2*:7*)
+ case `/usr/bin/uname -p` in
+ sparc) echo sparc-icl-nx7; exit ;;
+ esac ;;
+ s390x:SunOS:*:*)
+ echo ${UNAME_MACHINE}-ibm-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4H:SunOS:5.*:*)
+ echo sparc-hal-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:5.*:* | tadpole*:SunOS:5.*:*)
+ echo sparc-sun-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ i86pc:AuroraUX:5.*:* | i86xen:AuroraUX:5.*:*)
+ echo i386-pc-auroraux${UNAME_RELEASE}
+ exit ;;
+ i86pc:SunOS:5.*:* | i86xen:SunOS:5.*:*)
+ eval $set_cc_for_build
+ SUN_ARCH="i386"
+ # If there is a compiler, see if it is configured for 64-bit objects.
+ # Note that the Sun cc does not turn __LP64__ into 1 like gcc does.
+ # This test works for both compilers.
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __amd64'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ SUN_ARCH="x86_64"
+ fi
+ fi
+ echo ${SUN_ARCH}-pc-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:6*:*)
+ # According to config.sub, this is the proper way to canonicalize
+ # SunOS6. Hard to guess exactly what SunOS6 will be like, but
+ # it's likely to be more like Solaris than SunOS4.
+ echo sparc-sun-solaris3`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ sun4*:SunOS:*:*)
+ case "`/usr/bin/arch -k`" in
+ Series*|S4*)
+ UNAME_RELEASE=`uname -v`
+ ;;
+ esac
+ # Japanese Language versions have a version number like `4.1.3-JL'.
+ echo sparc-sun-sunos`echo ${UNAME_RELEASE}|sed -e 's/-/_/'`
+ exit ;;
+ sun3*:SunOS:*:*)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ exit ;;
+ sun*:*:4.2BSD:*)
+ UNAME_RELEASE=`(sed 1q /etc/motd | awk '{print substr($5,1,3)}') 2>/dev/null`
+ test "x${UNAME_RELEASE}" = "x" && UNAME_RELEASE=3
+ case "`/bin/arch`" in
+ sun3)
+ echo m68k-sun-sunos${UNAME_RELEASE}
+ ;;
+ sun4)
+ echo sparc-sun-sunos${UNAME_RELEASE}
+ ;;
+ esac
+ exit ;;
+ aushp:SunOS:*:*)
+ echo sparc-auspex-sunos${UNAME_RELEASE}
+ exit ;;
+ # The situation for MiNT is a little confusing. The machine name
+ # can be virtually everything (everything which is not
+ # "atarist" or "atariste" at least should have a processor
+ # > m68000). The system name ranges from "MiNT" over "FreeMiNT"
+ # to the lowercase version "mint" (or "freemint"). Finally
+ # the system name "TOS" denotes a system which is actually not
+ # MiNT. But MiNT is downward compatible to TOS, so this should
+ # be no problem.
+ atarist[e]:*MiNT:*:* | atarist[e]:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ atari*:*MiNT:*:* | atari*:*mint:*:* | atarist[e]:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ *falcon*:*MiNT:*:* | *falcon*:*mint:*:* | *falcon*:*TOS:*:*)
+ echo m68k-atari-mint${UNAME_RELEASE}
+ exit ;;
+ milan*:*MiNT:*:* | milan*:*mint:*:* | *milan*:*TOS:*:*)
+ echo m68k-milan-mint${UNAME_RELEASE}
+ exit ;;
+ hades*:*MiNT:*:* | hades*:*mint:*:* | *hades*:*TOS:*:*)
+ echo m68k-hades-mint${UNAME_RELEASE}
+ exit ;;
+ *:*MiNT:*:* | *:*mint:*:* | *:*TOS:*:*)
+ echo m68k-unknown-mint${UNAME_RELEASE}
+ exit ;;
+ m68k:machten:*:*)
+ echo m68k-apple-machten${UNAME_RELEASE}
+ exit ;;
+ powerpc:machten:*:*)
+ echo powerpc-apple-machten${UNAME_RELEASE}
+ exit ;;
+ RISC*:Mach:*:*)
+ echo mips-dec-mach_bsd4.3
+ exit ;;
+ RISC*:ULTRIX:*:*)
+ echo mips-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ VAX*:ULTRIX*:*:*)
+ echo vax-dec-ultrix${UNAME_RELEASE}
+ exit ;;
+ 2020:CLIX:*:* | 2430:CLIX:*:*)
+ echo clipper-intergraph-clix${UNAME_RELEASE}
+ exit ;;
+ mips:*:*:UMIPS | mips:*:*:RISCos)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+#ifdef __cplusplus
+#include <stdio.h> /* for printf() prototype */
+ int main (int argc, char *argv[]) {
+#else
+ int main (argc, argv) int argc; char *argv[]; {
+#endif
+ #if defined (host_mips) && defined (MIPSEB)
+ #if defined (SYSTYPE_SYSV)
+ printf ("mips-mips-riscos%ssysv\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_SVR4)
+ printf ("mips-mips-riscos%ssvr4\n", argv[1]); exit (0);
+ #endif
+ #if defined (SYSTYPE_BSD43) || defined(SYSTYPE_BSD)
+ printf ("mips-mips-riscos%sbsd\n", argv[1]); exit (0);
+ #endif
+ #endif
+ exit (-1);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c &&
+ dummyarg=`echo "${UNAME_RELEASE}" | sed -n 's/\([0-9]*\).*/\1/p'` &&
+ SYSTEM_NAME=`$dummy $dummyarg` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo mips-mips-riscos${UNAME_RELEASE}
+ exit ;;
+ Motorola:PowerMAX_OS:*:*)
+ echo powerpc-motorola-powermax
+ exit ;;
+ Motorola:*:4.3:PL8-*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:*:*:PowerMAX_OS | Synergy:PowerMAX_OS:*:*)
+ echo powerpc-harris-powermax
+ exit ;;
+ Night_Hawk:Power_UNIX:*:*)
+ echo powerpc-harris-powerunix
+ exit ;;
+ m88k:CX/UX:7*:*)
+ echo m88k-harris-cxux7
+ exit ;;
+ m88k:*:4*:R4*)
+ echo m88k-motorola-sysv4
+ exit ;;
+ m88k:*:3*:R3*)
+ echo m88k-motorola-sysv3
+ exit ;;
+ AViiON:dgux:*:*)
+ # DG/UX returns AViiON for all architectures
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ if [ $UNAME_PROCESSOR = mc88100 ] || [ $UNAME_PROCESSOR = mc88110 ]
+ then
+ if [ ${TARGET_BINARY_INTERFACE}x = m88kdguxelfx ] || \
+ [ ${TARGET_BINARY_INTERFACE}x = x ]
+ then
+ echo m88k-dg-dgux${UNAME_RELEASE}
+ else
+ echo m88k-dg-dguxbcs${UNAME_RELEASE}
+ fi
+ else
+ echo i586-dg-dgux${UNAME_RELEASE}
+ fi
+ exit ;;
+ M88*:DolphinOS:*:*) # DolphinOS (SVR3)
+ echo m88k-dolphin-sysv3
+ exit ;;
+ M88*:*:R3*:*)
+ # Delta 88k system running SVR3
+ echo m88k-motorola-sysv3
+ exit ;;
+ XD88*:*:*:*) # Tektronix XD88 system running UTekV (SVR3)
+ echo m88k-tektronix-sysv3
+ exit ;;
+ Tek43[0-9][0-9]:UTek:*:*) # Tektronix 4300 system running UTek (BSD)
+ echo m68k-tektronix-bsd
+ exit ;;
+ *:IRIX*:*:*)
+ echo mips-sgi-irix`echo ${UNAME_RELEASE}|sed -e 's/-/_/g'`
+ exit ;;
+ ????????:AIX?:[12].1:2) # AIX 2.2.1 or AIX 2.1.1 is RT/PC AIX.
+ echo romp-ibm-aix # uname -m gives an 8 hex-code CPU id
+ exit ;; # Note that: echo "'`uname -s`'" gives 'AIX '
+ i*86:AIX:*:*)
+ echo i386-ibm-aix
+ exit ;;
+ ia64:AIX:*:*)
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${UNAME_MACHINE}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:2:3)
+ if grep bos325 /usr/include/stdio.h >/dev/null 2>&1; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <sys/systemcfg.h>
+
+ main()
+ {
+ if (!__power_pc())
+ exit(1);
+ puts("powerpc-ibm-aix3.2.5");
+ exit(0);
+ }
+EOF
+ if $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy`
+ then
+ echo "$SYSTEM_NAME"
+ else
+ echo rs6000-ibm-aix3.2.5
+ fi
+ elif grep bos324 /usr/include/stdio.h >/dev/null 2>&1; then
+ echo rs6000-ibm-aix3.2.4
+ else
+ echo rs6000-ibm-aix3.2
+ fi
+ exit ;;
+ *:AIX:*:[4567])
+ IBM_CPU_ID=`/usr/sbin/lsdev -C -c processor -S available | sed 1q | awk '{ print $1 }'`
+ if /usr/sbin/lsattr -El ${IBM_CPU_ID} | grep ' POWER' >/dev/null 2>&1; then
+ IBM_ARCH=rs6000
+ else
+ IBM_ARCH=powerpc
+ fi
+ if [ -x /usr/bin/oslevel ] ; then
+ IBM_REV=`/usr/bin/oslevel`
+ else
+ IBM_REV=${UNAME_VERSION}.${UNAME_RELEASE}
+ fi
+ echo ${IBM_ARCH}-ibm-aix${IBM_REV}
+ exit ;;
+ *:AIX:*:*)
+ echo rs6000-ibm-aix
+ exit ;;
+ ibmrt:4.4BSD:*|romp-ibm:BSD:*)
+ echo romp-ibm-bsd4.4
+ exit ;;
+ ibmrt:*BSD:*|romp-ibm:BSD:*) # covers RT/PC BSD and
+ echo romp-ibm-bsd${UNAME_RELEASE} # 4.3 with uname added to
+ exit ;; # report: romp-ibm BSD 4.3
+ *:BOSX:*:*)
+ echo rs6000-bull-bosx
+ exit ;;
+ DPX/2?00:B.O.S.:*:*)
+ echo m68k-bull-sysv3
+ exit ;;
+ 9000/[34]??:4.3bsd:1.*:*)
+ echo m68k-hp-bsd
+ exit ;;
+ hp300:4.4BSD:*:* | 9000/[34]??:4.3bsd:2.*:*)
+ echo m68k-hp-bsd4.4
+ exit ;;
+ 9000/[34678]??:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ case "${UNAME_MACHINE}" in
+ 9000/31? ) HP_ARCH=m68000 ;;
+ 9000/[34]?? ) HP_ARCH=m68k ;;
+ 9000/[678][0-9][0-9])
+ if [ -x /usr/bin/getconf ]; then
+ sc_cpu_version=`/usr/bin/getconf SC_CPU_VERSION 2>/dev/null`
+ sc_kernel_bits=`/usr/bin/getconf SC_KERNEL_BITS 2>/dev/null`
+ case "${sc_cpu_version}" in
+ 523) HP_ARCH="hppa1.0" ;; # CPU_PA_RISC1_0
+ 528) HP_ARCH="hppa1.1" ;; # CPU_PA_RISC1_1
+ 532) # CPU_PA_RISC2_0
+ case "${sc_kernel_bits}" in
+ 32) HP_ARCH="hppa2.0n" ;;
+ 64) HP_ARCH="hppa2.0w" ;;
+ '') HP_ARCH="hppa2.0" ;; # HP-UX 10.20
+ esac ;;
+ esac
+ fi
+ if [ "${HP_ARCH}" = "" ]; then
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+
+ #define _HPUX_SOURCE
+ #include <stdlib.h>
+ #include <unistd.h>
+
+ int main ()
+ {
+ #if defined(_SC_KERNEL_BITS)
+ long bits = sysconf(_SC_KERNEL_BITS);
+ #endif
+ long cpu = sysconf (_SC_CPU_VERSION);
+
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1"); break;
+ case CPU_PA_RISC2_0:
+ #if defined(_SC_KERNEL_BITS)
+ switch (bits)
+ {
+ case 64: puts ("hppa2.0w"); break;
+ case 32: puts ("hppa2.0n"); break;
+ default: puts ("hppa2.0"); break;
+ } break;
+ #else /* !defined(_SC_KERNEL_BITS) */
+ puts ("hppa2.0"); break;
+ #endif
+ default: puts ("hppa1.0"); break;
+ }
+ exit (0);
+ }
+EOF
+ (CCOPTS= $CC_FOR_BUILD -o $dummy $dummy.c 2>/dev/null) && HP_ARCH=`$dummy`
+ test -z "$HP_ARCH" && HP_ARCH=hppa
+ fi ;;
+ esac
+ if [ ${HP_ARCH} = "hppa2.0w" ]
+ then
+ eval $set_cc_for_build
+
+ # hppa2.0w-hp-hpux* has a 64-bit kernel and a compiler generating
+ # 32-bit code. hppa64-hp-hpux* has the same kernel and a compiler
+ # generating 64-bit code. GNU and HP use different nomenclature:
+ #
+ # $ CC_FOR_BUILD=cc ./config.guess
+ # => hppa2.0w-hp-hpux11.23
+ # $ CC_FOR_BUILD="cc +DA2.0w" ./config.guess
+ # => hppa64-hp-hpux11.23
+
+ if echo __LP64__ | (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) |
+ grep -q __LP64__
+ then
+ HP_ARCH="hppa2.0w"
+ else
+ HP_ARCH="hppa64"
+ fi
+ fi
+ echo ${HP_ARCH}-hp-hpux${HPUX_REV}
+ exit ;;
+ ia64:HP-UX:*:*)
+ HPUX_REV=`echo ${UNAME_RELEASE}|sed -e 's/[^.]*.[0B]*//'`
+ echo ia64-hp-hpux${HPUX_REV}
+ exit ;;
+ 3050*:HI-UX:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #include <unistd.h>
+ int
+ main ()
+ {
+ long cpu = sysconf (_SC_CPU_VERSION);
+ /* The order matters, because CPU_IS_HP_MC68K erroneously returns
+ true for CPU_PA_RISC1_0. CPU_IS_PA_RISC returns correct
+ results, however. */
+ if (CPU_IS_PA_RISC (cpu))
+ {
+ switch (cpu)
+ {
+ case CPU_PA_RISC1_0: puts ("hppa1.0-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC1_1: puts ("hppa1.1-hitachi-hiuxwe2"); break;
+ case CPU_PA_RISC2_0: puts ("hppa2.0-hitachi-hiuxwe2"); break;
+ default: puts ("hppa-hitachi-hiuxwe2"); break;
+ }
+ }
+ else if (CPU_IS_HP_MC68K (cpu))
+ puts ("m68k-hitachi-hiuxwe2");
+ else puts ("unknown-hitachi-hiuxwe2");
+ exit (0);
+ }
+EOF
+ $CC_FOR_BUILD -o $dummy $dummy.c && SYSTEM_NAME=`$dummy` &&
+ { echo "$SYSTEM_NAME"; exit; }
+ echo unknown-hitachi-hiuxwe2
+ exit ;;
+ 9000/7??:4.3bsd:*:* | 9000/8?[79]:4.3bsd:*:* )
+ echo hppa1.1-hp-bsd
+ exit ;;
+ 9000/8??:4.3bsd:*:*)
+ echo hppa1.0-hp-bsd
+ exit ;;
+ *9??*:MPE/iX:*:* | *3000*:MPE/iX:*:*)
+ echo hppa1.0-hp-mpeix
+ exit ;;
+ hp7??:OSF1:*:* | hp8?[79]:OSF1:*:* )
+ echo hppa1.1-hp-osf
+ exit ;;
+ hp8??:OSF1:*:*)
+ echo hppa1.0-hp-osf
+ exit ;;
+ i*86:OSF1:*:*)
+ if [ -x /usr/sbin/sysversion ] ; then
+ echo ${UNAME_MACHINE}-unknown-osf1mk
+ else
+ echo ${UNAME_MACHINE}-unknown-osf1
+ fi
+ exit ;;
+ parisc*:Lites*:*:*)
+ echo hppa1.1-hp-lites
+ exit ;;
+ C1*:ConvexOS:*:* | convex:ConvexOS:C1*:*)
+ echo c1-convex-bsd
+ exit ;;
+ C2*:ConvexOS:*:* | convex:ConvexOS:C2*:*)
+ if getsysinfo -f scalar_acc
+ then echo c32-convex-bsd
+ else echo c2-convex-bsd
+ fi
+ exit ;;
+ C34*:ConvexOS:*:* | convex:ConvexOS:C34*:*)
+ echo c34-convex-bsd
+ exit ;;
+ C38*:ConvexOS:*:* | convex:ConvexOS:C38*:*)
+ echo c38-convex-bsd
+ exit ;;
+ C4*:ConvexOS:*:* | convex:ConvexOS:C4*:*)
+ echo c4-convex-bsd
+ exit ;;
+ CRAY*Y-MP:*:*:*)
+ echo ymp-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*[A-Z]90:*:*:*)
+ echo ${UNAME_MACHINE}-cray-unicos${UNAME_RELEASE} \
+ | sed -e 's/CRAY.*\([A-Z]90\)/\1/' \
+ -e y/ABCDEFGHIJKLMNOPQRSTUVWXYZ/abcdefghijklmnopqrstuvwxyz/ \
+ -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*TS:*:*:*)
+ echo t90-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*T3E:*:*:*)
+ echo alphaev5-cray-unicosmk${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ CRAY*SV1:*:*:*)
+ echo sv1-cray-unicos${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ *:UNICOS/mp:*:*)
+ echo craynv-cray-unicosmp${UNAME_RELEASE} | sed -e 's/\.[^.]*$/.X/'
+ exit ;;
+ F30[01]:UNIX_System_V:*:* | F700:UNIX_System_V:*:*)
+ FUJITSU_PROC=`uname -m | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz'`
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | sed -e 's/ /_/'`
+ echo "${FUJITSU_PROC}-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ 5000:UNIX_System_V:4.*:*)
+ FUJITSU_SYS=`uname -p | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/\///'`
+ FUJITSU_REL=`echo ${UNAME_RELEASE} | tr 'ABCDEFGHIJKLMNOPQRSTUVWXYZ' 'abcdefghijklmnopqrstuvwxyz' | sed -e 's/ /_/'`
+ echo "sparc-fujitsu-${FUJITSU_SYS}${FUJITSU_REL}"
+ exit ;;
+ i*86:BSD/386:*:* | i*86:BSD/OS:*:* | *:Ascend\ Embedded/OS:*:*)
+ echo ${UNAME_MACHINE}-pc-bsdi${UNAME_RELEASE}
+ exit ;;
+ sparc*:BSD/OS:*:*)
+ echo sparc-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:BSD/OS:*:*)
+ echo ${UNAME_MACHINE}-unknown-bsdi${UNAME_RELEASE}
+ exit ;;
+ *:FreeBSD:*:*)
+ UNAME_PROCESSOR=`/usr/bin/uname -p`
+ case ${UNAME_PROCESSOR} in
+ amd64)
+ echo x86_64-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ *)
+ echo ${UNAME_PROCESSOR}-unknown-freebsd`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'` ;;
+ esac
+ exit ;;
+ i*:CYGWIN*:*)
+ echo ${UNAME_MACHINE}-pc-cygwin
+ exit ;;
+ *:MINGW64*:*)
+ echo ${UNAME_MACHINE}-pc-mingw64
+ exit ;;
+ *:MINGW*:*)
+ echo ${UNAME_MACHINE}-pc-mingw32
+ exit ;;
+ *:MSYS*:*)
+ echo ${UNAME_MACHINE}-pc-msys
+ exit ;;
+ i*:windows32*:*)
+ # uname -m includes "-pc" on this system.
+ echo ${UNAME_MACHINE}-mingw32
+ exit ;;
+ i*:PW*:*)
+ echo ${UNAME_MACHINE}-pc-pw32
+ exit ;;
+ *:Interix*:*)
+ case ${UNAME_MACHINE} in
+ x86)
+ echo i586-pc-interix${UNAME_RELEASE}
+ exit ;;
+ authenticamd | genuineintel | EM64T)
+ echo x86_64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ IA64)
+ echo ia64-unknown-interix${UNAME_RELEASE}
+ exit ;;
+ esac ;;
+ [345]86:Windows_95:* | [345]86:Windows_98:* | [345]86:Windows_NT:*)
+ echo i${UNAME_MACHINE}-pc-mks
+ exit ;;
+ 8664:Windows_NT:*)
+ echo x86_64-pc-mks
+ exit ;;
+ i*:Windows_NT*:* | Pentium*:Windows_NT*:*)
+ # How do we know it's Interix rather than the generic POSIX subsystem?
+ # It also conflicts with pre-2.0 versions of AT&T UWIN. Should we
+ # UNAME_MACHINE based on the output of uname instead of i386?
+ echo i586-pc-interix
+ exit ;;
+ i*:UWIN*:*)
+ echo ${UNAME_MACHINE}-pc-uwin
+ exit ;;
+ amd64:CYGWIN*:*:* | x86_64:CYGWIN*:*:*)
+ echo x86_64-unknown-cygwin
+ exit ;;
+ p*:CYGWIN*:*)
+ echo powerpcle-unknown-cygwin
+ exit ;;
+ prep*:SunOS:5.*:*)
+ echo powerpcle-unknown-solaris2`echo ${UNAME_RELEASE}|sed -e 's/[^.]*//'`
+ exit ;;
+ *:GNU:*:*)
+ # the GNU system
+ echo `echo ${UNAME_MACHINE}|sed -e 's,[-/].*$,,'`-unknown-${LIBC}`echo ${UNAME_RELEASE}|sed -e 's,/.*$,,'`
+ exit ;;
+ *:GNU/*:*:*)
+ # other systems with GNU libc and userland
+ echo ${UNAME_MACHINE}-unknown-`echo ${UNAME_SYSTEM} | sed 's,^[^/]*/,,' | tr '[A-Z]' '[a-z]'``echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`-${LIBC}
+ exit ;;
+ i*86:Minix:*:*)
+ echo ${UNAME_MACHINE}-pc-minix
+ exit ;;
+ aarch64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ aarch64_be:Linux:*:*)
+ UNAME_MACHINE=aarch64_be
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ alpha:Linux:*:*)
+ case `sed -n '/^cpu model/s/^.*: \(.*\)/\1/p' < /proc/cpuinfo` in
+ EV5) UNAME_MACHINE=alphaev5 ;;
+ EV56) UNAME_MACHINE=alphaev56 ;;
+ PCA56) UNAME_MACHINE=alphapca56 ;;
+ PCA57) UNAME_MACHINE=alphapca56 ;;
+ EV6) UNAME_MACHINE=alphaev6 ;;
+ EV67) UNAME_MACHINE=alphaev67 ;;
+ EV68*) UNAME_MACHINE=alphaev68 ;;
+ esac
+ objdump --private-headers /bin/sh | grep -q ld.so.1
+ if test "$?" = 0 ; then LIBC="gnulibc1" ; fi
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arc:Linux:*:* | arceb:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ arm*:Linux:*:*)
+ eval $set_cc_for_build
+ if echo __ARM_EABI__ | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_EABI__
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ else
+ if echo __ARM_PCS_VFP | $CC_FOR_BUILD -E - 2>/dev/null \
+ | grep -q __ARM_PCS_VFP
+ then
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabi
+ else
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}eabihf
+ fi
+ fi
+ exit ;;
+ avr32*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ cris:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ crisv32:Linux:*:*)
+ echo ${UNAME_MACHINE}-axis-linux-${LIBC}
+ exit ;;
+ frv:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ hexagon:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:Linux:*:*)
+ echo ${UNAME_MACHINE}-pc-linux-${LIBC}
+ exit ;;
+ ia64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m32r*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ m68*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ mips:Linux:*:* | mips64:Linux:*:*)
+ eval $set_cc_for_build
+ sed 's/^ //' << EOF >$dummy.c
+ #undef CPU
+ #undef ${UNAME_MACHINE}
+ #undef ${UNAME_MACHINE}el
+ #if defined(__MIPSEL__) || defined(__MIPSEL) || defined(_MIPSEL) || defined(MIPSEL)
+ CPU=${UNAME_MACHINE}el
+ #else
+ #if defined(__MIPSEB__) || defined(__MIPSEB) || defined(_MIPSEB) || defined(MIPSEB)
+ CPU=${UNAME_MACHINE}
+ #else
+ CPU=
+ #endif
+ #endif
+EOF
+ eval `$CC_FOR_BUILD -E $dummy.c 2>/dev/null | grep '^CPU'`
+ test x"${CPU}" != x && { echo "${CPU}-unknown-linux-${LIBC}"; exit; }
+ ;;
+ openrisc*:Linux:*:*)
+ echo or1k-unknown-linux-${LIBC}
+ exit ;;
+ or32:Linux:*:* | or1k*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ padre:Linux:*:*)
+ echo sparc-unknown-linux-${LIBC}
+ exit ;;
+ parisc64:Linux:*:* | hppa64:Linux:*:*)
+ echo hppa64-unknown-linux-${LIBC}
+ exit ;;
+ parisc:Linux:*:* | hppa:Linux:*:*)
+ # Look for CPU level
+ case `grep '^cpu[^a-z]*:' /proc/cpuinfo 2>/dev/null | cut -d' ' -f2` in
+ PA7*) echo hppa1.1-unknown-linux-${LIBC} ;;
+ PA8*) echo hppa2.0-unknown-linux-${LIBC} ;;
+ *) echo hppa-unknown-linux-${LIBC} ;;
+ esac
+ exit ;;
+ ppc64:Linux:*:*)
+ echo powerpc64-unknown-linux-${LIBC}
+ exit ;;
+ ppc:Linux:*:*)
+ echo powerpc-unknown-linux-${LIBC}
+ exit ;;
+ ppc64le:Linux:*:*)
+ echo powerpc64le-unknown-linux-${LIBC}
+ exit ;;
+ ppcle:Linux:*:*)
+ echo powerpcle-unknown-linux-${LIBC}
+ exit ;;
+ s390:Linux:*:* | s390x:Linux:*:*)
+ echo ${UNAME_MACHINE}-ibm-linux-${LIBC}
+ exit ;;
+ sh64*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sh*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ sparc:Linux:*:* | sparc64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ tile*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ vax:Linux:*:*)
+ echo ${UNAME_MACHINE}-dec-linux-${LIBC}
+ exit ;;
+ x86_64:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ xtensa*:Linux:*:*)
+ echo ${UNAME_MACHINE}-unknown-linux-${LIBC}
+ exit ;;
+ i*86:DYNIX/ptx:4*:*)
+ # ptx 4.0 does uname -s correctly, with DYNIX/ptx in there.
+ # earlier versions are messed up and put the nodename in both
+ # sysname and nodename.
+ echo i386-sequent-sysv4
+ exit ;;
+ i*86:UNIX_SV:4.2MP:2.*)
+ # Unixware is an offshoot of SVR4, but it has its own version
+ # number series starting with 2...
+ # I am not positive that other SVR4 systems won't match this,
+ # I just have to hope. -- rms.
+ # Use sysv4.2uw... so that sysv4* matches it.
+ echo ${UNAME_MACHINE}-pc-sysv4.2uw${UNAME_VERSION}
+ exit ;;
+ i*86:OS/2:*:*)
+ # If we were able to find `uname', then EMX Unix compatibility
+ # is probably installed.
+ echo ${UNAME_MACHINE}-pc-os2-emx
+ exit ;;
+ i*86:XTS-300:*:STOP)
+ echo ${UNAME_MACHINE}-unknown-stop
+ exit ;;
+ i*86:atheos:*:*)
+ echo ${UNAME_MACHINE}-unknown-atheos
+ exit ;;
+ i*86:syllable:*:*)
+ echo ${UNAME_MACHINE}-pc-syllable
+ exit ;;
+ i*86:LynxOS:2.*:* | i*86:LynxOS:3.[01]*:* | i*86:LynxOS:4.[02]*:*)
+ echo i386-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ i*86:*DOS:*:*)
+ echo ${UNAME_MACHINE}-pc-msdosdjgpp
+ exit ;;
+ i*86:*:4.*:* | i*86:SYSTEM_V:4.*:*)
+ UNAME_REL=`echo ${UNAME_RELEASE} | sed 's/\/MP$//'`
+ if grep Novell /usr/include/link.h >/dev/null 2>/dev/null; then
+ echo ${UNAME_MACHINE}-univel-sysv${UNAME_REL}
+ else
+ echo ${UNAME_MACHINE}-pc-sysv${UNAME_REL}
+ fi
+ exit ;;
+ i*86:*:5:[678]*)
+ # UnixWare 7.x, OpenUNIX and OpenServer 6.
+ case `/bin/uname -X | grep "^Machine"` in
+ *486*) UNAME_MACHINE=i486 ;;
+ *Pentium) UNAME_MACHINE=i586 ;;
+ *Pent*|*Celeron) UNAME_MACHINE=i686 ;;
+ esac
+ echo ${UNAME_MACHINE}-unknown-sysv${UNAME_RELEASE}${UNAME_SYSTEM}${UNAME_VERSION}
+ exit ;;
+ i*86:*:3.2:*)
+ if test -f /usr/options/cb.name; then
+ UNAME_REL=`sed -n 's/.*Version //p' </usr/options/cb.name`
+ echo ${UNAME_MACHINE}-pc-isc$UNAME_REL
+ elif /bin/uname -X 2>/dev/null >/dev/null ; then
+ UNAME_REL=`(/bin/uname -X|grep Release|sed -e 's/.*= //')`
+ (/bin/uname -X|grep i80486 >/dev/null) && UNAME_MACHINE=i486
+ (/bin/uname -X|grep '^Machine.*Pentium' >/dev/null) \
+ && UNAME_MACHINE=i586
+ (/bin/uname -X|grep '^Machine.*Pent *II' >/dev/null) \
+ && UNAME_MACHINE=i686
+ (/bin/uname -X|grep '^Machine.*Pentium Pro' >/dev/null) \
+ && UNAME_MACHINE=i686
+ echo ${UNAME_MACHINE}-pc-sco$UNAME_REL
+ else
+ echo ${UNAME_MACHINE}-pc-sysv32
+ fi
+ exit ;;
+ pc:*:*:*)
+ # Left here for compatibility:
+ # uname -m prints for DJGPP always 'pc', but it prints nothing about
+ # the processor, so we play safe by assuming i586.
+ # Note: whatever this is, it MUST be the same as what config.sub
+ # prints for the "djgpp" host, or else GDB configury will decide that
+ # this is a cross-build.
+ echo i586-pc-msdosdjgpp
+ exit ;;
+ Intel:Mach:3*:*)
+ echo i386-pc-mach3
+ exit ;;
+ paragon:*:*:*)
+ echo i860-intel-osf1
+ exit ;;
+ i860:*:4.*:*) # i860-SVR4
+ if grep Stardent /usr/include/sys/uadmin.h >/dev/null 2>&1 ; then
+ echo i860-stardent-sysv${UNAME_RELEASE} # Stardent Vistra i860-SVR4
+ else # Add other i860-SVR4 vendors below as they are discovered.
+ echo i860-unknown-sysv${UNAME_RELEASE} # Unknown i860-SVR4
+ fi
+ exit ;;
+ mini*:CTIX:SYS*5:*)
+ # "miniframe"
+ echo m68010-convergent-sysv
+ exit ;;
+ mc68k:UNIX:SYSTEM5:3.51m)
+ echo m68k-convergent-sysv
+ exit ;;
+ M680?0:D-NIX:5.3:*)
+ echo m68k-diab-dnix
+ exit ;;
+ M68*:*:R3V[5678]*:*)
+ test -r /sysV68 && { echo 'm68k-motorola-sysv'; exit; } ;;
+ 3[345]??:*:4.0:3.0 | 3[34]??A:*:4.0:3.0 | 3[34]??,*:*:4.0:3.0 | 3[34]??/*:*:4.0:3.0 | 4400:*:4.0:3.0 | 4850:*:4.0:3.0 | SKA40:*:4.0:3.0 | SDS2:*:4.0:3.0 | SHG2:*:4.0:3.0 | S7501*:*:4.0:3.0)
+ OS_REL=''
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ 3[34]??:*:4.0:* | 3[34]??,*:*:4.0:*)
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4; exit; } ;;
+ NCR*:*:4.2:* | MPRAS*:*:4.2:*)
+ OS_REL='.3'
+ test -r /etc/.relid \
+ && OS_REL=.`sed -n 's/[^ ]* [^ ]* \([0-9][0-9]\).*/\1/p' < /etc/.relid`
+ /bin/uname -p 2>/dev/null | grep 86 >/dev/null \
+ && { echo i486-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep entium >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; }
+ /bin/uname -p 2>/dev/null | /bin/grep pteron >/dev/null \
+ && { echo i586-ncr-sysv4.3${OS_REL}; exit; } ;;
+ m68*:LynxOS:2.*:* | m68*:LynxOS:3.0*:*)
+ echo m68k-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ mc68030:UNIX_System_V:4.*:*)
+ echo m68k-atari-sysv4
+ exit ;;
+ TSUNAMI:LynxOS:2.*:*)
+ echo sparc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ rs6000:LynxOS:2.*:*)
+ echo rs6000-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ PowerPC:LynxOS:2.*:* | PowerPC:LynxOS:3.[01]*:* | PowerPC:LynxOS:4.[02]*:*)
+ echo powerpc-unknown-lynxos${UNAME_RELEASE}
+ exit ;;
+ SM[BE]S:UNIX_SV:*:*)
+ echo mips-dde-sysv${UNAME_RELEASE}
+ exit ;;
+ RM*:ReliantUNIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ RM*:SINIX-*:*:*)
+ echo mips-sni-sysv4
+ exit ;;
+ *:SINIX-*:*:*)
+ if uname -p 2>/dev/null >/dev/null ; then
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ echo ${UNAME_MACHINE}-sni-sysv4
+ else
+ echo ns32k-sni-sysv
+ fi
+ exit ;;
+ PENTIUM:*:4.0*:*) # Unisys `ClearPath HMP IX 4000' SVR4/MP effort
+ # says <Richard.M.Bartel@ccMail.Census.GOV>
+ echo i586-unisys-sysv4
+ exit ;;
+ *:UNIX_System_V:4*:FTX*)
+ # From Gerald Hewes <hewes@openmarket.com>.
+ # How about differentiating between stratus architectures? -djm
+ echo hppa1.1-stratus-sysv4
+ exit ;;
+ *:*:*:FTX*)
+ # From seanf@swdc.stratus.com.
+ echo i860-stratus-sysv4
+ exit ;;
+ i*86:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo ${UNAME_MACHINE}-stratus-vos
+ exit ;;
+ *:VOS:*:*)
+ # From Paul.Green@stratus.com.
+ echo hppa1.1-stratus-vos
+ exit ;;
+ mc68*:A/UX:*:*)
+ echo m68k-apple-aux${UNAME_RELEASE}
+ exit ;;
+ news*:NEWS-OS:6*:*)
+ echo mips-sony-newsos6
+ exit ;;
+ R[34]000:*System_V*:*:* | R4000:UNIX_SYSV:*:* | R*000:UNIX_SV:*:*)
+ if [ -d /usr/nec ]; then
+ echo mips-nec-sysv${UNAME_RELEASE}
+ else
+ echo mips-unknown-sysv${UNAME_RELEASE}
+ fi
+ exit ;;
+ BeBox:BeOS:*:*) # BeOS running on hardware made by Be, PPC only.
+ echo powerpc-be-beos
+ exit ;;
+ BeMac:BeOS:*:*) # BeOS running on Mac or Mac clone, PPC only.
+ echo powerpc-apple-beos
+ exit ;;
+ BePC:BeOS:*:*) # BeOS running on Intel PC compatible.
+ echo i586-pc-beos
+ exit ;;
+ BePC:Haiku:*:*) # Haiku running on Intel PC compatible.
+ echo i586-pc-haiku
+ exit ;;
+ x86_64:Haiku:*:*)
+ echo x86_64-unknown-haiku
+ exit ;;
+ SX-4:SUPER-UX:*:*)
+ echo sx4-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-5:SUPER-UX:*:*)
+ echo sx5-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-6:SUPER-UX:*:*)
+ echo sx6-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-7:SUPER-UX:*:*)
+ echo sx7-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8:SUPER-UX:*:*)
+ echo sx8-nec-superux${UNAME_RELEASE}
+ exit ;;
+ SX-8R:SUPER-UX:*:*)
+ echo sx8r-nec-superux${UNAME_RELEASE}
+ exit ;;
+ Power*:Rhapsody:*:*)
+ echo powerpc-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Rhapsody:*:*)
+ echo ${UNAME_MACHINE}-apple-rhapsody${UNAME_RELEASE}
+ exit ;;
+ *:Darwin:*:*)
+ UNAME_PROCESSOR=`uname -p` || UNAME_PROCESSOR=unknown
+ eval $set_cc_for_build
+ if test "$UNAME_PROCESSOR" = unknown ; then
+ UNAME_PROCESSOR=powerpc
+ fi
+ if test `echo "$UNAME_RELEASE" | sed -e 's/\..*//'` -le 10 ; then
+ if [ "$CC_FOR_BUILD" != 'no_compiler_found' ]; then
+ if (echo '#ifdef __LP64__'; echo IS_64BIT_ARCH; echo '#endif') | \
+ (CCOPTS= $CC_FOR_BUILD -E - 2>/dev/null) | \
+ grep IS_64BIT_ARCH >/dev/null
+ then
+ case $UNAME_PROCESSOR in
+ i386) UNAME_PROCESSOR=x86_64 ;;
+ powerpc) UNAME_PROCESSOR=powerpc64 ;;
+ esac
+ fi
+ fi
+ elif test "$UNAME_PROCESSOR" = i386 ; then
+ # Avoid executing cc on OS X 10.9, as it ships with a stub
+ # that puts up a graphical alert prompting to install
+ # developer tools. Any system running Mac OS X 10.7 or
+ # later (Darwin 11 and later) is required to have a 64-bit
+ # processor. This is not true of the ARM version of Darwin
+ # that Apple uses in portable devices.
+ UNAME_PROCESSOR=x86_64
+ fi
+ echo ${UNAME_PROCESSOR}-apple-darwin${UNAME_RELEASE}
+ exit ;;
+ *:procnto*:*:* | *:QNX:[0123456789]*:*)
+ UNAME_PROCESSOR=`uname -p`
+ if test "$UNAME_PROCESSOR" = "x86"; then
+ UNAME_PROCESSOR=i386
+ UNAME_MACHINE=pc
+ fi
+ echo ${UNAME_PROCESSOR}-${UNAME_MACHINE}-nto-qnx${UNAME_RELEASE}
+ exit ;;
+ *:QNX:*:4*)
+ echo i386-pc-qnx
+ exit ;;
+ NEO-?:NONSTOP_KERNEL:*:*)
+ echo neo-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSE-*:NONSTOP_KERNEL:*:*)
+ echo nse-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ NSR-?:NONSTOP_KERNEL:*:*)
+ echo nsr-tandem-nsk${UNAME_RELEASE}
+ exit ;;
+ *:NonStop-UX:*:*)
+ echo mips-compaq-nonstopux
+ exit ;;
+ BS2000:POSIX*:*:*)
+ echo bs2000-siemens-sysv
+ exit ;;
+ DS/*:UNIX_System_V:*:*)
+ echo ${UNAME_MACHINE}-${UNAME_SYSTEM}-${UNAME_RELEASE}
+ exit ;;
+ *:Plan9:*:*)
+ # "uname -m" is not consistent, so use $cputype instead. 386
+ # is converted to i386 for consistency with other x86
+ # operating systems.
+ if test "$cputype" = "386"; then
+ UNAME_MACHINE=i386
+ else
+ UNAME_MACHINE="$cputype"
+ fi
+ echo ${UNAME_MACHINE}-unknown-plan9
+ exit ;;
+ *:TOPS-10:*:*)
+ echo pdp10-unknown-tops10
+ exit ;;
+ *:TENEX:*:*)
+ echo pdp10-unknown-tenex
+ exit ;;
+ KS10:TOPS-20:*:* | KL10:TOPS-20:*:* | TYPE4:TOPS-20:*:*)
+ echo pdp10-dec-tops20
+ exit ;;
+ XKL-1:TOPS-20:*:* | TYPE5:TOPS-20:*:*)
+ echo pdp10-xkl-tops20
+ exit ;;
+ *:TOPS-20:*:*)
+ echo pdp10-unknown-tops20
+ exit ;;
+ *:ITS:*:*)
+ echo pdp10-unknown-its
+ exit ;;
+ SEI:*:*:SEIUX)
+ echo mips-sei-seiux${UNAME_RELEASE}
+ exit ;;
+ *:DragonFly:*:*)
+ echo ${UNAME_MACHINE}-unknown-dragonfly`echo ${UNAME_RELEASE}|sed -e 's/[-(].*//'`
+ exit ;;
+ *:*VMS:*:*)
+ UNAME_MACHINE=`(uname -p) 2>/dev/null`
+ case "${UNAME_MACHINE}" in
+ A*) echo alpha-dec-vms ; exit ;;
+ I*) echo ia64-dec-vms ; exit ;;
+ V*) echo vax-dec-vms ; exit ;;
+ esac ;;
+ *:XENIX:*:SysV)
+ echo i386-pc-xenix
+ exit ;;
+ i*86:skyos:*:*)
+ echo ${UNAME_MACHINE}-pc-skyos`echo ${UNAME_RELEASE}` | sed -e 's/ .*$//'
+ exit ;;
+ i*86:rdos:*:*)
+ echo ${UNAME_MACHINE}-pc-rdos
+ exit ;;
+ i*86:AROS:*:*)
+ echo ${UNAME_MACHINE}-pc-aros
+ exit ;;
+ x86_64:VMkernel:*:*)
+ echo ${UNAME_MACHINE}-unknown-esx
+ exit ;;
+esac
+
+cat >&2 <<EOF
+$0: unable to guess system type
+
+This script, last modified $timestamp, has failed to recognize
+the operating system you are using. It is advised that you
+download the most up to date version of the config scripts from
+
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.guess;hb=HEAD
+and
+ http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+If the version you run ($0) is already up to date, please
+send the following data and any information you think might be
+pertinent to <config-patches@gnu.org> in order to provide the needed
+information to handle your system.
+
+config.guess timestamp = $timestamp
+
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null`
+
+hostinfo = `(hostinfo) 2>/dev/null`
+/bin/universe = `(/bin/universe) 2>/dev/null`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null`
+/bin/arch = `(/bin/arch) 2>/dev/null`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null`
+
+UNAME_MACHINE = ${UNAME_MACHINE}
+UNAME_RELEASE = ${UNAME_RELEASE}
+UNAME_SYSTEM = ${UNAME_SYSTEM}
+UNAME_VERSION = ${UNAME_VERSION}
+EOF
+
+exit 1
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# Configuration validation subroutine script.
+# Copyright 1992-2014 Free Software Foundation, Inc.
+
+timestamp='2014-09-11'
+
+# This file is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that
+# program. This Exception is an additional permission under section 7
+# of the GNU General Public License, version 3 ("GPLv3").
+
+
+# Please send patches with a ChangeLog entry to config-patches@gnu.org.
+#
+# Configuration subroutine to validate and canonicalize a configuration type.
+# Supply the specified configuration type as an argument.
+# If it is invalid, we print an error message on stderr and exit with code 1.
+# Otherwise, we print the canonical config type on stdout and succeed.
+
+# You can get the latest version of this script from:
+# http://git.savannah.gnu.org/gitweb/?p=config.git;a=blob_plain;f=config.sub;hb=HEAD
+
+# This file is supposed to be the same for all GNU packages
+# and recognize all the CPU types, system types and aliases
+# that are meaningful with *any* GNU software.
+# Each package is responsible for reporting which valid configurations
+# it does not support. The user should be able to distinguish
+# a failure to support a valid configuration from a meaningless
+# configuration.
+
+# The goal of this file is to map all the various variations of a given
+# machine specification into a single specification in the form:
+# CPU_TYPE-MANUFACTURER-OPERATING_SYSTEM
+# or in some cases, the newer four-part form:
+# CPU_TYPE-MANUFACTURER-KERNEL-OPERATING_SYSTEM
+# It is wrong to echo any other type of specification.
+
+me=`echo "$0" | sed -e 's,.*/,,'`
+
+usage="\
+Usage: $0 [OPTION] CPU-MFR-OPSYS
+ $0 [OPTION] ALIAS
+
+Canonicalize a configuration name.
+
+Operation modes:
+ -h, --help print this help, then exit
+ -t, --time-stamp print date of last modification, then exit
+ -v, --version print version number, then exit
+
+Report bugs and patches to <config-patches@gnu.org>."
+
+version="\
+GNU config.sub ($timestamp)
+
+Copyright 1992-2014 Free Software Foundation, Inc.
+
+This is free software; see the source for copying conditions. There is NO
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
+
+help="
+Try \`$me --help' for more information."
+
+# Parse command line
+while test $# -gt 0 ; do
+ case $1 in
+ --time-stamp | --time* | -t )
+ echo "$timestamp" ; exit ;;
+ --version | -v )
+ echo "$version" ; exit ;;
+ --help | --h* | -h )
+ echo "$usage"; exit ;;
+ -- ) # Stop option processing
+ shift; break ;;
+ - ) # Use stdin as input.
+ break ;;
+ -* )
+ echo "$me: invalid option $1$help"
+ exit 1 ;;
+
+ *local*)
+ # First pass through any local machine types.
+ echo $1
+ exit ;;
+
+ * )
+ break ;;
+ esac
+done
+
+case $# in
+ 0) echo "$me: missing argument$help" >&2
+ exit 1;;
+ 1) ;;
+ *) echo "$me: too many arguments$help" >&2
+ exit 1;;
+esac
+
+# Separate what the user gave into CPU-COMPANY and OS or KERNEL-OS (if any).
+# Here we must recognize all the valid KERNEL-OS combinations.
+maybe_os=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\2/'`
+case $maybe_os in
+ nto-qnx* | linux-gnu* | linux-android* | linux-dietlibc | linux-newlib* | \
+ linux-musl* | linux-uclibc* | uclinux-uclibc* | uclinux-gnu* | kfreebsd*-gnu* | \
+ knetbsd*-gnu* | netbsd*-gnu* | \
+ kopensolaris*-gnu* | \
+ storm-chaos* | os2-emx* | rtmk-nova*)
+ os=-$maybe_os
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`
+ ;;
+ android-linux)
+ os=-linux-android
+ basic_machine=`echo $1 | sed 's/^\(.*\)-\([^-]*-[^-]*\)$/\1/'`-unknown
+ ;;
+ *)
+ basic_machine=`echo $1 | sed 's/-[^-]*$//'`
+ if [ $basic_machine != $1 ]
+ then os=`echo $1 | sed 's/.*-/-/'`
+ else os=; fi
+ ;;
+esac
+
+### Let's recognize common machines as not being operating systems so
+### that things like config.sub decstation-3100 work. We also
+### recognize some manufacturers as not being operating systems, so we
+### can provide default operating systems below.
+case $os in
+ -sun*os*)
+ # Prevent following clause from handling this invalid input.
+ ;;
+ -dec* | -mips* | -sequent* | -encore* | -pc532* | -sgi* | -sony* | \
+ -att* | -7300* | -3300* | -delta* | -motorola* | -sun[234]* | \
+ -unicom* | -ibm* | -next | -hp | -isi* | -apollo | -altos* | \
+ -convergent* | -ncr* | -news | -32* | -3600* | -3100* | -hitachi* |\
+ -c[123]* | -convex* | -sun | -crds | -omron* | -dg | -ultra | -tti* | \
+ -harris | -dolphin | -highlevel | -gould | -cbm | -ns | -masscomp | \
+ -apple | -axis | -knuth | -cray | -microblaze*)
+ os=
+ basic_machine=$1
+ ;;
+ -bluegene*)
+ os=-cnk
+ ;;
+ -sim | -cisco | -oki | -wec | -winbond)
+ os=
+ basic_machine=$1
+ ;;
+ -scout)
+ ;;
+ -wrs)
+ os=-vxworks
+ basic_machine=$1
+ ;;
+ -chorusos*)
+ os=-chorusos
+ basic_machine=$1
+ ;;
+ -chorusrdb)
+ os=-chorusrdb
+ basic_machine=$1
+ ;;
+ -hiux*)
+ os=-hiuxwe2
+ ;;
+ -sco6)
+ os=-sco5v6
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5)
+ os=-sco3.2v5
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco4)
+ os=-sco3.2v4
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2.[4-9]*)
+ os=`echo $os | sed -e 's/sco3.2./sco3.2v/'`
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco3.2v[4-9]*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco5v6*)
+ # Don't forget version if it is 3.2v4 or newer.
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -sco*)
+ os=-sco3.2v2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -udk*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -isc)
+ os=-isc2.2
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -clix*)
+ basic_machine=clipper-intergraph
+ ;;
+ -isc*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
+ ;;
+ -lynx*178)
+ os=-lynxos178
+ ;;
+ -lynx*5)
+ os=-lynxos5
+ ;;
+ -lynx*)
+ os=-lynxos
+ ;;
+ -ptx*)
+ basic_machine=`echo $1 | sed -e 's/86-.*/86-sequent/'`
+ ;;
+ -windowsnt*)
+ os=`echo $os | sed -e 's/windowsnt/winnt/'`
+ ;;
+ -psos*)
+ os=-psos
+ ;;
+ -mint | -mint[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+esac
+
+# Decode aliases for certain CPU-COMPANY combinations.
+case $basic_machine in
+ # Recognize the basic CPU types without company name.
+ # Some are omitted here because they have special meanings below.
+ 1750a | 580 \
+ | a29k \
+ | aarch64 | aarch64_be \
+ | alpha | alphaev[4-8] | alphaev56 | alphaev6[78] | alphapca5[67] \
+ | alpha64 | alpha64ev[4-8] | alpha64ev56 | alpha64ev6[78] | alpha64pca5[67] \
+ | am33_2.0 \
+ | arc | arceb \
+ | arm | arm[bl]e | arme[lb] | armv[2-8] | armv[3-8][lb] | armv7[arm] \
+ | avr | avr32 \
+ | be32 | be64 \
+ | bfin \
+ | c4x | c8051 | clipper \
+ | d10v | d30v | dlx | dsp16xx \
+ | epiphany \
+ | fido | fr30 | frv \
+ | h8300 | h8500 | hppa | hppa1.[01] | hppa2.0 | hppa2.0[nw] | hppa64 \
+ | hexagon \
+ | i370 | i860 | i960 | ia64 \
+ | ip2k | iq2000 \
+ | k1om \
+ | le32 | le64 \
+ | lm32 \
+ | m32c | m32r | m32rle | m68000 | m68k | m88k \
+ | maxq | mb | microblaze | microblazeel | mcore | mep | metag \
+ | mips | mipsbe | mipseb | mipsel | mipsle \
+ | mips16 \
+ | mips64 | mips64el \
+ | mips64octeon | mips64octeonel \
+ | mips64orion | mips64orionel \
+ | mips64r5900 | mips64r5900el \
+ | mips64vr | mips64vrel \
+ | mips64vr4100 | mips64vr4100el \
+ | mips64vr4300 | mips64vr4300el \
+ | mips64vr5000 | mips64vr5000el \
+ | mips64vr5900 | mips64vr5900el \
+ | mipsisa32 | mipsisa32el \
+ | mipsisa32r2 | mipsisa32r2el \
+ | mipsisa32r6 | mipsisa32r6el \
+ | mipsisa64 | mipsisa64el \
+ | mipsisa64r2 | mipsisa64r2el \
+ | mipsisa64r6 | mipsisa64r6el \
+ | mipsisa64sb1 | mipsisa64sb1el \
+ | mipsisa64sr71k | mipsisa64sr71kel \
+ | mipsr5900 | mipsr5900el \
+ | mipstx39 | mipstx39el \
+ | mn10200 | mn10300 \
+ | moxie \
+ | mt \
+ | msp430 \
+ | nds32 | nds32le | nds32be \
+ | nios | nios2 | nios2eb | nios2el \
+ | ns16k | ns32k \
+ | open8 | or1k | or1knd | or32 \
+ | pdp10 | pdp11 | pj | pjl \
+ | powerpc | powerpc64 | powerpc64le | powerpcle \
+ | pyramid \
+ | riscv32 | riscv64 \
+ | rl78 | rx \
+ | score \
+ | sh | sh[1234] | sh[24]a | sh[24]aeb | sh[23]e | sh[34]eb | sheb | shbe | shle | sh[1234]le | sh3ele \
+ | sh64 | sh64le \
+ | sparc | sparc64 | sparc64b | sparc64v | sparc86x | sparclet | sparclite \
+ | sparcv8 | sparcv9 | sparcv9b | sparcv9v \
+ | spu \
+ | tahoe | tic4x | tic54x | tic55x | tic6x | tic80 | tron \
+ | ubicom32 \
+ | v850 | v850e | v850e1 | v850e2 | v850es | v850e2v3 \
+ | we32k \
+ | x86 | xc16x | xstormy16 | xtensa \
+ | z8k | z80)
+ basic_machine=$basic_machine-unknown
+ ;;
+ c54x)
+ basic_machine=tic54x-unknown
+ ;;
+ c55x)
+ basic_machine=tic55x-unknown
+ ;;
+ c6x)
+ basic_machine=tic6x-unknown
+ ;;
+ m6811 | m68hc11 | m6812 | m68hc12 | m68hcs12x | nvptx | picochip)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ m88110 | m680[12346]0 | m683?2 | m68360 | m5200 | v70 | w65 | z8k)
+ ;;
+ ms1)
+ basic_machine=mt-unknown
+ ;;
+
+ strongarm | thumb | xscale)
+ basic_machine=arm-unknown
+ ;;
+ xgate)
+ basic_machine=$basic_machine-unknown
+ os=-none
+ ;;
+ xscaleeb)
+ basic_machine=armeb-unknown
+ ;;
+
+ xscaleel)
+ basic_machine=armel-unknown
+ ;;
+
+ # We use `pc' rather than `unknown'
+ # because (1) that's what they normally are, and
+ # (2) the word "unknown" tends to confuse beginning users.
+ i*86 | x86_64)
+ basic_machine=$basic_machine-pc
+ ;;
+ # Object if more than one company name word.
+ *-*-*)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+ # Recognize the basic CPU types with company name.
+ 580-* \
+ | a29k-* \
+ | aarch64-* | aarch64_be-* \
+ | alpha-* | alphaev[4-8]-* | alphaev56-* | alphaev6[78]-* \
+ | alpha64-* | alpha64ev[4-8]-* | alpha64ev56-* | alpha64ev6[78]-* \
+ | alphapca5[67]-* | alpha64pca5[67]-* | arc-* | arceb-* \
+ | arm-* | armbe-* | armle-* | armeb-* | armv*-* \
+ | avr-* | avr32-* \
+ | be32-* | be64-* \
+ | bfin-* | bs2000-* \
+ | c[123]* | c30-* | [cjt]90-* | c4x-* \
+ | c8051-* | clipper-* | craynv-* | cydra-* \
+ | d10v-* | d30v-* | dlx-* \
+ | elxsi-* \
+ | f30[01]-* | f700-* | fido-* | fr30-* | frv-* | fx80-* \
+ | h8300-* | h8500-* \
+ | hppa-* | hppa1.[01]-* | hppa2.0-* | hppa2.0[nw]-* | hppa64-* \
+ | hexagon-* \
+ | i*86-* | i860-* | i960-* | ia64-* \
+ | ip2k-* | iq2000-* \
+ | k1om-* \
+ | le32-* | le64-* \
+ | lm32-* \
+ | m32c-* | m32r-* | m32rle-* \
+ | m68000-* | m680[012346]0-* | m68360-* | m683?2-* | m68k-* \
+ | m88110-* | m88k-* | maxq-* | mcore-* | metag-* \
+ | microblaze-* | microblazeel-* \
+ | mips-* | mipsbe-* | mipseb-* | mipsel-* | mipsle-* \
+ | mips16-* \
+ | mips64-* | mips64el-* \
+ | mips64octeon-* | mips64octeonel-* \
+ | mips64orion-* | mips64orionel-* \
+ | mips64r5900-* | mips64r5900el-* \
+ | mips64vr-* | mips64vrel-* \
+ | mips64vr4100-* | mips64vr4100el-* \
+ | mips64vr4300-* | mips64vr4300el-* \
+ | mips64vr5000-* | mips64vr5000el-* \
+ | mips64vr5900-* | mips64vr5900el-* \
+ | mipsisa32-* | mipsisa32el-* \
+ | mipsisa32r2-* | mipsisa32r2el-* \
+ | mipsisa32r6-* | mipsisa32r6el-* \
+ | mipsisa64-* | mipsisa64el-* \
+ | mipsisa64r2-* | mipsisa64r2el-* \
+ | mipsisa64r6-* | mipsisa64r6el-* \
+ | mipsisa64sb1-* | mipsisa64sb1el-* \
+ | mipsisa64sr71k-* | mipsisa64sr71kel-* \
+ | mipsr5900-* | mipsr5900el-* \
+ | mipstx39-* | mipstx39el-* \
+ | mmix-* \
+ | mt-* \
+ | msp430-* \
+ | nds32-* | nds32le-* | nds32be-* \
+ | nios-* | nios2-* | nios2eb-* | nios2el-* \
+ | none-* | np1-* | ns16k-* | ns32k-* \
+ | open8-* \
+ | or1k*-* \
+ | orion-* \
+ | pdp10-* | pdp11-* | pj-* | pjl-* | pn-* | power-* \
+ | powerpc-* | powerpc64-* | powerpc64le-* | powerpcle-* \
+ | pyramid-* \
+ | rl78-* | romp-* | rs6000-* | rx-* \
+ | sh-* | sh[1234]-* | sh[24]a-* | sh[24]aeb-* | sh[23]e-* | sh[34]eb-* | sheb-* | shbe-* \
+ | shle-* | sh[1234]le-* | sh3ele-* | sh64-* | sh64le-* \
+ | sparc-* | sparc64-* | sparc64b-* | sparc64v-* | sparc86x-* | sparclet-* \
+ | sparclite-* \
+ | sparcv8-* | sparcv9-* | sparcv9b-* | sparcv9v-* | sv1-* | sx?-* \
+ | tahoe-* \
+ | tic30-* | tic4x-* | tic54x-* | tic55x-* | tic6x-* | tic80-* \
+ | tile*-* \
+ | tron-* \
+ | ubicom32-* \
+ | v850-* | v850e-* | v850e1-* | v850es-* | v850e2-* | v850e2v3-* \
+ | vax-* \
+ | we32k-* \
+ | x86-* | x86_64-* | xc16x-* | xps100-* \
+ | xstormy16-* | xtensa*-* \
+ | ymp-* \
+ | z8k-* | z80-*)
+ ;;
+ # Recognize the basic CPU types without company name, with glob match.
+ xtensa*)
+ basic_machine=$basic_machine-unknown
+ ;;
+ # Recognize the various machine names and aliases which stand
+ # for a CPU type and a company and sometimes even an OS.
+ 386bsd)
+ basic_machine=i386-unknown
+ os=-bsd
+ ;;
+ 3b1 | 7300 | 7300-att | att-7300 | pc7300 | safari | unixpc)
+ basic_machine=m68000-att
+ ;;
+ 3b*)
+ basic_machine=we32k-att
+ ;;
+ a29khif)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ abacus)
+ basic_machine=abacus-unknown
+ ;;
+ adobe68k)
+ basic_machine=m68010-adobe
+ os=-scout
+ ;;
+ alliant | fx80)
+ basic_machine=fx80-alliant
+ ;;
+ altos | altos3068)
+ basic_machine=m68k-altos
+ ;;
+ am29k)
+ basic_machine=a29k-none
+ os=-bsd
+ ;;
+ amd64)
+ basic_machine=x86_64-pc
+ ;;
+ amd64-*)
+ basic_machine=x86_64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ amdahl)
+ basic_machine=580-amdahl
+ os=-sysv
+ ;;
+ amiga | amiga-*)
+ basic_machine=m68k-unknown
+ ;;
+ amigaos | amigados)
+ basic_machine=m68k-unknown
+ os=-amigaos
+ ;;
+ amigaunix | amix)
+ basic_machine=m68k-unknown
+ os=-sysv4
+ ;;
+ apollo68)
+ basic_machine=m68k-apollo
+ os=-sysv
+ ;;
+ apollo68bsd)
+ basic_machine=m68k-apollo
+ os=-bsd
+ ;;
+ aros)
+ basic_machine=i386-pc
+ os=-aros
+ ;;
+ aux)
+ basic_machine=m68k-apple
+ os=-aux
+ ;;
+ balance)
+ basic_machine=ns32k-sequent
+ os=-dynix
+ ;;
+ blackfin)
+ basic_machine=bfin-unknown
+ os=-linux
+ ;;
+ blackfin-*)
+ basic_machine=bfin-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ bluegene*)
+ basic_machine=powerpc-ibm
+ os=-cnk
+ ;;
+ c54x-*)
+ basic_machine=tic54x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c55x-*)
+ basic_machine=tic55x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c6x-*)
+ basic_machine=tic6x-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ c90)
+ basic_machine=c90-cray
+ os=-unicos
+ ;;
+ cegcc)
+ basic_machine=arm-unknown
+ os=-cegcc
+ ;;
+ convex-c1)
+ basic_machine=c1-convex
+ os=-bsd
+ ;;
+ convex-c2)
+ basic_machine=c2-convex
+ os=-bsd
+ ;;
+ convex-c32)
+ basic_machine=c32-convex
+ os=-bsd
+ ;;
+ convex-c34)
+ basic_machine=c34-convex
+ os=-bsd
+ ;;
+ convex-c38)
+ basic_machine=c38-convex
+ os=-bsd
+ ;;
+ cray | j90)
+ basic_machine=j90-cray
+ os=-unicos
+ ;;
+ craynv)
+ basic_machine=craynv-cray
+ os=-unicosmp
+ ;;
+ cr16 | cr16-*)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
+ crds | unos)
+ basic_machine=m68k-crds
+ ;;
+ crisv32 | crisv32-* | etraxfs*)
+ basic_machine=crisv32-axis
+ ;;
+ cris | cris-* | etrax*)
+ basic_machine=cris-axis
+ ;;
+ crx)
+ basic_machine=crx-unknown
+ os=-elf
+ ;;
+ da30 | da30-*)
+ basic_machine=m68k-da30
+ ;;
+ decstation | decstation-3100 | pmax | pmax-* | pmin | dec3100 | decstatn)
+ basic_machine=mips-dec
+ ;;
+ decsystem10* | dec10*)
+ basic_machine=pdp10-dec
+ os=-tops10
+ ;;
+ decsystem20* | dec20*)
+ basic_machine=pdp10-dec
+ os=-tops20
+ ;;
+ delta | 3300 | motorola-3300 | motorola-delta \
+ | 3300-motorola | delta-motorola)
+ basic_machine=m68k-motorola
+ ;;
+ delta88)
+ basic_machine=m88k-motorola
+ os=-sysv3
+ ;;
+ dicos)
+ basic_machine=i686-pc
+ os=-dicos
+ ;;
+ djgpp)
+ basic_machine=i586-pc
+ os=-msdosdjgpp
+ ;;
+ dpx20 | dpx20-*)
+ basic_machine=rs6000-bull
+ os=-bosx
+ ;;
+ dpx2* | dpx2*-bull)
+ basic_machine=m68k-bull
+ os=-sysv3
+ ;;
+ ebmon29k)
+ basic_machine=a29k-amd
+ os=-ebmon
+ ;;
+ elxsi)
+ basic_machine=elxsi-elxsi
+ os=-bsd
+ ;;
+ encore | umax | mmax)
+ basic_machine=ns32k-encore
+ ;;
+ es1800 | OSE68k | ose68k | ose | OSE)
+ basic_machine=m68k-ericsson
+ os=-ose
+ ;;
+ fx2800)
+ basic_machine=i860-alliant
+ ;;
+ genix)
+ basic_machine=ns32k-ns
+ ;;
+ gmicro)
+ basic_machine=tron-gmicro
+ os=-sysv
+ ;;
+ go32)
+ basic_machine=i386-pc
+ os=-go32
+ ;;
+ h3050r* | hiux*)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ h8300hms)
+ basic_machine=h8300-hitachi
+ os=-hms
+ ;;
+ h8300xray)
+ basic_machine=h8300-hitachi
+ os=-xray
+ ;;
+ h8500hms)
+ basic_machine=h8500-hitachi
+ os=-hms
+ ;;
+ harris)
+ basic_machine=m88k-harris
+ os=-sysv3
+ ;;
+ hp300-*)
+ basic_machine=m68k-hp
+ ;;
+ hp300bsd)
+ basic_machine=m68k-hp
+ os=-bsd
+ ;;
+ hp300hpux)
+ basic_machine=m68k-hp
+ os=-hpux
+ ;;
+ hp3k9[0-9][0-9] | hp9[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k2[0-9][0-9] | hp9k31[0-9])
+ basic_machine=m68000-hp
+ ;;
+ hp9k3[2-9][0-9])
+ basic_machine=m68k-hp
+ ;;
+ hp9k6[0-9][0-9] | hp6[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hp9k7[0-79][0-9] | hp7[0-79][0-9])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k78[0-9] | hp78[0-9])
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[67]1 | hp8[67]1 | hp9k80[24] | hp80[24] | hp9k8[78]9 | hp8[78]9 | hp9k893 | hp893)
+ # FIXME: really hppa2.0-hp
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][13679] | hp8[0-9][13679])
+ basic_machine=hppa1.1-hp
+ ;;
+ hp9k8[0-9][0-9] | hp8[0-9][0-9])
+ basic_machine=hppa1.0-hp
+ ;;
+ hppa-next)
+ os=-nextstep3
+ ;;
+ hppaosf)
+ basic_machine=hppa1.1-hp
+ os=-osf
+ ;;
+ hppro)
+ basic_machine=hppa1.1-hp
+ os=-proelf
+ ;;
+ i370-ibm* | ibm*)
+ basic_machine=i370-ibm
+ ;;
+ i*86v32)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv32
+ ;;
+ i*86v4*)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv4
+ ;;
+ i*86v)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-sysv
+ ;;
+ i*86sol2)
+ basic_machine=`echo $1 | sed -e 's/86.*/86-pc/'`
+ os=-solaris2
+ ;;
+ i386mach)
+ basic_machine=i386-mach
+ os=-mach
+ ;;
+ i386-vsta | vsta)
+ basic_machine=i386-unknown
+ os=-vsta
+ ;;
+ iris | iris4d)
+ basic_machine=mips-sgi
+ case $os in
+ -irix*)
+ ;;
+ *)
+ os=-irix4
+ ;;
+ esac
+ ;;
+ isi68 | isi)
+ basic_machine=m68k-isi
+ os=-sysv
+ ;;
+ m68knommu)
+ basic_machine=m68k-unknown
+ os=-linux
+ ;;
+ m68knommu-*)
+ basic_machine=m68k-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ m88k-omron*)
+ basic_machine=m88k-omron
+ ;;
+ magnum | m3230)
+ basic_machine=mips-mips
+ os=-sysv
+ ;;
+ merlin)
+ basic_machine=ns32k-utek
+ os=-sysv
+ ;;
+ microblaze*)
+ basic_machine=microblaze-xilinx
+ ;;
+ mingw64)
+ basic_machine=x86_64-pc
+ os=-mingw64
+ ;;
+ mingw32)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ mingw32ce)
+ basic_machine=arm-unknown
+ os=-mingw32ce
+ ;;
+ miniframe)
+ basic_machine=m68000-convergent
+ ;;
+ *mint | -mint[0-9]* | *MiNT | *MiNT[0-9]*)
+ basic_machine=m68k-atari
+ os=-mint
+ ;;
+ mips3*-*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`
+ ;;
+ mips3*)
+ basic_machine=`echo $basic_machine | sed -e 's/mips3/mips64/'`-unknown
+ ;;
+ monitor)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ morphos)
+ basic_machine=powerpc-unknown
+ os=-morphos
+ ;;
+ moxiebox)
+ basic_machine=moxie-unknown
+ os=-moxiebox
+ ;;
+ msdos)
+ basic_machine=i386-pc
+ os=-msdos
+ ;;
+ ms1-*)
+ basic_machine=`echo $basic_machine | sed -e 's/ms1-/mt-/'`
+ ;;
+ msys)
+ basic_machine=i686-pc
+ os=-msys
+ ;;
+ mvs)
+ basic_machine=i370-ibm
+ os=-mvs
+ ;;
+ nacl)
+ basic_machine=le32-unknown
+ os=-nacl
+ ;;
+ ncr3000)
+ basic_machine=i486-ncr
+ os=-sysv4
+ ;;
+ netbsd386)
+ basic_machine=i386-unknown
+ os=-netbsd
+ ;;
+ netwinder)
+ basic_machine=armv4l-rebel
+ os=-linux
+ ;;
+ news | news700 | news800 | news900)
+ basic_machine=m68k-sony
+ os=-newsos
+ ;;
+ news1000)
+ basic_machine=m68030-sony
+ os=-newsos
+ ;;
+ news-3600 | risc-news)
+ basic_machine=mips-sony
+ os=-newsos
+ ;;
+ necv70)
+ basic_machine=v70-nec
+ os=-sysv
+ ;;
+ next | m*-next )
+ basic_machine=m68k-next
+ case $os in
+ -nextstep* )
+ ;;
+ -ns2*)
+ os=-nextstep2
+ ;;
+ *)
+ os=-nextstep3
+ ;;
+ esac
+ ;;
+ nh3000)
+ basic_machine=m68k-harris
+ os=-cxux
+ ;;
+ nh[45]000)
+ basic_machine=m88k-harris
+ os=-cxux
+ ;;
+ nindy960)
+ basic_machine=i960-intel
+ os=-nindy
+ ;;
+ mon960)
+ basic_machine=i960-intel
+ os=-mon960
+ ;;
+ nonstopux)
+ basic_machine=mips-compaq
+ os=-nonstopux
+ ;;
+ np1)
+ basic_machine=np1-gould
+ ;;
+ neo-tandem)
+ basic_machine=neo-tandem
+ ;;
+ nse-tandem)
+ basic_machine=nse-tandem
+ ;;
+ nsr-tandem)
+ basic_machine=nsr-tandem
+ ;;
+ op50n-* | op60c-*)
+ basic_machine=hppa1.1-oki
+ os=-proelf
+ ;;
+ openrisc | openrisc-*)
+ basic_machine=or32-unknown
+ ;;
+ os400)
+ basic_machine=powerpc-ibm
+ os=-os400
+ ;;
+ OSE68000 | ose68000)
+ basic_machine=m68000-ericsson
+ os=-ose
+ ;;
+ os68k)
+ basic_machine=m68k-none
+ os=-os68k
+ ;;
+ pa-hitachi)
+ basic_machine=hppa1.1-hitachi
+ os=-hiuxwe2
+ ;;
+ paragon)
+ basic_machine=i860-intel
+ os=-osf
+ ;;
+ parisc)
+ basic_machine=hppa-unknown
+ os=-linux
+ ;;
+ parisc-*)
+ basic_machine=hppa-`echo $basic_machine | sed 's/^[^-]*-//'`
+ os=-linux
+ ;;
+ pbd)
+ basic_machine=sparc-tti
+ ;;
+ pbb)
+ basic_machine=m68k-tti
+ ;;
+ pc532 | pc532-*)
+ basic_machine=ns32k-pc532
+ ;;
+ pc98)
+ basic_machine=i386-pc
+ ;;
+ pc98-*)
+ basic_machine=i386-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium | p5 | k5 | k6 | nexgen | viac3)
+ basic_machine=i586-pc
+ ;;
+ pentiumpro | p6 | 6x86 | athlon | athlon_*)
+ basic_machine=i686-pc
+ ;;
+ pentiumii | pentium2 | pentiumiii | pentium3)
+ basic_machine=i686-pc
+ ;;
+ pentium4)
+ basic_machine=i786-pc
+ ;;
+ pentium-* | p5-* | k5-* | k6-* | nexgen-* | viac3-*)
+ basic_machine=i586-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumpro-* | p6-* | 6x86-* | athlon-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentiumii-* | pentium2-* | pentiumiii-* | pentium3-*)
+ basic_machine=i686-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pentium4-*)
+ basic_machine=i786-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ pn)
+ basic_machine=pn-gould
+ ;;
+ power) basic_machine=power-ibm
+ ;;
+ ppc | ppcbe) basic_machine=powerpc-unknown
+ ;;
+ ppc-* | ppcbe-*)
+ basic_machine=powerpc-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppcle | powerpclittle | ppc-le | powerpc-little)
+ basic_machine=powerpcle-unknown
+ ;;
+ ppcle-* | powerpclittle-*)
+ basic_machine=powerpcle-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64) basic_machine=powerpc64-unknown
+ ;;
+ ppc64-*) basic_machine=powerpc64-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ppc64le | powerpc64little | ppc64-le | powerpc64-little)
+ basic_machine=powerpc64le-unknown
+ ;;
+ ppc64le-* | powerpc64little-*)
+ basic_machine=powerpc64le-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ ps2)
+ basic_machine=i386-ibm
+ ;;
+ pw32)
+ basic_machine=i586-unknown
+ os=-pw32
+ ;;
+ rdos | rdos64)
+ basic_machine=x86_64-pc
+ os=-rdos
+ ;;
+ rdos32)
+ basic_machine=i386-pc
+ os=-rdos
+ ;;
+ rom68k)
+ basic_machine=m68k-rom68k
+ os=-coff
+ ;;
+ rm[46]00)
+ basic_machine=mips-siemens
+ ;;
+ rtpc | rtpc-*)
+ basic_machine=romp-ibm
+ ;;
+ s390 | s390-*)
+ basic_machine=s390-ibm
+ ;;
+ s390x | s390x-*)
+ basic_machine=s390x-ibm
+ ;;
+ sa29200)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ sb1)
+ basic_machine=mipsisa64sb1-unknown
+ ;;
+ sb1el)
+ basic_machine=mipsisa64sb1el-unknown
+ ;;
+ sde)
+ basic_machine=mipsisa32-sde
+ os=-elf
+ ;;
+ sei)
+ basic_machine=mips-sei
+ os=-seiux
+ ;;
+ sequent)
+ basic_machine=i386-sequent
+ ;;
+ sh)
+ basic_machine=sh-hitachi
+ os=-hms
+ ;;
+ sh5el)
+ basic_machine=sh5le-unknown
+ ;;
+ sh64)
+ basic_machine=sh64-unknown
+ ;;
+ sparclite-wrs | simso-wrs)
+ basic_machine=sparclite-wrs
+ os=-vxworks
+ ;;
+ sps7)
+ basic_machine=m68k-bull
+ os=-sysv2
+ ;;
+ spur)
+ basic_machine=spur-unknown
+ ;;
+ st2000)
+ basic_machine=m68k-tandem
+ ;;
+ stratus)
+ basic_machine=i860-stratus
+ os=-sysv4
+ ;;
+ strongarm-* | thumb-*)
+ basic_machine=arm-`echo $basic_machine | sed 's/^[^-]*-//'`
+ ;;
+ sun2)
+ basic_machine=m68000-sun
+ ;;
+ sun2os3)
+ basic_machine=m68000-sun
+ os=-sunos3
+ ;;
+ sun2os4)
+ basic_machine=m68000-sun
+ os=-sunos4
+ ;;
+ sun3os3)
+ basic_machine=m68k-sun
+ os=-sunos3
+ ;;
+ sun3os4)
+ basic_machine=m68k-sun
+ os=-sunos4
+ ;;
+ sun4os3)
+ basic_machine=sparc-sun
+ os=-sunos3
+ ;;
+ sun4os4)
+ basic_machine=sparc-sun
+ os=-sunos4
+ ;;
+ sun4sol2)
+ basic_machine=sparc-sun
+ os=-solaris2
+ ;;
+ sun3 | sun3-*)
+ basic_machine=m68k-sun
+ ;;
+ sun4)
+ basic_machine=sparc-sun
+ ;;
+ sun386 | sun386i | roadrunner)
+ basic_machine=i386-sun
+ ;;
+ sv1)
+ basic_machine=sv1-cray
+ os=-unicos
+ ;;
+ symmetry)
+ basic_machine=i386-sequent
+ os=-dynix
+ ;;
+ t3e)
+ basic_machine=alphaev5-cray
+ os=-unicos
+ ;;
+ t90)
+ basic_machine=t90-cray
+ os=-unicos
+ ;;
+ tile*)
+ basic_machine=$basic_machine-unknown
+ os=-linux-gnu
+ ;;
+ tx39)
+ basic_machine=mipstx39-unknown
+ ;;
+ tx39el)
+ basic_machine=mipstx39el-unknown
+ ;;
+ toad1)
+ basic_machine=pdp10-xkl
+ os=-tops20
+ ;;
+ tower | tower-32)
+ basic_machine=m68k-ncr
+ ;;
+ tpf)
+ basic_machine=s390x-ibm
+ os=-tpf
+ ;;
+ udi29k)
+ basic_machine=a29k-amd
+ os=-udi
+ ;;
+ ultra3)
+ basic_machine=a29k-nyu
+ os=-sym1
+ ;;
+ v810 | necv810)
+ basic_machine=v810-nec
+ os=-none
+ ;;
+ vaxv)
+ basic_machine=vax-dec
+ os=-sysv
+ ;;
+ vms)
+ basic_machine=vax-dec
+ os=-vms
+ ;;
+ vpp*|vx|vx-*)
+ basic_machine=f301-fujitsu
+ ;;
+ vxworks960)
+ basic_machine=i960-wrs
+ os=-vxworks
+ ;;
+ vxworks68)
+ basic_machine=m68k-wrs
+ os=-vxworks
+ ;;
+ vxworks29k)
+ basic_machine=a29k-wrs
+ os=-vxworks
+ ;;
+ w65*)
+ basic_machine=w65-wdc
+ os=-none
+ ;;
+ w89k-*)
+ basic_machine=hppa1.1-winbond
+ os=-proelf
+ ;;
+ xbox)
+ basic_machine=i686-pc
+ os=-mingw32
+ ;;
+ xps | xps100)
+ basic_machine=xps100-honeywell
+ ;;
+ xscale-* | xscalee[bl]-*)
+ basic_machine=`echo $basic_machine | sed 's/^xscale/arm/'`
+ ;;
+ ymp)
+ basic_machine=ymp-cray
+ os=-unicos
+ ;;
+ z8k-*-coff)
+ basic_machine=z8k-unknown
+ os=-sim
+ ;;
+ z80-*-coff)
+ basic_machine=z80-unknown
+ os=-sim
+ ;;
+ none)
+ basic_machine=none-none
+ os=-none
+ ;;
+
+# Here we handle the default manufacturer of certain CPU types. It is in
+# some cases the only manufacturer, in others, it is the most popular.
+ w89k)
+ basic_machine=hppa1.1-winbond
+ ;;
+ op50n)
+ basic_machine=hppa1.1-oki
+ ;;
+ op60c)
+ basic_machine=hppa1.1-oki
+ ;;
+ romp)
+ basic_machine=romp-ibm
+ ;;
+ mmix)
+ basic_machine=mmix-knuth
+ ;;
+ rs6000)
+ basic_machine=rs6000-ibm
+ ;;
+ vax)
+ basic_machine=vax-dec
+ ;;
+ pdp10)
+ # there are many clones, so DEC is not a safe bet
+ basic_machine=pdp10-unknown
+ ;;
+ pdp11)
+ basic_machine=pdp11-dec
+ ;;
+ we32k)
+ basic_machine=we32k-att
+ ;;
+ sh[1234] | sh[24]a | sh[24]aeb | sh[34]eb | sh[1234]le | sh[23]ele)
+ basic_machine=sh-unknown
+ ;;
+ sparc | sparcv8 | sparcv9 | sparcv9b | sparcv9v)
+ basic_machine=sparc-sun
+ ;;
+ cydra)
+ basic_machine=cydra-cydrome
+ ;;
+ orion)
+ basic_machine=orion-highlevel
+ ;;
+ orion105)
+ basic_machine=clipper-highlevel
+ ;;
+ mac | mpw | mac-mpw)
+ basic_machine=m68k-apple
+ ;;
+ pmac | pmac-mpw)
+ basic_machine=powerpc-apple
+ ;;
+ *-unknown)
+ # Make sure to match an already-canonicalized machine name.
+ ;;
+ *)
+ echo Invalid configuration \`$1\': machine \`$basic_machine\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+
+# Here we canonicalize certain aliases for manufacturers.
+case $basic_machine in
+ *-digital*)
+ basic_machine=`echo $basic_machine | sed 's/digital.*/dec/'`
+ ;;
+ *-commodore*)
+ basic_machine=`echo $basic_machine | sed 's/commodore.*/cbm/'`
+ ;;
+ *)
+ ;;
+esac
+
+# Decode manufacturer-specific aliases for certain operating systems.
+
+if [ x"$os" != x"" ]
+then
+case $os in
+ # First match some system type aliases
+ # that might get confused with valid system types.
+ # -solaris* is a basic system type, with this one exception.
+ -auroraux)
+ os=-auroraux
+ ;;
+ -solaris1 | -solaris1.*)
+ os=`echo $os | sed -e 's|solaris1|sunos4|'`
+ ;;
+ -solaris)
+ os=-solaris2
+ ;;
+ -svr4*)
+ os=-sysv4
+ ;;
+ -unixware*)
+ os=-sysv4.2uw
+ ;;
+ -gnu/linux*)
+ os=`echo $os | sed -e 's|gnu/linux|linux-gnu|'`
+ ;;
+ # First accept the basic system types.
+ # The portable systems comes first.
+ # Each alternative MUST END IN A *, to match a version number.
+ # -sysv* is not here because it comes later, after sysvr4.
+ -gnu* | -bsd* | -mach* | -minix* | -genix* | -ultrix* | -irix* \
+ | -*vms* | -sco* | -esix* | -isc* | -aix* | -cnk* | -sunos | -sunos[34]*\
+ | -hpux* | -unos* | -osf* | -luna* | -dgux* | -auroraux* | -solaris* \
+ | -sym* | -kopensolaris* | -plan9* \
+ | -amigaos* | -amigados* | -msdos* | -newsos* | -unicos* | -aof* \
+ | -aos* | -aros* \
+ | -nindy* | -vxsim* | -vxworks* | -ebmon* | -hms* | -mvs* \
+ | -clix* | -riscos* | -uniplus* | -iris* | -rtu* | -xenix* \
+ | -hiux* | -386bsd* | -knetbsd* | -mirbsd* | -netbsd* \
+ | -bitrig* | -openbsd* | -solidbsd* \
+ | -ekkobsd* | -kfreebsd* | -freebsd* | -riscix* | -lynxos* \
+ | -bosx* | -nextstep* | -cxux* | -aout* | -elf* | -oabi* \
+ | -ptx* | -coff* | -ecoff* | -winnt* | -domain* | -vsta* \
+ | -udi* | -eabi* | -lites* | -ieee* | -go32* | -aux* \
+ | -chorusos* | -chorusrdb* | -cegcc* \
+ | -cygwin* | -msys* | -pe* | -psos* | -moss* | -proelf* | -rtems* \
+ | -mingw32* | -mingw64* | -linux-gnu* | -linux-android* \
+ | -linux-newlib* | -linux-musl* | -linux-uclibc* \
+ | -uxpv* | -beos* | -mpeix* | -udk* | -moxiebox* \
+ | -interix* | -uwin* | -mks* | -rhapsody* | -darwin* | -opened* \
+ | -openstep* | -oskit* | -conix* | -pw32* | -nonstopux* \
+ | -storm-chaos* | -tops10* | -tenex* | -tops20* | -its* \
+ | -os2* | -vos* | -palmos* | -uclinux* | -nucleus* \
+ | -morphos* | -superux* | -rtmk* | -rtmk-nova* | -windiss* \
+ | -powermax* | -dnix* | -nx6 | -nx7 | -sei* | -dragonfly* \
+ | -skyos* | -haiku* | -rdos* | -toppers* | -drops* | -es* | -tirtos*)
+ # Remember, each alternative MUST END IN *, to match a version number.
+ ;;
+ -qnx*)
+ case $basic_machine in
+ x86-* | i*86-*)
+ ;;
+ *)
+ os=-nto$os
+ ;;
+ esac
+ ;;
+ -nto-qnx*)
+ ;;
+ -nto*)
+ os=`echo $os | sed -e 's|nto|nto-qnx|'`
+ ;;
+ -sim | -es1800* | -hms* | -xray | -os68k* | -none* | -v88r* \
+ | -windows* | -osx | -abug | -netware* | -os9* | -beos* | -haiku* \
+ | -macos* | -mpw* | -magic* | -mmixware* | -mon960* | -lnews*)
+ ;;
+ -mac*)
+ os=`echo $os | sed -e 's|mac|macos|'`
+ ;;
+ -linux-dietlibc)
+ os=-linux-dietlibc
+ ;;
+ -linux*)
+ os=`echo $os | sed -e 's|linux|linux-gnu|'`
+ ;;
+ -sunos5*)
+ os=`echo $os | sed -e 's|sunos5|solaris2|'`
+ ;;
+ -sunos6*)
+ os=`echo $os | sed -e 's|sunos6|solaris3|'`
+ ;;
+ -opened*)
+ os=-openedition
+ ;;
+ -os400*)
+ os=-os400
+ ;;
+ -wince*)
+ os=-wince
+ ;;
+ -osfrose*)
+ os=-osfrose
+ ;;
+ -osf*)
+ os=-osf
+ ;;
+ -utek*)
+ os=-bsd
+ ;;
+ -dynix*)
+ os=-bsd
+ ;;
+ -acis*)
+ os=-aos
+ ;;
+ -atheos*)
+ os=-atheos
+ ;;
+ -syllable*)
+ os=-syllable
+ ;;
+ -386bsd)
+ os=-bsd
+ ;;
+ -ctix* | -uts*)
+ os=-sysv
+ ;;
+ -nova*)
+ os=-rtmk-nova
+ ;;
+ -ns2 )
+ os=-nextstep2
+ ;;
+ -nsk*)
+ os=-nsk
+ ;;
+ # Preserve the version number of sinix5.
+ -sinix5.*)
+ os=`echo $os | sed -e 's|sinix|sysv|'`
+ ;;
+ -sinix*)
+ os=-sysv4
+ ;;
+ -tpf*)
+ os=-tpf
+ ;;
+ -triton*)
+ os=-sysv3
+ ;;
+ -oss*)
+ os=-sysv3
+ ;;
+ -svr4)
+ os=-sysv4
+ ;;
+ -svr3)
+ os=-sysv3
+ ;;
+ -sysvr4)
+ os=-sysv4
+ ;;
+ # This must come after -sysvr4.
+ -sysv*)
+ ;;
+ -ose*)
+ os=-ose
+ ;;
+ -es1800*)
+ os=-ose
+ ;;
+ -xenix)
+ os=-xenix
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ os=-mint
+ ;;
+ -aros*)
+ os=-aros
+ ;;
+ -zvmoe)
+ os=-zvmoe
+ ;;
+ -dicos*)
+ os=-dicos
+ ;;
+ -nacl*)
+ ;;
+ -none)
+ ;;
+ *)
+ # Get rid of the `-' at the beginning of $os.
+ os=`echo $os | sed 's/[^-]*-//'`
+ echo Invalid configuration \`$1\': system \`$os\' not recognized 1>&2
+ exit 1
+ ;;
+esac
+else
+
+# Here we handle the default operating systems that come with various machines.
+# The value should be what the vendor currently ships out the door with their
+# machine or put another way, the most popular os provided with the machine.
+
+# Note that if you're going to try to match "-MANUFACTURER" here (say,
+# "-sun"), then you have to tell the case statement up towards the top
+# that MANUFACTURER isn't an operating system. Otherwise, code above
+# will signal an error saying that MANUFACTURER isn't an operating
+# system, and we'll never get to this point.
+
+case $basic_machine in
+ score-*)
+ os=-elf
+ ;;
+ spu-*)
+ os=-elf
+ ;;
+ *-acorn)
+ os=-riscix1.2
+ ;;
+ arm*-rebel)
+ os=-linux
+ ;;
+ arm*-semi)
+ os=-aout
+ ;;
+ c4x-* | tic4x-*)
+ os=-coff
+ ;;
+ c8051-*)
+ os=-elf
+ ;;
+ hexagon-*)
+ os=-elf
+ ;;
+ tic54x-*)
+ os=-coff
+ ;;
+ tic55x-*)
+ os=-coff
+ ;;
+ tic6x-*)
+ os=-coff
+ ;;
+ # This must come before the *-dec entry.
+ pdp10-*)
+ os=-tops20
+ ;;
+ pdp11-*)
+ os=-none
+ ;;
+ *-dec | vax-*)
+ os=-ultrix4.2
+ ;;
+ m68*-apollo)
+ os=-domain
+ ;;
+ i386-sun)
+ os=-sunos4.0.2
+ ;;
+ m68000-sun)
+ os=-sunos3
+ ;;
+ m68*-cisco)
+ os=-aout
+ ;;
+ mep-*)
+ os=-elf
+ ;;
+ mips*-cisco)
+ os=-elf
+ ;;
+ mips*-*)
+ os=-elf
+ ;;
+ or32-*)
+ os=-coff
+ ;;
+ *-tti) # must be before sparc entry or we get the wrong os.
+ os=-sysv3
+ ;;
+ sparc-* | *-sun)
+ os=-sunos4.1.1
+ ;;
+ *-be)
+ os=-beos
+ ;;
+ *-haiku)
+ os=-haiku
+ ;;
+ *-ibm)
+ os=-aix
+ ;;
+ *-knuth)
+ os=-mmixware
+ ;;
+ *-wec)
+ os=-proelf
+ ;;
+ *-winbond)
+ os=-proelf
+ ;;
+ *-oki)
+ os=-proelf
+ ;;
+ *-hp)
+ os=-hpux
+ ;;
+ *-hitachi)
+ os=-hiux
+ ;;
+ i860-* | *-att | *-ncr | *-altos | *-motorola | *-convergent)
+ os=-sysv
+ ;;
+ *-cbm)
+ os=-amigaos
+ ;;
+ *-dg)
+ os=-dgux
+ ;;
+ *-dolphin)
+ os=-sysv3
+ ;;
+ m68k-ccur)
+ os=-rtu
+ ;;
+ m88k-omron*)
+ os=-luna
+ ;;
+ *-next )
+ os=-nextstep
+ ;;
+ *-sequent)
+ os=-ptx
+ ;;
+ *-crds)
+ os=-unos
+ ;;
+ *-ns)
+ os=-genix
+ ;;
+ i370-*)
+ os=-mvs
+ ;;
+ *-next)
+ os=-nextstep3
+ ;;
+ *-gould)
+ os=-sysv
+ ;;
+ *-highlevel)
+ os=-bsd
+ ;;
+ *-encore)
+ os=-bsd
+ ;;
+ *-sgi)
+ os=-irix
+ ;;
+ *-siemens)
+ os=-sysv4
+ ;;
+ *-masscomp)
+ os=-rtu
+ ;;
+ f30[01]-fujitsu | f700-fujitsu)
+ os=-uxpv
+ ;;
+ *-rom68k)
+ os=-coff
+ ;;
+ *-*bug)
+ os=-coff
+ ;;
+ *-apple)
+ os=-macos
+ ;;
+ *-atari*)
+ os=-mint
+ ;;
+ *)
+ os=-none
+ ;;
+esac
+fi
+
+# Here we handle the case where we know the os, and the CPU type, but not the
+# manufacturer. We pick the logical manufacturer.
+vendor=unknown
+case $basic_machine in
+ *-unknown)
+ case $os in
+ -riscix*)
+ vendor=acorn
+ ;;
+ -sunos*)
+ vendor=sun
+ ;;
+ -cnk*|-aix*)
+ vendor=ibm
+ ;;
+ -beos*)
+ vendor=be
+ ;;
+ -hpux*)
+ vendor=hp
+ ;;
+ -mpeix*)
+ vendor=hp
+ ;;
+ -hiux*)
+ vendor=hitachi
+ ;;
+ -unos*)
+ vendor=crds
+ ;;
+ -dgux*)
+ vendor=dg
+ ;;
+ -luna*)
+ vendor=omron
+ ;;
+ -genix*)
+ vendor=ns
+ ;;
+ -mvs* | -opened*)
+ vendor=ibm
+ ;;
+ -os400*)
+ vendor=ibm
+ ;;
+ -ptx*)
+ vendor=sequent
+ ;;
+ -tpf*)
+ vendor=ibm
+ ;;
+ -vxsim* | -vxworks* | -windiss*)
+ vendor=wrs
+ ;;
+ -aux*)
+ vendor=apple
+ ;;
+ -hms*)
+ vendor=hitachi
+ ;;
+ -mpw* | -macos*)
+ vendor=apple
+ ;;
+ -*mint | -mint[0-9]* | -*MiNT | -MiNT[0-9]*)
+ vendor=atari
+ ;;
+ -vos*)
+ vendor=stratus
+ ;;
+ esac
+ basic_machine=`echo $basic_machine | sed "s/unknown/$vendor/"`
+ ;;
+esac
+
+echo $basic_machine$os
+exit
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "timestamp='"
+# time-stamp-format: "%:y-%02m-%02d"
+# time-stamp-end: "'"
+# End:
--- /dev/null
+#! /bin/sh
+# depcomp - compile a program generating dependencies as side-effects
+
+scriptversion=2013-05-30.07; # UTC
+
+# Copyright (C) 1999-2013 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# Originally written by Alexandre Oliva <oliva@dcc.unicamp.br>.
+
+case $1 in
+ '')
+ echo "$0: No command. Try '$0 --help' for more information." 1>&2
+ exit 1;
+ ;;
+ -h | --h*)
+ cat <<\EOF
+Usage: depcomp [--help] [--version] PROGRAM [ARGS]
+
+Run PROGRAMS ARGS to compile a file, generating dependencies
+as side-effects.
+
+Environment variables:
+ depmode Dependency tracking mode.
+ source Source file read by 'PROGRAMS ARGS'.
+ object Object file output by 'PROGRAMS ARGS'.
+ DEPDIR directory where to store dependencies.
+ depfile Dependency file to output.
+ tmpdepfile Temporary file to use when outputting dependencies.
+ libtool Whether libtool is used (yes/no).
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v | --v*)
+ echo "depcomp $scriptversion"
+ exit $?
+ ;;
+esac
+
+# Get the directory component of the given path, and save it in the
+# global variables '$dir'. Note that this directory component will
+# be either empty or ending with a '/' character. This is deliberate.
+set_dir_from ()
+{
+ case $1 in
+ */*) dir=`echo "$1" | sed -e 's|/[^/]*$|/|'`;;
+ *) dir=;;
+ esac
+}
+
+# Get the suffix-stripped basename of the given path, and save it the
+# global variable '$base'.
+set_base_from ()
+{
+ base=`echo "$1" | sed -e 's|^.*/||' -e 's/\.[^.]*$//'`
+}
+
+# If no dependency file was actually created by the compiler invocation,
+# we still have to create a dummy depfile, to avoid errors with the
+# Makefile "include basename.Plo" scheme.
+make_dummy_depfile ()
+{
+ echo "#dummy" > "$depfile"
+}
+
+# Factor out some common post-processing of the generated depfile.
+# Requires the auxiliary global variable '$tmpdepfile' to be set.
+aix_post_process_depfile ()
+{
+ # If the compiler actually managed to produce a dependency file,
+ # post-process it.
+ if test -f "$tmpdepfile"; then
+ # Each line is of the form 'foo.o: dependency.h'.
+ # Do two passes, one to just change these to
+ # $object: dependency.h
+ # and one to simply output
+ # dependency.h:
+ # which is needed to avoid the deleted-header problem.
+ { sed -e "s,^.*\.[$lower]*:,$object:," < "$tmpdepfile"
+ sed -e "s,^.*\.[$lower]*:[$tab ]*,," -e 's,$,:,' < "$tmpdepfile"
+ } > "$depfile"
+ rm -f "$tmpdepfile"
+ else
+ make_dummy_depfile
+ fi
+}
+
+# A tabulation character.
+tab=' '
+# A newline character.
+nl='
+'
+# Character ranges might be problematic outside the C locale.
+# These definitions help.
+upper=ABCDEFGHIJKLMNOPQRSTUVWXYZ
+lower=abcdefghijklmnopqrstuvwxyz
+digits=0123456789
+alpha=${upper}${lower}
+
+if test -z "$depmode" || test -z "$source" || test -z "$object"; then
+ echo "depcomp: Variables source, object and depmode must be set" 1>&2
+ exit 1
+fi
+
+# Dependencies for sub/bar.o or sub/bar.obj go into sub/.deps/bar.Po.
+depfile=${depfile-`echo "$object" |
+ sed 's|[^\\/]*$|'${DEPDIR-.deps}'/&|;s|\.\([^.]*\)$|.P\1|;s|Pobj$|Po|'`}
+tmpdepfile=${tmpdepfile-`echo "$depfile" | sed 's/\.\([^.]*\)$/.T\1/'`}
+
+rm -f "$tmpdepfile"
+
+# Avoid interferences from the environment.
+gccflag= dashmflag=
+
+# Some modes work just like other modes, but use different flags. We
+# parameterize here, but still list the modes in the big case below,
+# to make depend.m4 easier to write. Note that we *cannot* use a case
+# here, because this file can only contain one case statement.
+if test "$depmode" = hp; then
+ # HP compiler uses -M and no extra arg.
+ gccflag=-M
+ depmode=gcc
+fi
+
+if test "$depmode" = dashXmstdout; then
+ # This is just like dashmstdout with a different argument.
+ dashmflag=-xM
+ depmode=dashmstdout
+fi
+
+cygpath_u="cygpath -u -f -"
+if test "$depmode" = msvcmsys; then
+ # This is just like msvisualcpp but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvisualcpp
+fi
+
+if test "$depmode" = msvc7msys; then
+ # This is just like msvc7 but w/o cygpath translation.
+ # Just convert the backslash-escaped backslashes to single forward
+ # slashes to satisfy depend.m4
+ cygpath_u='sed s,\\\\,/,g'
+ depmode=msvc7
+fi
+
+if test "$depmode" = xlc; then
+ # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency information.
+ gccflag=-qmakedep=gcc,-MF
+ depmode=gcc
+fi
+
+case "$depmode" in
+gcc3)
+## gcc 3 implements dependency tracking that does exactly what
+## we want. Yay! Note: for some reason libtool 1.4 doesn't like
+## it if -MD -MP comes after the -MF stuff. Hmm.
+## Unfortunately, FreeBSD c89 acceptance of flags depends upon
+## the command line argument order; so add the flags where they
+## appear in depend2.am. Note that the slowdown incurred here
+## affects only configure: in makefiles, %FASTDEP% shortcuts this.
+ for arg
+ do
+ case $arg in
+ -c) set fnord "$@" -MT "$object" -MD -MP -MF "$tmpdepfile" "$arg" ;;
+ *) set fnord "$@" "$arg" ;;
+ esac
+ shift # fnord
+ shift # $arg
+ done
+ "$@"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ mv "$tmpdepfile" "$depfile"
+ ;;
+
+gcc)
+## Note that this doesn't just cater to obsosete pre-3.x GCC compilers.
+## but also to in-use compilers like IMB xlc/xlC and the HP C compiler.
+## (see the conditional assignment to $gccflag above).
+## There are various ways to get dependency output from gcc. Here's
+## why we pick this rather obscure method:
+## - Don't want to use -MD because we'd like the dependencies to end
+## up in a subdir. Having to rename by hand is ugly.
+## (We might end up doing this anyway to support other compilers.)
+## - The DEPENDENCIES_OUTPUT environment variable makes gcc act like
+## -MM, not -M (despite what the docs say). Also, it might not be
+## supported by the other compilers which use the 'gcc' depmode.
+## - Using -M directly means running the compiler twice (even worse
+## than renaming).
+ if test -z "$gccflag"; then
+ gccflag=-MD,
+ fi
+ "$@" -Wp,"$gccflag$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The second -e expression handles DOS-style file names with drive
+ # letters.
+ sed -e 's/^[^:]*: / /' \
+ -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
+## This next piece of magic avoids the "deleted header file" problem.
+## The problem is that when a header file which appears in a .P file
+## is deleted, the dependency causes make to die (because there is
+## typically no way to rebuild the header). We avoid this by adding
+## dummy dependencies for each header file. Too bad gcc doesn't do
+## this for us directly.
+## Some versions of gcc put a space before the ':'. On the theory
+## that the space means something, we add a space to the output as
+## well. hp depmode also adds that space, but also prefixes the VPATH
+## to the object. Take care to not repeat it in the output.
+## Some versions of the HPUX 10.20 sed can't process this invocation
+## correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e "s|.*$object$||" -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+sgi)
+ if test "$libtool" = yes; then
+ "$@" "-Wp,-MDupdate,$tmpdepfile"
+ else
+ "$@" -MDupdate "$tmpdepfile"
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+
+ if test -f "$tmpdepfile"; then # yes, the sourcefile depend on other files
+ echo "$object : \\" > "$depfile"
+ # Clip off the initial element (the dependent). Don't try to be
+ # clever and replace this with sed code, as IRIX sed won't handle
+ # lines with more than a fixed number of characters (4096 in
+ # IRIX 6.2 sed, 8192 in IRIX 6.5). We also remove comment lines;
+ # the IRIX cc adds comments like '#:fec' to the end of the
+ # dependency line.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' \
+ | tr "$nl" ' ' >> "$depfile"
+ echo >> "$depfile"
+ # The second pass generates a dummy entry for each header file.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
+ >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile"
+ ;;
+
+xlc)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+aix)
+ # The C for AIX Compiler uses -M and outputs the dependencies
+ # in a .u file. In older versions, this file always lives in the
+ # current directory. Also, the AIX compiler puts '$object:' at the
+ # start of each line; $object doesn't have directory information.
+ # Version 6 uses the directory in both cases.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$base.u
+ tmpdepfile3=$dir.libs/$base.u
+ "$@" -Wc,-M
+ else
+ tmpdepfile1=$dir$base.u
+ tmpdepfile2=$dir$base.u
+ tmpdepfile3=$dir$base.u
+ "$@" -M
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ aix_post_process_depfile
+ ;;
+
+tcc)
+ # tcc (Tiny C Compiler) understand '-MD -MF file' since version 0.9.26
+ # FIXME: That version still under development at the moment of writing.
+ # Make that this statement remains true also for stable, released
+ # versions.
+ # It will wrap lines (doesn't matter whether long or short) with a
+ # trailing '\', as in:
+ #
+ # foo.o : \
+ # foo.c \
+ # foo.h \
+ #
+ # It will put a trailing '\' even on the last line, and will use leading
+ # spaces rather than leading tabs (at least since its commit 0394caf7
+ # "Emit spaces for -MD").
+ "$@" -MD -MF "$tmpdepfile"
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each non-empty line is of the form 'foo.o : \' or ' dep.h \'.
+ # We have to change lines of the first kind to '$object: \'.
+ sed -e "s|.*:|$object :|" < "$tmpdepfile" > "$depfile"
+ # And for each line of the second kind, we have to emit a 'dep.h:'
+ # dummy dependency, to avoid the deleted-header problem.
+ sed -n -e 's|^ *\(.*\) *\\$|\1:|p' < "$tmpdepfile" >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+## The order of this option in the case statement is important, since the
+## shell code in configure will try each of these formats in the order
+## listed in this file. A plain '-MD' option would be understood by many
+## compilers, so we must ensure this comes after the gcc and icc options.
+pgcc)
+ # Portland's C compiler understands '-MD'.
+ # Will always output deps to 'file.d' where file is the root name of the
+ # source file under compilation, even if file resides in a subdirectory.
+ # The object file name does not affect the name of the '.d' file.
+ # pgcc 10.2 will output
+ # foo.o: sub/foo.c sub/foo.h
+ # and will wrap long lines using '\' :
+ # foo.o: sub/foo.c ... \
+ # sub/foo.h ... \
+ # ...
+ set_dir_from "$object"
+ # Use the source, not the object, to determine the base name, since
+ # that's sadly what pgcc will do too.
+ set_base_from "$source"
+ tmpdepfile=$base.d
+
+ # For projects that build the same source file twice into different object
+ # files, the pgcc approach of using the *source* file root name can cause
+ # problems in parallel builds. Use a locking strategy to avoid stomping on
+ # the same $tmpdepfile.
+ lockdir=$base.d-lock
+ trap "
+ echo '$0: caught signal, cleaning up...' >&2
+ rmdir '$lockdir'
+ exit 1
+ " 1 2 13 15
+ numtries=100
+ i=$numtries
+ while test $i -gt 0; do
+ # mkdir is a portable test-and-set.
+ if mkdir "$lockdir" 2>/dev/null; then
+ # This process acquired the lock.
+ "$@" -MD
+ stat=$?
+ # Release the lock.
+ rmdir "$lockdir"
+ break
+ else
+ # If the lock is being held by a different process, wait
+ # until the winning process is done or we timeout.
+ while test -d "$lockdir" && test $i -gt 0; do
+ sleep 1
+ i=`expr $i - 1`
+ done
+ fi
+ i=`expr $i - 1`
+ done
+ trap - 1 2 13 15
+ if test $i -le 0; then
+ echo "$0: failed to acquire lock after $numtries attempts" >&2
+ echo "$0: check lockdir '$lockdir'" >&2
+ exit 1
+ fi
+
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ # Each line is of the form `foo.o: dependent.h',
+ # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+ # Do two passes, one to just change these to
+ # `$object: dependent.h' and one to simply `dependent.h:'.
+ sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+hp2)
+ # The "hp" stanza above does not work with aCC (C++) and HP's ia64
+ # compilers, which have integrated preprocessors. The correct option
+ # to use with these is +Maked; it writes dependencies to a file named
+ # 'foo.d', which lands next to the object file, wherever that
+ # happens to be.
+ # Much of this is similar to the tru64 case; see comments there.
+ set_dir_from "$object"
+ set_base_from "$object"
+ if test "$libtool" = yes; then
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir.libs/$base.d
+ "$@" -Wc,+Maked
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ "$@" +Maked
+ fi
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ if test -f "$tmpdepfile"; then
+ sed -e "s,^.*\.[$lower]*:,$object:," "$tmpdepfile" > "$depfile"
+ # Add 'dependent.h:' lines.
+ sed -ne '2,${
+ s/^ *//
+ s/ \\*$//
+ s/$/:/
+ p
+ }' "$tmpdepfile" >> "$depfile"
+ else
+ make_dummy_depfile
+ fi
+ rm -f "$tmpdepfile" "$tmpdepfile2"
+ ;;
+
+tru64)
+ # The Tru64 compiler uses -MD to generate dependencies as a side
+ # effect. 'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
+ # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
+ # dependencies in 'foo.d' instead, so we check for that too.
+ # Subdirectories are respected.
+ set_dir_from "$object"
+ set_base_from "$object"
+
+ if test "$libtool" = yes; then
+ # Libtool generates 2 separate objects for the 2 libraries. These
+ # two compilations output dependencies in $dir.libs/$base.o.d and
+ # in $dir$base.o.d. We have to check for both files, because
+ # one of the two compilations can be disabled. We should prefer
+ # $dir$base.o.d over $dir.libs/$base.o.d because the latter is
+ # automatically cleaned when .libs/ is deleted, while ignoring
+ # the former would cause a distcleancheck panic.
+ tmpdepfile1=$dir$base.o.d # libtool 1.5
+ tmpdepfile2=$dir.libs/$base.o.d # Likewise.
+ tmpdepfile3=$dir.libs/$base.d # Compaq CCC V6.2-504
+ "$@" -Wc,-MD
+ else
+ tmpdepfile1=$dir$base.d
+ tmpdepfile2=$dir$base.d
+ tmpdepfile3=$dir$base.d
+ "$@" -MD
+ fi
+
+ stat=$?
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ exit $stat
+ fi
+
+ for tmpdepfile in "$tmpdepfile1" "$tmpdepfile2" "$tmpdepfile3"
+ do
+ test -f "$tmpdepfile" && break
+ done
+ # Same post-processing that is required for AIX mode.
+ aix_post_process_depfile
+ ;;
+
+msvc7)
+ if test "$libtool" = yes; then
+ showIncludes=-Wc,-showIncludes
+ else
+ showIncludes=-showIncludes
+ fi
+ "$@" $showIncludes > "$tmpdepfile"
+ stat=$?
+ grep -v '^Note: including file: ' "$tmpdepfile"
+ if test $stat -ne 0; then
+ rm -f "$tmpdepfile"
+ exit $stat
+ fi
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ # The first sed program below extracts the file names and escapes
+ # backslashes for cygpath. The second sed program outputs the file
+ # name when reading, but also accumulates all include files in the
+ # hold buffer in order to output them again at the end. This only
+ # works with sed implementations that can handle large buffers.
+ sed < "$tmpdepfile" -n '
+/^Note: including file: *\(.*\)/ {
+ s//\1/
+ s/\\/\\\\/g
+ p
+}' | $cygpath_u | sort -u | sed -n '
+s/ /\\ /g
+s/\(.*\)/'"$tab"'\1 \\/p
+s/.\(.*\) \\/\1:/
+H
+$ {
+ s/.*/'"$tab"'/
+ G
+ p
+}' >> "$depfile"
+ echo >> "$depfile" # make sure the fragment doesn't end with a backslash
+ rm -f "$tmpdepfile"
+ ;;
+
+msvc7msys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+#nosideeffect)
+ # This comment above is used by automake to tell side-effect
+ # dependency tracking mechanisms from slower ones.
+
+dashmstdout)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout, regardless of -o.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ test -z "$dashmflag" && dashmflag=-M
+ # Require at least two characters before searching for ':'
+ # in the target name. This is to cope with DOS-style filenames:
+ # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
+ "$@" $dashmflag |
+ sed "s|^[$tab ]*[^:$tab ][^:][^:]*:[$tab ]*|$object: |" > "$tmpdepfile"
+ rm -f "$depfile"
+ cat < "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process this sed invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ tr ' ' "$nl" < "$tmpdepfile" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+dashXmstdout)
+ # This case only exists to satisfy depend.m4. It is never actually
+ # run, as this mode is specially recognized in the preamble.
+ exit 1
+ ;;
+
+makedepend)
+ "$@" || exit $?
+ # Remove any Libtool call
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+ # X makedepend
+ shift
+ cleared=no eat=no
+ for arg
+ do
+ case $cleared in
+ no)
+ set ""; shift
+ cleared=yes ;;
+ esac
+ if test $eat = yes; then
+ eat=no
+ continue
+ fi
+ case "$arg" in
+ -D*|-I*)
+ set fnord "$@" "$arg"; shift ;;
+ # Strip any option that makedepend may not understand. Remove
+ # the object too, otherwise makedepend will parse it as a source file.
+ -arch)
+ eat=yes ;;
+ -*|$object)
+ ;;
+ *)
+ set fnord "$@" "$arg"; shift ;;
+ esac
+ done
+ obj_suffix=`echo "$object" | sed 's/^.*\././'`
+ touch "$tmpdepfile"
+ ${MAKEDEPEND-makedepend} -o"$obj_suffix" -f"$tmpdepfile" "$@"
+ rm -f "$depfile"
+ # makedepend may prepend the VPATH from the source file name to the object.
+ # No need to regex-escape $object, excess matching of '.' is harmless.
+ sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
+ # Some versions of the HPUX 10.20 sed can't process the last invocation
+ # correctly. Breaking it into two sed invocations is a workaround.
+ sed '1,2d' "$tmpdepfile" \
+ | tr ' ' "$nl" \
+ | sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' \
+ | sed -e 's/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile" "$tmpdepfile".bak
+ ;;
+
+cpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ # Remove '-o $object'.
+ IFS=" "
+ for arg
+ do
+ case $arg in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift # fnord
+ shift # $arg
+ ;;
+ esac
+ done
+
+ "$@" -E \
+ | sed -n -e '/^# [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ -e '/^#line [0-9][0-9]* "\([^"]*\)".*/ s:: \1 \\:p' \
+ | sed '$ s: \\$::' > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ cat < "$tmpdepfile" >> "$depfile"
+ sed < "$tmpdepfile" '/^$/d;s/^ //;s/ \\$//;s/$/ :/' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvisualcpp)
+ # Important note: in order to support this mode, a compiler *must*
+ # always write the preprocessed file to stdout.
+ "$@" || exit $?
+
+ # Remove the call to Libtool.
+ if test "$libtool" = yes; then
+ while test "X$1" != 'X--mode=compile'; do
+ shift
+ done
+ shift
+ fi
+
+ IFS=" "
+ for arg
+ do
+ case "$arg" in
+ -o)
+ shift
+ ;;
+ $object)
+ shift
+ ;;
+ "-Gm"|"/Gm"|"-Gi"|"/Gi"|"-ZI"|"/ZI")
+ set fnord "$@"
+ shift
+ shift
+ ;;
+ *)
+ set fnord "$@" "$arg"
+ shift
+ shift
+ ;;
+ esac
+ done
+ "$@" -E 2>/dev/null |
+ sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
+ rm -f "$depfile"
+ echo "$object : \\" > "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+ echo "$tab" >> "$depfile"
+ sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
+ rm -f "$tmpdepfile"
+ ;;
+
+msvcmsys)
+ # This case exists only to let depend.m4 do its work. It works by
+ # looking at the text of this script. This case will never be run,
+ # since it is checked for above.
+ exit 1
+ ;;
+
+none)
+ exec "$@"
+ ;;
+
+*)
+ echo "Unknown depmode $depmode" 1>&2
+ exit 1
+ ;;
+esac
+
+exit 0
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+#!/bin/sh
+VERSION="unknown"
+
+DIRTY=""
+git status | grep -q clean || DIRTY='.dirty'
+
+# Special environment variable to signal that we are building a release, as this
+# has condequenses for the version number.
+if [ "${IS_RELEASE}" = "YES" ]; then
+ TAG="$(git describe --tags --exact-match 2> /dev/null | cut -d- -f 2-)"
+ if [ -n "${TAG}" ]; then
+ # We're on a tag
+ echo "${TAG}${DIRTY}" > .version
+ printf "${TAG}${DIRTY}"
+ exit 0
+ fi
+ echo 'This is not a tag, either tag this commit or do not set $IS_RELEASE' >&2
+ exit 1
+fi
+
+#
+# Generate the version number based on the branch
+#
+if [ ! -z "$(git rev-parse --abbrev-ref HEAD 2> /dev/null)" ]; then
+ if $(git rev-parse --abbrev-ref HEAD | grep -q 'rel/'); then
+ REL_TYPE="$(git rev-parse --abbrev-ref HEAD | cut -d/ -f 2 | cut -d- -f 1)"
+ VERSION="$(git describe --match=${REL_TYPE}-* --dirty=.dirty | cut -d- -f 2-)"
+ else
+ GIT_VERSION=$(git show --no-patch --format=format:%h HEAD)
+ BRANCH=".$(git rev-parse --abbrev-ref HEAD | perl -p -e 's/-//g;')"
+ [ "${BRANCH}" = ".master" ] && BRANCH=''
+ VERSION="0.0${BRANCH}.${PDNS_BUILD_NUMBER}g${GIT_VERSION}${DIRTY}"
+ fi
+ echo "$VERSION" > .version
+elif [ -f .version ]; then
+ VERSION="$(cat .version)"
+fi
+
+printf $VERSION
--- /dev/null
+#!/bin/sh
+# install - install a program, script, or datafile
+
+scriptversion=2011-11-20.07; # UTC
+
+# This originates from X11R5 (mit/util/scripts/install.sh), which was
+# later released in X11R6 (xc/config/util/install.sh) with the
+# following copyright and license.
+#
+# Copyright (C) 1994 X Consortium
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy
+# of this software and associated documentation files (the "Software"), to
+# deal in the Software without restriction, including without limitation the
+# rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+# sell copies of the Software, and to permit persons to whom the Software is
+# furnished to do so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in
+# all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# X CONSORTIUM BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+# AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNEC-
+# TION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+#
+# Except as contained in this notice, the name of the X Consortium shall not
+# be used in advertising or otherwise to promote the sale, use or other deal-
+# ings in this Software without prior written authorization from the X Consor-
+# tium.
+#
+#
+# FSF changes to this file are in the public domain.
+#
+# Calling this script install-sh is preferred over install.sh, to prevent
+# 'make' implicit rules from creating a file called install from it
+# when there is no Makefile.
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+
+nl='
+'
+IFS=" "" $nl"
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit=${DOITPROG-}
+if test -z "$doit"; then
+ doit_exec=exec
+else
+ doit_exec=$doit
+fi
+
+# Put in absolute file names if you don't have them in your path;
+# or use environment vars.
+
+chgrpprog=${CHGRPPROG-chgrp}
+chmodprog=${CHMODPROG-chmod}
+chownprog=${CHOWNPROG-chown}
+cmpprog=${CMPPROG-cmp}
+cpprog=${CPPROG-cp}
+mkdirprog=${MKDIRPROG-mkdir}
+mvprog=${MVPROG-mv}
+rmprog=${RMPROG-rm}
+stripprog=${STRIPPROG-strip}
+
+posix_glob='?'
+initialize_posix_glob='
+ test "$posix_glob" != "?" || {
+ if (set -f) 2>/dev/null; then
+ posix_glob=
+ else
+ posix_glob=:
+ fi
+ }
+'
+
+posix_mkdir=
+
+# Desired mode of installed file.
+mode=0755
+
+chgrpcmd=
+chmodcmd=$chmodprog
+chowncmd=
+mvcmd=$mvprog
+rmcmd="$rmprog -f"
+stripcmd=
+
+src=
+dst=
+dir_arg=
+dst_arg=
+
+copy_on_change=false
+no_target_directory=
+
+usage="\
+Usage: $0 [OPTION]... [-T] SRCFILE DSTFILE
+ or: $0 [OPTION]... SRCFILES... DIRECTORY
+ or: $0 [OPTION]... -t DIRECTORY SRCFILES...
+ or: $0 [OPTION]... -d DIRECTORIES...
+
+In the 1st form, copy SRCFILE to DSTFILE.
+In the 2nd and 3rd, copy all SRCFILES to DIRECTORY.
+In the 4th, create DIRECTORIES.
+
+Options:
+ --help display this help and exit.
+ --version display version info and exit.
+
+ -c (ignored)
+ -C install only if different (preserve the last data modification time)
+ -d create directories instead of installing files.
+ -g GROUP $chgrpprog installed files to GROUP.
+ -m MODE $chmodprog installed files to MODE.
+ -o USER $chownprog installed files to USER.
+ -s $stripprog installed files.
+ -t DIRECTORY install into DIRECTORY.
+ -T report an error if DSTFILE is a directory.
+
+Environment variables override the default commands:
+ CHGRPPROG CHMODPROG CHOWNPROG CMPPROG CPPROG MKDIRPROG MVPROG
+ RMPROG STRIPPROG
+"
+
+while test $# -ne 0; do
+ case $1 in
+ -c) ;;
+
+ -C) copy_on_change=true;;
+
+ -d) dir_arg=true;;
+
+ -g) chgrpcmd="$chgrpprog $2"
+ shift;;
+
+ --help) echo "$usage"; exit $?;;
+
+ -m) mode=$2
+ case $mode in
+ *' '* | *' '* | *'
+'* | *'*'* | *'?'* | *'['*)
+ echo "$0: invalid mode: $mode" >&2
+ exit 1;;
+ esac
+ shift;;
+
+ -o) chowncmd="$chownprog $2"
+ shift;;
+
+ -s) stripcmd=$stripprog;;
+
+ -t) dst_arg=$2
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ shift;;
+
+ -T) no_target_directory=true;;
+
+ --version) echo "$0 $scriptversion"; exit $?;;
+
+ --) shift
+ break;;
+
+ -*) echo "$0: invalid option: $1" >&2
+ exit 1;;
+
+ *) break;;
+ esac
+ shift
+done
+
+if test $# -ne 0 && test -z "$dir_arg$dst_arg"; then
+ # When -d is used, all remaining arguments are directories to create.
+ # When -t is used, the destination is already specified.
+ # Otherwise, the last argument is the destination. Remove it from $@.
+ for arg
+ do
+ if test -n "$dst_arg"; then
+ # $@ is not empty: it contains at least $arg.
+ set fnord "$@" "$dst_arg"
+ shift # fnord
+ fi
+ shift # arg
+ dst_arg=$arg
+ # Protect names problematic for 'test' and other utilities.
+ case $dst_arg in
+ -* | [=\(\)!]) dst_arg=./$dst_arg;;
+ esac
+ done
+fi
+
+if test $# -eq 0; then
+ if test -z "$dir_arg"; then
+ echo "$0: no input file specified." >&2
+ exit 1
+ fi
+ # It's OK to call 'install-sh -d' without argument.
+ # This can happen when creating conditional directories.
+ exit 0
+fi
+
+if test -z "$dir_arg"; then
+ do_exit='(exit $ret); exit $ret'
+ trap "ret=129; $do_exit" 1
+ trap "ret=130; $do_exit" 2
+ trap "ret=141; $do_exit" 13
+ trap "ret=143; $do_exit" 15
+
+ # Set umask so as not to create temps with too-generous modes.
+ # However, 'strip' requires both read and write access to temps.
+ case $mode in
+ # Optimize common cases.
+ *644) cp_umask=133;;
+ *755) cp_umask=22;;
+
+ *[0-7])
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw='% 200'
+ fi
+ cp_umask=`expr '(' 777 - $mode % 1000 ')' $u_plus_rw`;;
+ *)
+ if test -z "$stripcmd"; then
+ u_plus_rw=
+ else
+ u_plus_rw=,u+rw
+ fi
+ cp_umask=$mode$u_plus_rw;;
+ esac
+fi
+
+for src
+do
+ # Protect names problematic for 'test' and other utilities.
+ case $src in
+ -* | [=\(\)!]) src=./$src;;
+ esac
+
+ if test -n "$dir_arg"; then
+ dst=$src
+ dstdir=$dst
+ test -d "$dstdir"
+ dstdir_status=$?
+ else
+
+ # Waiting for this to be detected by the "$cpprog $src $dsttmp" command
+ # might cause directories to be created, which would be especially bad
+ # if $src (and thus $dsttmp) contains '*'.
+ if test ! -f "$src" && test ! -d "$src"; then
+ echo "$0: $src does not exist." >&2
+ exit 1
+ fi
+
+ if test -z "$dst_arg"; then
+ echo "$0: no destination specified." >&2
+ exit 1
+ fi
+ dst=$dst_arg
+
+ # If destination is a directory, append the input filename; won't work
+ # if double slashes aren't ignored.
+ if test -d "$dst"; then
+ if test -n "$no_target_directory"; then
+ echo "$0: $dst_arg: Is a directory" >&2
+ exit 1
+ fi
+ dstdir=$dst
+ dst=$dstdir/`basename "$src"`
+ dstdir_status=0
+ else
+ # Prefer dirname, but fall back on a substitute if dirname fails.
+ dstdir=`
+ (dirname "$dst") 2>/dev/null ||
+ expr X"$dst" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$dst" : 'X\(//\)[^/]' \| \
+ X"$dst" : 'X\(//\)$' \| \
+ X"$dst" : 'X\(/\)' \| . 2>/dev/null ||
+ echo X"$dst" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'
+ `
+
+ test -d "$dstdir"
+ dstdir_status=$?
+ fi
+ fi
+
+ obsolete_mkdir_used=false
+
+ if test $dstdir_status != 0; then
+ case $posix_mkdir in
+ '')
+ # Create intermediate dirs using mode 755 as modified by the umask.
+ # This is like FreeBSD 'install' as of 1997-10-28.
+ umask=`umask`
+ case $stripcmd.$umask in
+ # Optimize common cases.
+ *[2367][2367]) mkdir_umask=$umask;;
+ .*0[02][02] | .[02][02] | .[02]) mkdir_umask=22;;
+
+ *[0-7])
+ mkdir_umask=`expr $umask + 22 \
+ - $umask % 100 % 40 + $umask % 20 \
+ - $umask % 10 % 4 + $umask % 2
+ `;;
+ *) mkdir_umask=$umask,go-w;;
+ esac
+
+ # With -d, create the new directory with the user-specified mode.
+ # Otherwise, rely on $mkdir_umask.
+ if test -n "$dir_arg"; then
+ mkdir_mode=-m$mode
+ else
+ mkdir_mode=
+ fi
+
+ posix_mkdir=false
+ case $umask in
+ *[123567][0-7][0-7])
+ # POSIX mkdir -p sets u+wx bits regardless of umask, which
+ # is incompatible with FreeBSD 'install' when (umask & 300) != 0.
+ ;;
+ *)
+ # $RANDOM is not portable (e.g. dash); use it when possible to
+ # lower collision chance
+ tmpdir=${TMPDIR-/tmp}/ins$RANDOM-$$
+ trap 'ret=$?; rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir" 2>/dev/null; exit $ret' 0
+
+ # As "mkdir -p" follows symlinks and we work in /tmp possibly; so
+ # create the $tmpdir first (and fail if unsuccessful) to make sure
+ # that nobody tries to guess the $tmpdir name.
+ if (umask $mkdir_umask &&
+ $mkdirprog $mkdir_mode "$tmpdir" &&
+ exec $mkdirprog $mkdir_mode -p -- "$tmpdir/a/b") >/dev/null 2>&1
+ then
+ if test -z "$dir_arg" || {
+ # Check for POSIX incompatibilities with -m.
+ # HP-UX 11.23 and IRIX 6.5 mkdir -m -p sets group- or
+ # other-writable bit of parent directory when it shouldn't.
+ # FreeBSD 6.1 mkdir -m -p sets mode of existing directory.
+ test_tmpdir="$tmpdir/a"
+ ls_ld_tmpdir=`ls -ld "$test_tmpdir"`
+ case $ls_ld_tmpdir in
+ d????-?r-*) different_mode=700;;
+ d????-?--*) different_mode=755;;
+ *) false;;
+ esac &&
+ $mkdirprog -m$different_mode -p -- "$test_tmpdir" && {
+ ls_ld_tmpdir_1=`ls -ld "$test_tmpdir"`
+ test "$ls_ld_tmpdir" = "$ls_ld_tmpdir_1"
+ }
+ }
+ then posix_mkdir=:
+ fi
+ rmdir "$tmpdir/a/b" "$tmpdir/a" "$tmpdir"
+ else
+ # Remove any dirs left behind by ancient mkdir implementations.
+ rmdir ./$mkdir_mode ./-p ./-- "$tmpdir" 2>/dev/null
+ fi
+ trap '' 0;;
+ esac;;
+ esac
+
+ if
+ $posix_mkdir && (
+ umask $mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir"
+ )
+ then :
+ else
+
+ # The umask is ridiculous, or mkdir does not conform to POSIX,
+ # or it failed possibly due to a race condition. Create the
+ # directory the slow way, step by step, checking for races as we go.
+
+ case $dstdir in
+ /*) prefix='/';;
+ [-=\(\)!]*) prefix='./';;
+ *) prefix='';;
+ esac
+
+ eval "$initialize_posix_glob"
+
+ oIFS=$IFS
+ IFS=/
+ $posix_glob set -f
+ set fnord $dstdir
+ shift
+ $posix_glob set +f
+ IFS=$oIFS
+
+ prefixes=
+
+ for d
+ do
+ test X"$d" = X && continue
+
+ prefix=$prefix$d
+ if test -d "$prefix"; then
+ prefixes=
+ else
+ if $posix_mkdir; then
+ (umask=$mkdir_umask &&
+ $doit_exec $mkdirprog $mkdir_mode -p -- "$dstdir") && break
+ # Don't fail if two instances are running concurrently.
+ test -d "$prefix" || exit 1
+ else
+ case $prefix in
+ *\'*) qprefix=`echo "$prefix" | sed "s/'/'\\\\\\\\''/g"`;;
+ *) qprefix=$prefix;;
+ esac
+ prefixes="$prefixes '$qprefix'"
+ fi
+ fi
+ prefix=$prefix/
+ done
+
+ if test -n "$prefixes"; then
+ # Don't fail if two instances are running concurrently.
+ (umask $mkdir_umask &&
+ eval "\$doit_exec \$mkdirprog $prefixes") ||
+ test -d "$dstdir" || exit 1
+ obsolete_mkdir_used=true
+ fi
+ fi
+ fi
+
+ if test -n "$dir_arg"; then
+ { test -z "$chowncmd" || $doit $chowncmd "$dst"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dst"; } &&
+ { test "$obsolete_mkdir_used$chowncmd$chgrpcmd" = false ||
+ test -z "$chmodcmd" || $doit $chmodcmd $mode "$dst"; } || exit 1
+ else
+
+ # Make a couple of temp file names in the proper directory.
+ dsttmp=$dstdir/_inst.$$_
+ rmtmp=$dstdir/_rm.$$_
+
+ # Trap to clean up those temp files at exit.
+ trap 'ret=$?; rm -f "$dsttmp" "$rmtmp" && exit $ret' 0
+
+ # Copy the file name to the temp name.
+ (umask $cp_umask && $doit_exec $cpprog "$src" "$dsttmp") &&
+
+ # and set any options; do chmod last to preserve setuid bits.
+ #
+ # If any of these fail, we abort the whole thing. If we want to
+ # ignore errors from any of these, just make sure not to ignore
+ # errors from the above "$doit $cpprog $src $dsttmp" command.
+ #
+ { test -z "$chowncmd" || $doit $chowncmd "$dsttmp"; } &&
+ { test -z "$chgrpcmd" || $doit $chgrpcmd "$dsttmp"; } &&
+ { test -z "$stripcmd" || $doit $stripcmd "$dsttmp"; } &&
+ { test -z "$chmodcmd" || $doit $chmodcmd $mode "$dsttmp"; } &&
+
+ # If -C, don't bother to copy if it wouldn't change the file.
+ if $copy_on_change &&
+ old=`LC_ALL=C ls -dlL "$dst" 2>/dev/null` &&
+ new=`LC_ALL=C ls -dlL "$dsttmp" 2>/dev/null` &&
+
+ eval "$initialize_posix_glob" &&
+ $posix_glob set -f &&
+ set X $old && old=:$2:$4:$5:$6 &&
+ set X $new && new=:$2:$4:$5:$6 &&
+ $posix_glob set +f &&
+
+ test "$old" = "$new" &&
+ $cmpprog "$dst" "$dsttmp" >/dev/null 2>&1
+ then
+ rm -f "$dsttmp"
+ else
+ # Rename the file to the real destination.
+ $doit $mvcmd -f "$dsttmp" "$dst" 2>/dev/null ||
+
+ # The rename failed, perhaps because mv can't rename something else
+ # to itself, or perhaps because mv is so ancient that it does not
+ # support -f.
+ {
+ # Now remove or move aside any old file at destination location.
+ # We try this two ways since rm can't unlink itself on some
+ # systems and the destination file might be busy for other
+ # reasons. In this case, the final cleanup might fail but the new
+ # file should still install successfully.
+ {
+ test ! -f "$dst" ||
+ $doit $rmcmd -f "$dst" 2>/dev/null ||
+ { $doit $mvcmd -f "$dst" "$rmtmp" 2>/dev/null &&
+ { $doit $rmcmd -f "$rmtmp" 2>/dev/null; :; }
+ } ||
+ { echo "$0: cannot unlink or rename $dst" >&2
+ (exit 1); exit 1
+ }
+ } &&
+
+ # Now rename the file to the real destination.
+ $doit $mvcmd "$dsttmp" "$dst"
+ }
+ fi || exit 1
+
+ trap '' 0
+ fi
+done
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+
+# libtool (GNU libtool) 2.4.2
+# Written by Gordon Matzigkeit <gord@gnu.ai.mit.edu>, 1996
+
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005, 2006,
+# 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+# This is free software; see the source for copying conditions. There is NO
+# warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+
+# GNU Libtool is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html,
+# or obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+# Usage: $progname [OPTION]... [MODE-ARG]...
+#
+# Provide generalized library-building support services.
+#
+# --config show all configuration variables
+# --debug enable verbose shell tracing
+# -n, --dry-run display commands without modifying any files
+# --features display basic configuration information and exit
+# --mode=MODE use operation mode MODE
+# --preserve-dup-deps don't remove duplicate dependency libraries
+# --quiet, --silent don't print informational messages
+# --no-quiet, --no-silent
+# print informational messages (default)
+# --no-warn don't display warning messages
+# --tag=TAG use configuration variables from tag TAG
+# -v, --verbose print more informational messages than default
+# --no-verbose don't print the extra informational messages
+# --version print version information
+# -h, --help, --help-all print short, long, or detailed help message
+#
+# MODE must be one of the following:
+#
+# clean remove files from the build directory
+# compile compile a source file into a libtool object
+# execute automatically set library path, then run a program
+# finish complete the installation of libtool libraries
+# install install libraries or executables
+# link create a library or an executable
+# uninstall remove libraries from an installed directory
+#
+# MODE-ARGS vary depending on the MODE. When passed as first option,
+# `--mode=MODE' may be abbreviated as `MODE' or a unique abbreviation of that.
+# Try `$progname --help --mode=MODE' for a more detailed description of MODE.
+#
+# When reporting a bug, please describe a test case to reproduce it and
+# include the following information:
+#
+# host-triplet: $host
+# shell: $SHELL
+# compiler: $LTCC
+# compiler flags: $LTCFLAGS
+# linker: $LD (gnu? $with_gnu_ld)
+# $progname: (GNU libtool) 2.4.2 Debian-2.4.2-1.11
+# automake: $automake_version
+# autoconf: $autoconf_version
+#
+# Report bugs to <bug-libtool@gnu.org>.
+# GNU libtool home page: <http://www.gnu.org/software/libtool/>.
+# General help using GNU software: <http://www.gnu.org/gethelp/>.
+
+PROGRAM=libtool
+PACKAGE=libtool
+VERSION="2.4.2 Debian-2.4.2-1.11"
+TIMESTAMP=""
+package_revision=1.3337
+
+# Be Bourne compatible
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+}
+
+# NLS nuisances: We save the old values to restore during execute mode.
+lt_user_locale=
+lt_safe_locale=
+for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+do
+ eval "if test \"\${$lt_var+set}\" = set; then
+ save_$lt_var=\$$lt_var
+ $lt_var=C
+ export $lt_var
+ lt_user_locale=\"$lt_var=\\\$save_\$lt_var; \$lt_user_locale\"
+ lt_safe_locale=\"$lt_var=C; \$lt_safe_locale\"
+ fi"
+done
+LC_ALL=C
+LANGUAGE=C
+export LANGUAGE LC_ALL
+
+$lt_unset CDPATH
+
+
+# Work around backward compatibility issue on IRIX 6.5. On IRIX 6.4+, sh
+# is ksh but when the shell is invoked as "sh" and the current value of
+# the _XPG environment variable is not equal to 1 (one), the special
+# positional parameter $0, within a function call, is the name of the
+# function.
+progpath="$0"
+
+
+
+: ${CP="cp -f"}
+test "${ECHO+set}" = set || ECHO=${as_echo-'printf %s\n'}
+: ${MAKE="make"}
+: ${MKDIR="mkdir"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+: ${SHELL="${CONFIG_SHELL-/bin/sh}"}
+: ${Xsed="$SED -e 1s/^X//"}
+
+# Global variables:
+EXIT_SUCCESS=0
+EXIT_FAILURE=1
+EXIT_MISMATCH=63 # $? = 63 is used to indicate version mismatch to missing.
+EXIT_SKIP=77 # $? = 77 is used to indicate a skipped test to automake.
+
+exit_status=$EXIT_SUCCESS
+
+# Make sure IFS has a sensible default
+lt_nl='
+'
+IFS=" $lt_nl"
+
+dirname="s,/[^/]*$,,"
+basename="s,^.*/,,"
+
+# func_dirname file append nondir_replacement
+# Compute the dirname of FILE. If nonempty, add APPEND to the result,
+# otherwise set result to NONDIR_REPLACEMENT.
+func_dirname ()
+{
+ func_dirname_result=`$ECHO "${1}" | $SED "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+} # func_dirname may be replaced by extended shell implementation
+
+
+# func_basename file
+func_basename ()
+{
+ func_basename_result=`$ECHO "${1}" | $SED "$basename"`
+} # func_basename may be replaced by extended shell implementation
+
+
+# func_dirname_and_basename file append nondir_replacement
+# perform func_basename and func_dirname in a single function
+# call:
+# dirname: Compute the dirname of FILE. If nonempty,
+# add APPEND to the result, otherwise set result
+# to NONDIR_REPLACEMENT.
+# value returned in "$func_dirname_result"
+# basename: Compute filename of FILE.
+# value retuned in "$func_basename_result"
+# Implementation must be kept synchronized with func_dirname
+# and func_basename. For efficiency, we do not delegate to
+# those functions but instead duplicate the functionality here.
+func_dirname_and_basename ()
+{
+ # Extract subdirectory from the argument.
+ func_dirname_result=`$ECHO "${1}" | $SED -e "$dirname"`
+ if test "X$func_dirname_result" = "X${1}"; then
+ func_dirname_result="${3}"
+ else
+ func_dirname_result="$func_dirname_result${2}"
+ fi
+ func_basename_result=`$ECHO "${1}" | $SED -e "$basename"`
+} # func_dirname_and_basename may be replaced by extended shell implementation
+
+
+# func_stripname prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+# func_strip_suffix prefix name
+func_stripname ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname may be replaced by extended shell implementation
+
+
+# These SED scripts presuppose an absolute path with a trailing slash.
+pathcar='s,^/\([^/]*\).*$,\1,'
+pathcdr='s,^/[^/]*,,'
+removedotparts=':dotsl
+ s@/\./@/@g
+ t dotsl
+ s,/\.$,/,'
+collapseslashes='s@/\{1,\}@/@g'
+finalslash='s,/*$,/,'
+
+# func_normal_abspath PATH
+# Remove doubled-up and trailing slashes, "." path components,
+# and cancel out any ".." path components in PATH after making
+# it an absolute path.
+# value returned in "$func_normal_abspath_result"
+func_normal_abspath ()
+{
+ # Start from root dir and reassemble the path.
+ func_normal_abspath_result=
+ func_normal_abspath_tpath=$1
+ func_normal_abspath_altnamespace=
+ case $func_normal_abspath_tpath in
+ "")
+ # Empty path, that just means $cwd.
+ func_stripname '' '/' "`pwd`"
+ func_normal_abspath_result=$func_stripname_result
+ return
+ ;;
+ # The next three entries are used to spot a run of precisely
+ # two leading slashes without using negated character classes;
+ # we take advantage of case's first-match behaviour.
+ ///*)
+ # Unusual form of absolute path, do nothing.
+ ;;
+ //*)
+ # Not necessarily an ordinary path; POSIX reserves leading '//'
+ # and for example Cygwin uses it to access remote file shares
+ # over CIFS/SMB, so we conserve a leading double slash if found.
+ func_normal_abspath_altnamespace=/
+ ;;
+ /*)
+ # Absolute path, do nothing.
+ ;;
+ *)
+ # Relative path, prepend $cwd.
+ func_normal_abspath_tpath=`pwd`/$func_normal_abspath_tpath
+ ;;
+ esac
+ # Cancel out all the simple stuff to save iterations. We also want
+ # the path to end with a slash for ease of parsing, so make sure
+ # there is one (and only one) here.
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$removedotparts" -e "$collapseslashes" -e "$finalslash"`
+ while :; do
+ # Processed it all yet?
+ if test "$func_normal_abspath_tpath" = / ; then
+ # If we ascended to the root using ".." the result may be empty now.
+ if test -z "$func_normal_abspath_result" ; then
+ func_normal_abspath_result=/
+ fi
+ break
+ fi
+ func_normal_abspath_tcomponent=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcar"`
+ func_normal_abspath_tpath=`$ECHO "$func_normal_abspath_tpath" | $SED \
+ -e "$pathcdr"`
+ # Figure out what to do with it
+ case $func_normal_abspath_tcomponent in
+ "")
+ # Trailing empty path component, ignore it.
+ ;;
+ ..)
+ # Parent dir; strip last assembled component from result.
+ func_dirname "$func_normal_abspath_result"
+ func_normal_abspath_result=$func_dirname_result
+ ;;
+ *)
+ # Actual path component, append it.
+ func_normal_abspath_result=$func_normal_abspath_result/$func_normal_abspath_tcomponent
+ ;;
+ esac
+ done
+ # Restore leading double-slash if one was found on entry.
+ func_normal_abspath_result=$func_normal_abspath_altnamespace$func_normal_abspath_result
+}
+
+# func_relative_path SRCDIR DSTDIR
+# generates a relative path from SRCDIR to DSTDIR, with a trailing
+# slash if non-empty, suitable for immediately appending a filename
+# without needing to append a separator.
+# value returned in "$func_relative_path_result"
+func_relative_path ()
+{
+ func_relative_path_result=
+ func_normal_abspath "$1"
+ func_relative_path_tlibdir=$func_normal_abspath_result
+ func_normal_abspath "$2"
+ func_relative_path_tbindir=$func_normal_abspath_result
+
+ # Ascend the tree starting from libdir
+ while :; do
+ # check if we have found a prefix of bindir
+ case $func_relative_path_tbindir in
+ $func_relative_path_tlibdir)
+ # found an exact match
+ func_relative_path_tcancelled=
+ break
+ ;;
+ $func_relative_path_tlibdir*)
+ # found a matching prefix
+ func_stripname "$func_relative_path_tlibdir" '' "$func_relative_path_tbindir"
+ func_relative_path_tcancelled=$func_stripname_result
+ if test -z "$func_relative_path_result"; then
+ func_relative_path_result=.
+ fi
+ break
+ ;;
+ *)
+ func_dirname $func_relative_path_tlibdir
+ func_relative_path_tlibdir=${func_dirname_result}
+ if test "x$func_relative_path_tlibdir" = x ; then
+ # Have to descend all the way to the root!
+ func_relative_path_result=../$func_relative_path_result
+ func_relative_path_tcancelled=$func_relative_path_tbindir
+ break
+ fi
+ func_relative_path_result=../$func_relative_path_result
+ ;;
+ esac
+ done
+
+ # Now calculate path; take care to avoid doubling-up slashes.
+ func_stripname '' '/' "$func_relative_path_result"
+ func_relative_path_result=$func_stripname_result
+ func_stripname '/' '/' "$func_relative_path_tcancelled"
+ if test "x$func_stripname_result" != x ; then
+ func_relative_path_result=${func_relative_path_result}/${func_stripname_result}
+ fi
+
+ # Normalisation. If bindir is libdir, return empty string,
+ # else relative path ending with a slash; either way, target
+ # file name can be directly appended.
+ if test ! -z "$func_relative_path_result"; then
+ func_stripname './' '' "$func_relative_path_result/"
+ func_relative_path_result=$func_stripname_result
+ fi
+}
+
+# The name of this program:
+func_dirname_and_basename "$progpath"
+progname=$func_basename_result
+
+# Make sure we have an absolute path for reexecution:
+case $progpath in
+ [\\/]*|[A-Za-z]:\\*) ;;
+ *[\\/]*)
+ progdir=$func_dirname_result
+ progdir=`cd "$progdir" && pwd`
+ progpath="$progdir/$progname"
+ ;;
+ *)
+ save_IFS="$IFS"
+ IFS=${PATH_SEPARATOR-:}
+ for progdir in $PATH; do
+ IFS="$save_IFS"
+ test -x "$progdir/$progname" && break
+ done
+ IFS="$save_IFS"
+ test -n "$progdir" || progdir=`pwd`
+ progpath="$progdir/$progname"
+ ;;
+esac
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+Xsed="${SED}"' -e 1s/^X//'
+sed_quote_subst='s/\([`"$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution that turns a string into a regex matching for the
+# string literally.
+sed_make_literal_regex='s,[].[^$\\*\/],\\&,g'
+
+# Sed substitution that converts a w32 file name or path
+# which contains forward slashes, into one that contains
+# (escaped) backslashes. A very naive implementation.
+lt_sed_naive_backslashify='s|\\\\*|\\|g;s|/|\\|g;s|\\|\\\\|g'
+
+# Re-`\' parameter expansions in output of double_quote_subst that were
+# `\'-ed in input to the same. If an odd number of `\' preceded a '$'
+# in input to double_quote_subst, that '$' was protected from expansion.
+# Since each input `\' is now two `\'s, look for any number of runs of
+# four `\'s followed by two `\'s and then a '$'. `\' that '$'.
+bs='\\'
+bs2='\\\\'
+bs4='\\\\\\\\'
+dollar='\$'
+sed_double_backslash="\
+ s/$bs4/&\\
+/g
+ s/^$bs2$dollar/$bs&/
+ s/\\([^$bs]\\)$bs2$dollar/\\1$bs2$bs$dollar/g
+ s/\n//g"
+
+# Standard options:
+opt_dry_run=false
+opt_help=false
+opt_quiet=false
+opt_verbose=false
+opt_warning=:
+
+# func_echo arg...
+# Echo program name prefixed message, along with the current mode
+# name if it has been set yet.
+func_echo ()
+{
+ $ECHO "$progname: ${opt_mode+$opt_mode: }$*"
+}
+
+# func_verbose arg...
+# Echo program name prefixed message in verbose mode only.
+func_verbose ()
+{
+ $opt_verbose && func_echo ${1+"$@"}
+
+ # A bug in bash halts the script if the last line of a function
+ # fails when set -e is in force, so we need another command to
+ # work around that:
+ :
+}
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+# func_error arg...
+# Echo program name prefixed message to standard error.
+func_error ()
+{
+ $ECHO "$progname: ${opt_mode+$opt_mode: }"${1+"$@"} 1>&2
+}
+
+# func_warning arg...
+# Echo program name prefixed warning message to standard error.
+func_warning ()
+{
+ $opt_warning && $ECHO "$progname: ${opt_mode+$opt_mode: }warning: "${1+"$@"} 1>&2
+
+ # bash bug again:
+ :
+}
+
+# func_fatal_error arg...
+# Echo program name prefixed message to standard error, and exit.
+func_fatal_error ()
+{
+ func_error ${1+"$@"}
+ exit $EXIT_FAILURE
+}
+
+# func_fatal_help arg...
+# Echo program name prefixed message to standard error, followed by
+# a help hint, and exit.
+func_fatal_help ()
+{
+ func_error ${1+"$@"}
+ func_fatal_error "$help"
+}
+help="Try \`$progname --help' for more information." ## default
+
+
+# func_grep expression filename
+# Check whether EXPRESSION matches any line of FILENAME, without output.
+func_grep ()
+{
+ $GREP "$1" "$2" >/dev/null 2>&1
+}
+
+
+# func_mkdir_p directory-path
+# Make sure the entire path to DIRECTORY-PATH is available.
+func_mkdir_p ()
+{
+ my_directory_path="$1"
+ my_dir_list=
+
+ if test -n "$my_directory_path" && test "$opt_dry_run" != ":"; then
+
+ # Protect directory names starting with `-'
+ case $my_directory_path in
+ -*) my_directory_path="./$my_directory_path" ;;
+ esac
+
+ # While some portion of DIR does not yet exist...
+ while test ! -d "$my_directory_path"; do
+ # ...make a list in topmost first order. Use a colon delimited
+ # list incase some portion of path contains whitespace.
+ my_dir_list="$my_directory_path:$my_dir_list"
+
+ # If the last portion added has no slash in it, the list is done
+ case $my_directory_path in */*) ;; *) break ;; esac
+
+ # ...otherwise throw away the child directory and loop
+ my_directory_path=`$ECHO "$my_directory_path" | $SED -e "$dirname"`
+ done
+ my_dir_list=`$ECHO "$my_dir_list" | $SED 's,:*$,,'`
+
+ save_mkdir_p_IFS="$IFS"; IFS=':'
+ for my_dir in $my_dir_list; do
+ IFS="$save_mkdir_p_IFS"
+ # mkdir can fail with a `File exist' error if two processes
+ # try to create one of the directories concurrently. Don't
+ # stop in that case!
+ $MKDIR "$my_dir" 2>/dev/null || :
+ done
+ IFS="$save_mkdir_p_IFS"
+
+ # Bail out if we (or some other process) failed to create a directory.
+ test -d "$my_directory_path" || \
+ func_fatal_error "Failed to create \`$1'"
+ fi
+}
+
+
+# func_mktempdir [string]
+# Make a temporary directory that won't clash with other running
+# libtool processes, and avoids race conditions if possible. If
+# given, STRING is the basename for that directory.
+func_mktempdir ()
+{
+ my_template="${TMPDIR-/tmp}/${1-$progname}"
+
+ if test "$opt_dry_run" = ":"; then
+ # Return a directory name, but don't create it in dry-run mode
+ my_tmpdir="${my_template}-$$"
+ else
+
+ # If mktemp works, use that first and foremost
+ my_tmpdir=`mktemp -d "${my_template}-XXXXXXXX" 2>/dev/null`
+
+ if test ! -d "$my_tmpdir"; then
+ # Failing that, at least try and use $RANDOM to avoid a race
+ my_tmpdir="${my_template}-${RANDOM-0}$$"
+
+ save_mktempdir_umask=`umask`
+ umask 0077
+ $MKDIR "$my_tmpdir"
+ umask $save_mktempdir_umask
+ fi
+
+ # If we're not in dry-run mode, bomb out on failure
+ test -d "$my_tmpdir" || \
+ func_fatal_error "cannot create temporary directory \`$my_tmpdir'"
+ fi
+
+ $ECHO "$my_tmpdir"
+}
+
+
+# func_quote_for_eval arg
+# Aesthetically quote ARG to be evaled later.
+# This function returns two values: FUNC_QUOTE_FOR_EVAL_RESULT
+# is double-quoted, suitable for a subsequent eval, whereas
+# FUNC_QUOTE_FOR_EVAL_UNQUOTED_RESULT has merely all characters
+# which are still active within double quotes backslashified.
+func_quote_for_eval ()
+{
+ case $1 in
+ *[\\\`\"\$]*)
+ func_quote_for_eval_unquoted_result=`$ECHO "$1" | $SED "$sed_quote_subst"` ;;
+ *)
+ func_quote_for_eval_unquoted_result="$1" ;;
+ esac
+
+ case $func_quote_for_eval_unquoted_result in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting, command substitution and and variable
+ # expansion for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ func_quote_for_eval_result="\"$func_quote_for_eval_unquoted_result\""
+ ;;
+ *)
+ func_quote_for_eval_result="$func_quote_for_eval_unquoted_result"
+ esac
+}
+
+
+# func_quote_for_expand arg
+# Aesthetically quote ARG to be evaled later; same as above,
+# but do not quote variable references.
+func_quote_for_expand ()
+{
+ case $1 in
+ *[\\\`\"]*)
+ my_arg=`$ECHO "$1" | $SED \
+ -e "$double_quote_subst" -e "$sed_double_backslash"` ;;
+ *)
+ my_arg="$1" ;;
+ esac
+
+ case $my_arg in
+ # Double-quote args containing shell metacharacters to delay
+ # word splitting and command substitution for a subsequent eval.
+ # Many Bourne shells cannot handle close brackets correctly
+ # in scan sets, so we specify it separately.
+ *[\[\~\#\^\&\*\(\)\{\}\|\;\<\>\?\'\ \ ]*|*]*|"")
+ my_arg="\"$my_arg\""
+ ;;
+ esac
+
+ func_quote_for_expand_result="$my_arg"
+}
+
+
+# func_show_eval cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it.
+func_show_eval ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$my_cmd"
+ my_status=$?
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+
+# func_show_eval_locale cmd [fail_exp]
+# Unless opt_silent is true, then output CMD. Then, if opt_dryrun is
+# not true, evaluate CMD. If the evaluation of CMD fails, and FAIL_EXP
+# is given, then evaluate it. Use the saved locale for evaluation.
+func_show_eval_locale ()
+{
+ my_cmd="$1"
+ my_fail_exp="${2-:}"
+
+ ${opt_silent-false} || {
+ func_quote_for_expand "$my_cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+
+ if ${opt_dry_run-false}; then :; else
+ eval "$lt_user_locale
+ $my_cmd"
+ my_status=$?
+ eval "$lt_safe_locale"
+ if test "$my_status" -eq 0; then :; else
+ eval "(exit $my_status); $my_fail_exp"
+ fi
+ fi
+}
+
+# func_tr_sh
+# Turn $1 into a string suitable for a shell variable name.
+# Result is stored in $func_tr_sh_result. All characters
+# not in the set a-zA-Z0-9_ are replaced with '_'. Further,
+# if $1 begins with a digit, a '_' is prepended as well.
+func_tr_sh ()
+{
+ case $1 in
+ [0-9]* | *[!a-zA-Z0-9_]*)
+ func_tr_sh_result=`$ECHO "$1" | $SED 's/^\([0-9]\)/_\1/; s/[^a-zA-Z0-9_]/_/g'`
+ ;;
+ * )
+ func_tr_sh_result=$1
+ ;;
+ esac
+}
+
+
+# func_version
+# Echo version message to standard output and exit.
+func_version ()
+{
+ $opt_debug
+
+ $SED -n '/(C)/!b go
+ :more
+ /\./!{
+ N
+ s/\n# / /
+ b more
+ }
+ :go
+ /^# '$PROGRAM' (GNU /,/# warranty; / {
+ s/^# //
+ s/^# *$//
+ s/\((C)\)[ 0-9,-]*\( [1-9][0-9]*\)/\1\2/
+ p
+ }' < "$progpath"
+ exit $?
+}
+
+# func_usage
+# Echo short help message to standard output and exit.
+func_usage ()
+{
+ $opt_debug
+
+ $SED -n '/^# Usage:/,/^# *.*--help/ {
+ s/^# //
+ s/^# *$//
+ s/\$progname/'$progname'/
+ p
+ }' < "$progpath"
+ echo
+ $ECHO "run \`$progname --help | more' for full usage"
+ exit $?
+}
+
+# func_help [NOEXIT]
+# Echo long help message to standard output and exit,
+# unless 'noexit' is passed as argument.
+func_help ()
+{
+ $opt_debug
+
+ $SED -n '/^# Usage:/,/# Report bugs to/ {
+ :print
+ s/^# //
+ s/^# *$//
+ s*\$progname*'$progname'*
+ s*\$host*'"$host"'*
+ s*\$SHELL*'"$SHELL"'*
+ s*\$LTCC*'"$LTCC"'*
+ s*\$LTCFLAGS*'"$LTCFLAGS"'*
+ s*\$LD*'"$LD"'*
+ s/\$with_gnu_ld/'"$with_gnu_ld"'/
+ s/\$automake_version/'"`(${AUTOMAKE-automake} --version) 2>/dev/null |$SED 1q`"'/
+ s/\$autoconf_version/'"`(${AUTOCONF-autoconf} --version) 2>/dev/null |$SED 1q`"'/
+ p
+ d
+ }
+ /^# .* home page:/b print
+ /^# General help using/b print
+ ' < "$progpath"
+ ret=$?
+ if test -z "$1"; then
+ exit $ret
+ fi
+}
+
+# func_missing_arg argname
+# Echo program name prefixed message to standard error and set global
+# exit_cmd.
+func_missing_arg ()
+{
+ $opt_debug
+
+ func_error "missing argument for $1."
+ exit_cmd=exit
+}
+
+
+# func_split_short_opt shortopt
+# Set func_split_short_opt_name and func_split_short_opt_arg shell
+# variables after splitting SHORTOPT after the 2nd character.
+func_split_short_opt ()
+{
+ my_sed_short_opt='1s/^\(..\).*$/\1/;q'
+ my_sed_short_rest='1s/^..\(.*\)$/\1/;q'
+
+ func_split_short_opt_name=`$ECHO "$1" | $SED "$my_sed_short_opt"`
+ func_split_short_opt_arg=`$ECHO "$1" | $SED "$my_sed_short_rest"`
+} # func_split_short_opt may be replaced by extended shell implementation
+
+
+# func_split_long_opt longopt
+# Set func_split_long_opt_name and func_split_long_opt_arg shell
+# variables after splitting LONGOPT at the `=' sign.
+func_split_long_opt ()
+{
+ my_sed_long_opt='1s/^\(--[^=]*\)=.*/\1/;q'
+ my_sed_long_arg='1s/^--[^=]*=//'
+
+ func_split_long_opt_name=`$ECHO "$1" | $SED "$my_sed_long_opt"`
+ func_split_long_opt_arg=`$ECHO "$1" | $SED "$my_sed_long_arg"`
+} # func_split_long_opt may be replaced by extended shell implementation
+
+exit_cmd=:
+
+
+
+
+
+magic="%%%MAGIC variable%%%"
+magic_exe="%%%MAGIC EXE variable%%%"
+
+# Global variables.
+nonopt=
+preserve_args=
+lo2o="s/\\.lo\$/.${objext}/"
+o2lo="s/\\.${objext}\$/.lo/"
+extracted_archives=
+extracted_serial=0
+
+# If this variable is set in any of the actions, the command in it
+# will be execed at the end. This prevents here-documents from being
+# left over by shells.
+exec_cmd=
+
+# func_append var value
+# Append VALUE to the end of shell variable VAR.
+func_append ()
+{
+ eval "${1}=\$${1}\${2}"
+} # func_append may be replaced by extended shell implementation
+
+# func_append_quoted var value
+# Quote VALUE and append to the end of shell variable VAR, separated
+# by a space.
+func_append_quoted ()
+{
+ func_quote_for_eval "${2}"
+ eval "${1}=\$${1}\\ \$func_quote_for_eval_result"
+} # func_append_quoted may be replaced by extended shell implementation
+
+
+# func_arith arithmetic-term...
+func_arith ()
+{
+ func_arith_result=`expr "${@}"`
+} # func_arith may be replaced by extended shell implementation
+
+
+# func_len string
+# STRING may not start with a hyphen.
+func_len ()
+{
+ func_len_result=`expr "${1}" : ".*" 2>/dev/null || echo $max_cmd_len`
+} # func_len may be replaced by extended shell implementation
+
+
+# func_lo2o object
+func_lo2o ()
+{
+ func_lo2o_result=`$ECHO "${1}" | $SED "$lo2o"`
+} # func_lo2o may be replaced by extended shell implementation
+
+
+# func_xform libobj-or-source
+func_xform ()
+{
+ func_xform_result=`$ECHO "${1}" | $SED 's/\.[^.]*$/.lo/'`
+} # func_xform may be replaced by extended shell implementation
+
+
+# func_fatal_configuration arg...
+# Echo program name prefixed message to standard error, followed by
+# a configuration failure hint, and exit.
+func_fatal_configuration ()
+{
+ func_error ${1+"$@"}
+ func_error "See the $PACKAGE documentation for more information."
+ func_fatal_error "Fatal configuration error."
+}
+
+
+# func_config
+# Display the configuration for all the tags in this script.
+func_config ()
+{
+ re_begincf='^# ### BEGIN LIBTOOL'
+ re_endcf='^# ### END LIBTOOL'
+
+ # Default configuration.
+ $SED "1,/$re_begincf CONFIG/d;/$re_endcf CONFIG/,\$d" < "$progpath"
+
+ # Now print the configurations for the tags.
+ for tagname in $taglist; do
+ $SED -n "/$re_begincf TAG CONFIG: $tagname\$/,/$re_endcf TAG CONFIG: $tagname\$/p" < "$progpath"
+ done
+
+ exit $?
+}
+
+# func_features
+# Display the features supported by this script.
+func_features ()
+{
+ echo "host: $host"
+ if test "$build_libtool_libs" = yes; then
+ echo "enable shared libraries"
+ else
+ echo "disable shared libraries"
+ fi
+ if test "$build_old_libs" = yes; then
+ echo "enable static libraries"
+ else
+ echo "disable static libraries"
+ fi
+
+ exit $?
+}
+
+# func_enable_tag tagname
+# Verify that TAGNAME is valid, and either flag an error and exit, or
+# enable the TAGNAME tag. We also add TAGNAME to the global $taglist
+# variable here.
+func_enable_tag ()
+{
+ # Global variable:
+ tagname="$1"
+
+ re_begincf="^# ### BEGIN LIBTOOL TAG CONFIG: $tagname\$"
+ re_endcf="^# ### END LIBTOOL TAG CONFIG: $tagname\$"
+ sed_extractcf="/$re_begincf/,/$re_endcf/p"
+
+ # Validate tagname.
+ case $tagname in
+ *[!-_A-Za-z0-9,/]*)
+ func_fatal_error "invalid tag name: $tagname"
+ ;;
+ esac
+
+ # Don't test for the "default" C tag, as we know it's
+ # there but not specially marked.
+ case $tagname in
+ CC) ;;
+ *)
+ if $GREP "$re_begincf" "$progpath" >/dev/null 2>&1; then
+ taglist="$taglist $tagname"
+
+ # Evaluate the configuration. Be careful to quote the path
+ # and the sed script, to avoid splitting on whitespace, but
+ # also don't use non-portable quotes within backquotes within
+ # quotes we have to do it in 2 steps:
+ extractedcf=`$SED -n -e "$sed_extractcf" < "$progpath"`
+ eval "$extractedcf"
+ else
+ func_error "ignoring unknown tag $tagname"
+ fi
+ ;;
+ esac
+}
+
+# func_check_version_match
+# Ensure that we are using m4 macros, and libtool script from the same
+# release of libtool.
+func_check_version_match ()
+{
+ if test "$package_revision" != "$macro_revision"; then
+ if test "$VERSION" != "$macro_version"; then
+ if test -z "$macro_version"; then
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from an older release.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, but the
+$progname: definition of this LT_INIT comes from $PACKAGE $macro_version.
+$progname: You should recreate aclocal.m4 with macros from $PACKAGE $VERSION
+$progname: and run autoconf again.
+_LT_EOF
+ fi
+ else
+ cat >&2 <<_LT_EOF
+$progname: Version mismatch error. This is $PACKAGE $VERSION, revision $package_revision,
+$progname: but the definition of this LT_INIT comes from revision $macro_revision.
+$progname: You should recreate aclocal.m4 with macros from revision $package_revision
+$progname: of $PACKAGE $VERSION and run autoconf again.
+_LT_EOF
+ fi
+
+ exit $EXIT_MISMATCH
+ fi
+}
+
+
+# Shorthand for --mode=foo, only valid as the first argument
+case $1 in
+clean|clea|cle|cl)
+ shift; set dummy --mode clean ${1+"$@"}; shift
+ ;;
+compile|compil|compi|comp|com|co|c)
+ shift; set dummy --mode compile ${1+"$@"}; shift
+ ;;
+execute|execut|execu|exec|exe|ex|e)
+ shift; set dummy --mode execute ${1+"$@"}; shift
+ ;;
+finish|finis|fini|fin|fi|f)
+ shift; set dummy --mode finish ${1+"$@"}; shift
+ ;;
+install|instal|insta|inst|ins|in|i)
+ shift; set dummy --mode install ${1+"$@"}; shift
+ ;;
+link|lin|li|l)
+ shift; set dummy --mode link ${1+"$@"}; shift
+ ;;
+uninstall|uninstal|uninsta|uninst|unins|unin|uni|un|u)
+ shift; set dummy --mode uninstall ${1+"$@"}; shift
+ ;;
+esac
+
+
+
+# Option defaults:
+opt_debug=:
+opt_dry_run=false
+opt_config=false
+opt_preserve_dup_deps=false
+opt_features=false
+opt_finish=false
+opt_help=false
+opt_help_all=false
+opt_silent=:
+opt_warning=:
+opt_verbose=:
+opt_silent=false
+opt_verbose=false
+
+
+# Parse options once, thoroughly. This comes as soon as possible in the
+# script to make things like `--version' happen as quickly as we can.
+{
+ # this just eases exit handling
+ while test $# -gt 0; do
+ opt="$1"
+ shift
+ case $opt in
+ --debug|-x) opt_debug='set -x'
+ func_echo "enabling shell trace mode"
+ $opt_debug
+ ;;
+ --dry-run|--dryrun|-n)
+ opt_dry_run=:
+ ;;
+ --config)
+ opt_config=:
+func_config
+ ;;
+ --dlopen|-dlopen)
+ optarg="$1"
+ opt_dlopen="${opt_dlopen+$opt_dlopen
+}$optarg"
+ shift
+ ;;
+ --preserve-dup-deps)
+ opt_preserve_dup_deps=:
+ ;;
+ --features)
+ opt_features=:
+func_features
+ ;;
+ --finish)
+ opt_finish=:
+set dummy --mode finish ${1+"$@"}; shift
+ ;;
+ --help)
+ opt_help=:
+ ;;
+ --help-all)
+ opt_help_all=:
+opt_help=': help-all'
+ ;;
+ --mode)
+ test $# = 0 && func_missing_arg $opt && break
+ optarg="$1"
+ opt_mode="$optarg"
+case $optarg in
+ # Valid mode arguments:
+ clean|compile|execute|finish|install|link|relink|uninstall) ;;
+
+ # Catch anything else as an error
+ *) func_error "invalid argument for $opt"
+ exit_cmd=exit
+ break
+ ;;
+esac
+ shift
+ ;;
+ --no-silent|--no-quiet)
+ opt_silent=false
+func_append preserve_args " $opt"
+ ;;
+ --no-warning|--no-warn)
+ opt_warning=false
+func_append preserve_args " $opt"
+ ;;
+ --no-verbose)
+ opt_verbose=false
+func_append preserve_args " $opt"
+ ;;
+ --silent|--quiet)
+ opt_silent=:
+func_append preserve_args " $opt"
+ opt_verbose=false
+ ;;
+ --verbose|-v)
+ opt_verbose=:
+func_append preserve_args " $opt"
+opt_silent=false
+ ;;
+ --tag)
+ test $# = 0 && func_missing_arg $opt && break
+ optarg="$1"
+ opt_tag="$optarg"
+func_append preserve_args " $opt $optarg"
+func_enable_tag "$optarg"
+ shift
+ ;;
+
+ -\?|-h) func_usage ;;
+ --help) func_help ;;
+ --version) func_version ;;
+
+ # Separate optargs to long options:
+ --*=*)
+ func_split_long_opt "$opt"
+ set dummy "$func_split_long_opt_name" "$func_split_long_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ # Separate non-argument short options:
+ -\?*|-h*|-n*|-v*)
+ func_split_short_opt "$opt"
+ set dummy "$func_split_short_opt_name" "-$func_split_short_opt_arg" ${1+"$@"}
+ shift
+ ;;
+
+ --) break ;;
+ -*) func_fatal_help "unrecognized option \`$opt'" ;;
+ *) set dummy "$opt" ${1+"$@"}; shift; break ;;
+ esac
+ done
+
+ # Validate options:
+
+ # save first non-option argument
+ if test "$#" -gt 0; then
+ nonopt="$opt"
+ shift
+ fi
+
+ # preserve --debug
+ test "$opt_debug" = : || func_append preserve_args " --debug"
+
+ case $host in
+ *cygwin* | *mingw* | *pw32* | *cegcc*)
+ # don't eliminate duplications in $postdeps and $predeps
+ opt_duplicate_compiler_generated_deps=:
+ ;;
+ *)
+ opt_duplicate_compiler_generated_deps=$opt_preserve_dup_deps
+ ;;
+ esac
+
+ $opt_help || {
+ # Sanity checks first:
+ func_check_version_match
+
+ if test "$build_libtool_libs" != yes && test "$build_old_libs" != yes; then
+ func_fatal_configuration "not configured to build any kind of library"
+ fi
+
+ # Darwin sucks
+ eval std_shrext=\"$shrext_cmds\"
+
+ # Only execute mode is allowed to have -dlopen flags.
+ if test -n "$opt_dlopen" && test "$opt_mode" != execute; then
+ func_error "unrecognized option \`-dlopen'"
+ $ECHO "$help" 1>&2
+ exit $EXIT_FAILURE
+ fi
+
+ # Change the help message to a mode-specific one.
+ generic_help="$help"
+ help="Try \`$progname --help --mode=$opt_mode' for more information."
+ }
+
+
+ # Bail if the options were screwed
+ $exit_cmd $EXIT_FAILURE
+}
+
+
+
+
+## ----------- ##
+## Main. ##
+## ----------- ##
+
+# func_lalib_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_lalib_p ()
+{
+ test -f "$1" &&
+ $SED -e 4q "$1" 2>/dev/null \
+ | $GREP "^# Generated by .*$PACKAGE" > /dev/null 2>&1
+}
+
+# func_lalib_unsafe_p file
+# True iff FILE is a libtool `.la' library or `.lo' object file.
+# This function implements the same check as func_lalib_p without
+# resorting to external programs. To this end, it redirects stdin and
+# closes it afterwards, without saving the original file descriptor.
+# As a safety measure, use it only where a negative result would be
+# fatal anyway. Works if `file' does not exist.
+func_lalib_unsafe_p ()
+{
+ lalib_p=no
+ if test -f "$1" && test -r "$1" && exec 5<&0 <"$1"; then
+ for lalib_p_l in 1 2 3 4
+ do
+ read lalib_p_line
+ case "$lalib_p_line" in
+ \#\ Generated\ by\ *$PACKAGE* ) lalib_p=yes; break;;
+ esac
+ done
+ exec 0<&5 5<&-
+ fi
+ test "$lalib_p" = yes
+}
+
+# func_ltwrapper_script_p file
+# True iff FILE is a libtool wrapper script
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_script_p ()
+{
+ func_lalib_p "$1"
+}
+
+# func_ltwrapper_executable_p file
+# True iff FILE is a libtool wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_executable_p ()
+{
+ func_ltwrapper_exec_suffix=
+ case $1 in
+ *.exe) ;;
+ *) func_ltwrapper_exec_suffix=.exe ;;
+ esac
+ $GREP "$magic_exe" "$1$func_ltwrapper_exec_suffix" >/dev/null 2>&1
+}
+
+# func_ltwrapper_scriptname file
+# Assumes file is an ltwrapper_executable
+# uses $file to determine the appropriate filename for a
+# temporary ltwrapper_script.
+func_ltwrapper_scriptname ()
+{
+ func_dirname_and_basename "$1" "" "."
+ func_stripname '' '.exe' "$func_basename_result"
+ func_ltwrapper_scriptname_result="$func_dirname_result/$objdir/${func_stripname_result}_ltshwrapper"
+}
+
+# func_ltwrapper_p file
+# True iff FILE is a libtool wrapper script or wrapper executable
+# This function is only a basic sanity check; it will hardly flush out
+# determined imposters.
+func_ltwrapper_p ()
+{
+ func_ltwrapper_script_p "$1" || func_ltwrapper_executable_p "$1"
+}
+
+
+# func_execute_cmds commands fail_cmd
+# Execute tilde-delimited COMMANDS.
+# If FAIL_CMD is given, eval that upon failure.
+# FAIL_CMD may read-access the current command in variable CMD!
+func_execute_cmds ()
+{
+ $opt_debug
+ save_ifs=$IFS; IFS='~'
+ for cmd in $1; do
+ IFS=$save_ifs
+ eval cmd=\"$cmd\"
+ func_show_eval "$cmd" "${2-:}"
+ done
+ IFS=$save_ifs
+}
+
+
+# func_source file
+# Source FILE, adding directory component if necessary.
+# Note that it is not necessary on cygwin/mingw to append a dot to
+# FILE even if both FILE and FILE.exe exist: automatic-append-.exe
+# behavior happens only for exec(3), not for open(2)! Also, sourcing
+# `FILE.' does not work on cygwin managed mounts.
+func_source ()
+{
+ $opt_debug
+ case $1 in
+ */* | *\\*) . "$1" ;;
+ *) . "./$1" ;;
+ esac
+}
+
+
+# func_resolve_sysroot PATH
+# Replace a leading = in PATH with a sysroot. Store the result into
+# func_resolve_sysroot_result
+func_resolve_sysroot ()
+{
+ func_resolve_sysroot_result=$1
+ case $func_resolve_sysroot_result in
+ =*)
+ func_stripname '=' '' "$func_resolve_sysroot_result"
+ func_resolve_sysroot_result=$lt_sysroot$func_stripname_result
+ ;;
+ esac
+}
+
+# func_replace_sysroot PATH
+# If PATH begins with the sysroot, replace it with = and
+# store the result into func_replace_sysroot_result.
+func_replace_sysroot ()
+{
+ case "$lt_sysroot:$1" in
+ ?*:"$lt_sysroot"*)
+ func_stripname "$lt_sysroot" '' "$1"
+ func_replace_sysroot_result="=$func_stripname_result"
+ ;;
+ *)
+ # Including no sysroot.
+ func_replace_sysroot_result=$1
+ ;;
+ esac
+}
+
+# func_infer_tag arg
+# Infer tagged configuration to use if any are available and
+# if one wasn't chosen via the "--tag" command line option.
+# Only attempt this if the compiler in the base compile
+# command doesn't match the default compiler.
+# arg is usually of the form 'gcc ...'
+func_infer_tag ()
+{
+ $opt_debug
+ if test -n "$available_tags" && test -z "$tagname"; then
+ CC_quoted=
+ for arg in $CC; do
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case $@ in
+ # Blanks in the command may have been stripped by the calling shell,
+ # but not from the CC environment variable when configure was run.
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*) ;;
+ # Blanks at the start of $base_compile will cause this to fail
+ # if we don't check for them as well.
+ *)
+ for z in $available_tags; do
+ if $GREP "^# ### BEGIN LIBTOOL TAG CONFIG: $z$" < "$progpath" > /dev/null; then
+ # Evaluate the configuration.
+ eval "`${SED} -n -e '/^# ### BEGIN LIBTOOL TAG CONFIG: '$z'$/,/^# ### END LIBTOOL TAG CONFIG: '$z'$/p' < $progpath`"
+ CC_quoted=
+ for arg in $CC; do
+ # Double-quote args containing other shell metacharacters.
+ func_append_quoted CC_quoted "$arg"
+ done
+ CC_expanded=`func_echo_all $CC`
+ CC_quoted_expanded=`func_echo_all $CC_quoted`
+ case "$@ " in
+ " $CC "* | "$CC "* | " $CC_expanded "* | "$CC_expanded "* | \
+ " $CC_quoted"* | "$CC_quoted "* | " $CC_quoted_expanded "* | "$CC_quoted_expanded "*)
+ # The compiler in the base compile command matches
+ # the one in the tagged configuration.
+ # Assume this is the tagged configuration we want.
+ tagname=$z
+ break
+ ;;
+ esac
+ fi
+ done
+ # If $tagname still isn't set, then no tagged configuration
+ # was found and let the user know that the "--tag" command
+ # line option must be used.
+ if test -z "$tagname"; then
+ func_echo "unable to infer tagged configuration"
+ func_fatal_error "specify a tag with \`--tag'"
+# else
+# func_verbose "using $tagname tagged configuration"
+ fi
+ ;;
+ esac
+ fi
+}
+
+
+
+# func_write_libtool_object output_name pic_name nonpic_name
+# Create a libtool object file (analogous to a ".la" file),
+# but don't create it if we're doing a dry run.
+func_write_libtool_object ()
+{
+ write_libobj=${1}
+ if test "$build_libtool_libs" = yes; then
+ write_lobj=\'${2}\'
+ else
+ write_lobj=none
+ fi
+
+ if test "$build_old_libs" = yes; then
+ write_oldobj=\'${3}\'
+ else
+ write_oldobj=none
+ fi
+
+ $opt_dry_run || {
+ cat >${write_libobj}T <<EOF
+# $write_libobj - a libtool object file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# Name of the PIC object.
+pic_object=$write_lobj
+
+# Name of the non-PIC object
+non_pic_object=$write_oldobj
+
+EOF
+ $MV "${write_libobj}T" "${write_libobj}"
+ }
+}
+
+
+##################################################
+# FILE NAME AND PATH CONVERSION HELPER FUNCTIONS #
+##################################################
+
+# func_convert_core_file_wine_to_w32 ARG
+# Helper function used by file name conversion functions when $build is *nix,
+# and $host is mingw, cygwin, or some other w32 environment. Relies on a
+# correctly configured wine environment available, with the winepath program
+# in $build's $PATH.
+#
+# ARG is the $build file name to be converted to w32 format.
+# Result is available in $func_convert_core_file_wine_to_w32_result, and will
+# be empty on error (or when ARG is empty)
+func_convert_core_file_wine_to_w32 ()
+{
+ $opt_debug
+ func_convert_core_file_wine_to_w32_result="$1"
+ if test -n "$1"; then
+ # Unfortunately, winepath does not exit with a non-zero error code, so we
+ # are forced to check the contents of stdout. On the other hand, if the
+ # command is not found, the shell will set an exit code of 127 and print
+ # *an error message* to stdout. So we must check for both error code of
+ # zero AND non-empty stdout, which explains the odd construction:
+ func_convert_core_file_wine_to_w32_tmp=`winepath -w "$1" 2>/dev/null`
+ if test "$?" -eq 0 && test -n "${func_convert_core_file_wine_to_w32_tmp}"; then
+ func_convert_core_file_wine_to_w32_result=`$ECHO "$func_convert_core_file_wine_to_w32_tmp" |
+ $SED -e "$lt_sed_naive_backslashify"`
+ else
+ func_convert_core_file_wine_to_w32_result=
+ fi
+ fi
+}
+# end: func_convert_core_file_wine_to_w32
+
+
+# func_convert_core_path_wine_to_w32 ARG
+# Helper function used by path conversion functions when $build is *nix, and
+# $host is mingw, cygwin, or some other w32 environment. Relies on a correctly
+# configured wine environment available, with the winepath program in $build's
+# $PATH. Assumes ARG has no leading or trailing path separator characters.
+#
+# ARG is path to be converted from $build format to win32.
+# Result is available in $func_convert_core_path_wine_to_w32_result.
+# Unconvertible file (directory) names in ARG are skipped; if no directory names
+# are convertible, then the result may be empty.
+func_convert_core_path_wine_to_w32 ()
+{
+ $opt_debug
+ # unfortunately, winepath doesn't convert paths, only file names
+ func_convert_core_path_wine_to_w32_result=""
+ if test -n "$1"; then
+ oldIFS=$IFS
+ IFS=:
+ for func_convert_core_path_wine_to_w32_f in $1; do
+ IFS=$oldIFS
+ func_convert_core_file_wine_to_w32 "$func_convert_core_path_wine_to_w32_f"
+ if test -n "$func_convert_core_file_wine_to_w32_result" ; then
+ if test -z "$func_convert_core_path_wine_to_w32_result"; then
+ func_convert_core_path_wine_to_w32_result="$func_convert_core_file_wine_to_w32_result"
+ else
+ func_append func_convert_core_path_wine_to_w32_result ";$func_convert_core_file_wine_to_w32_result"
+ fi
+ fi
+ done
+ IFS=$oldIFS
+ fi
+}
+# end: func_convert_core_path_wine_to_w32
+
+
+# func_cygpath ARGS...
+# Wrapper around calling the cygpath program via LT_CYGPATH. This is used when
+# when (1) $build is *nix and Cygwin is hosted via a wine environment; or (2)
+# $build is MSYS and $host is Cygwin, or (3) $build is Cygwin. In case (1) or
+# (2), returns the Cygwin file name or path in func_cygpath_result (input
+# file name or path is assumed to be in w32 format, as previously converted
+# from $build's *nix or MSYS format). In case (3), returns the w32 file name
+# or path in func_cygpath_result (input file name or path is assumed to be in
+# Cygwin format). Returns an empty string on error.
+#
+# ARGS are passed to cygpath, with the last one being the file name or path to
+# be converted.
+#
+# Specify the absolute *nix (or w32) name to cygpath in the LT_CYGPATH
+# environment variable; do not put it in $PATH.
+func_cygpath ()
+{
+ $opt_debug
+ if test -n "$LT_CYGPATH" && test -f "$LT_CYGPATH"; then
+ func_cygpath_result=`$LT_CYGPATH "$@" 2>/dev/null`
+ if test "$?" -ne 0; then
+ # on failure, ensure result is empty
+ func_cygpath_result=
+ fi
+ else
+ func_cygpath_result=
+ func_error "LT_CYGPATH is empty or specifies non-existent file: \`$LT_CYGPATH'"
+ fi
+}
+#end: func_cygpath
+
+
+# func_convert_core_msys_to_w32 ARG
+# Convert file name or path ARG from MSYS format to w32 format. Return
+# result in func_convert_core_msys_to_w32_result.
+func_convert_core_msys_to_w32 ()
+{
+ $opt_debug
+ # awkward: cmd appends spaces to result
+ func_convert_core_msys_to_w32_result=`( cmd //c echo "$1" ) 2>/dev/null |
+ $SED -e 's/[ ]*$//' -e "$lt_sed_naive_backslashify"`
+}
+#end: func_convert_core_msys_to_w32
+
+
+# func_convert_file_check ARG1 ARG2
+# Verify that ARG1 (a file name in $build format) was converted to $host
+# format in ARG2. Otherwise, emit an error message, but continue (resetting
+# func_to_host_file_result to ARG1).
+func_convert_file_check ()
+{
+ $opt_debug
+ if test -z "$2" && test -n "$1" ; then
+ func_error "Could not determine host file name corresponding to"
+ func_error " \`$1'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback:
+ func_to_host_file_result="$1"
+ fi
+}
+# end func_convert_file_check
+
+
+# func_convert_path_check FROM_PATHSEP TO_PATHSEP FROM_PATH TO_PATH
+# Verify that FROM_PATH (a path in $build format) was converted to $host
+# format in TO_PATH. Otherwise, emit an error message, but continue, resetting
+# func_to_host_file_result to a simplistic fallback value (see below).
+func_convert_path_check ()
+{
+ $opt_debug
+ if test -z "$4" && test -n "$3"; then
+ func_error "Could not determine the host path corresponding to"
+ func_error " \`$3'"
+ func_error "Continuing, but uninstalled executables may not work."
+ # Fallback. This is a deliberately simplistic "conversion" and
+ # should not be "improved". See libtool.info.
+ if test "x$1" != "x$2"; then
+ lt_replace_pathsep_chars="s|$1|$2|g"
+ func_to_host_path_result=`echo "$3" |
+ $SED -e "$lt_replace_pathsep_chars"`
+ else
+ func_to_host_path_result="$3"
+ fi
+ fi
+}
+# end func_convert_path_check
+
+
+# func_convert_path_front_back_pathsep FRONTPAT BACKPAT REPL ORIG
+# Modifies func_to_host_path_result by prepending REPL if ORIG matches FRONTPAT
+# and appending REPL if ORIG matches BACKPAT.
+func_convert_path_front_back_pathsep ()
+{
+ $opt_debug
+ case $4 in
+ $1 ) func_to_host_path_result="$3$func_to_host_path_result"
+ ;;
+ esac
+ case $4 in
+ $2 ) func_append func_to_host_path_result "$3"
+ ;;
+ esac
+}
+# end func_convert_path_front_back_pathsep
+
+
+##################################################
+# $build to $host FILE NAME CONVERSION FUNCTIONS #
+##################################################
+# invoked via `$to_host_file_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# Result will be available in $func_to_host_file_result.
+
+
+# func_to_host_file ARG
+# Converts the file name ARG from $build format to $host format. Return result
+# in func_to_host_file_result.
+func_to_host_file ()
+{
+ $opt_debug
+ $to_host_file_cmd "$1"
+}
+# end func_to_host_file
+
+
+# func_to_tool_file ARG LAZY
+# converts the file name ARG from $build format to toolchain format. Return
+# result in func_to_tool_file_result. If the conversion in use is listed
+# in (the comma separated) LAZY, no conversion takes place.
+func_to_tool_file ()
+{
+ $opt_debug
+ case ,$2, in
+ *,"$to_tool_file_cmd",*)
+ func_to_tool_file_result=$1
+ ;;
+ *)
+ $to_tool_file_cmd "$1"
+ func_to_tool_file_result=$func_to_host_file_result
+ ;;
+ esac
+}
+# end func_to_tool_file
+
+
+# func_convert_file_noop ARG
+# Copy ARG to func_to_host_file_result.
+func_convert_file_noop ()
+{
+ func_to_host_file_result="$1"
+}
+# end func_convert_file_noop
+
+
+# func_convert_file_msys_to_w32 ARG
+# Convert file name ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_file_result.
+func_convert_file_msys_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_to_host_file_result="$func_convert_core_msys_to_w32_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_w32
+
+
+# func_convert_file_cygwin_to_w32 ARG
+# Convert file name ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_file_cygwin_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ # because $build is cygwin, we call "the" cygpath in $PATH; no need to use
+ # LT_CYGPATH in this case.
+ func_to_host_file_result=`cygpath -m "$1"`
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_cygwin_to_w32
+
+
+# func_convert_file_nix_to_w32 ARG
+# Convert file name ARG from *nix to w32 format. Requires a wine environment
+# and a working winepath. Returns result in func_to_host_file_result.
+func_convert_file_nix_to_w32 ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_file_wine_to_w32 "$1"
+ func_to_host_file_result="$func_convert_core_file_wine_to_w32_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_w32
+
+
+# func_convert_file_msys_to_cygwin ARG
+# Convert file name ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_file_msys_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ func_convert_core_msys_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_msys_to_w32_result"
+ func_to_host_file_result="$func_cygpath_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_msys_to_cygwin
+
+
+# func_convert_file_nix_to_cygwin ARG
+# Convert file name ARG from *nix to Cygwin format. Requires Cygwin installed
+# in a wine environment, working winepath, and LT_CYGPATH set. Returns result
+# in func_to_host_file_result.
+func_convert_file_nix_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_file_result="$1"
+ if test -n "$1"; then
+ # convert from *nix to w32, then use cygpath to convert from w32 to cygwin.
+ func_convert_core_file_wine_to_w32 "$1"
+ func_cygpath -u "$func_convert_core_file_wine_to_w32_result"
+ func_to_host_file_result="$func_cygpath_result"
+ fi
+ func_convert_file_check "$1" "$func_to_host_file_result"
+}
+# end func_convert_file_nix_to_cygwin
+
+
+#############################################
+# $build to $host PATH CONVERSION FUNCTIONS #
+#############################################
+# invoked via `$to_host_path_cmd ARG'
+#
+# In each case, ARG is the path to be converted from $build to $host format.
+# The result will be available in $func_to_host_path_result.
+#
+# Path separators are also converted from $build format to $host format. If
+# ARG begins or ends with a path separator character, it is preserved (but
+# converted to $host format) on output.
+#
+# All path conversion functions are named using the following convention:
+# file name conversion function : func_convert_file_X_to_Y ()
+# path conversion function : func_convert_path_X_to_Y ()
+# where, for any given $build/$host combination the 'X_to_Y' value is the
+# same. If conversion functions are added for new $build/$host combinations,
+# the two new functions must follow this pattern, or func_init_to_host_path_cmd
+# will break.
+
+
+# func_init_to_host_path_cmd
+# Ensures that function "pointer" variable $to_host_path_cmd is set to the
+# appropriate value, based on the value of $to_host_file_cmd.
+to_host_path_cmd=
+func_init_to_host_path_cmd ()
+{
+ $opt_debug
+ if test -z "$to_host_path_cmd"; then
+ func_stripname 'func_convert_file_' '' "$to_host_file_cmd"
+ to_host_path_cmd="func_convert_path_${func_stripname_result}"
+ fi
+}
+
+
+# func_to_host_path ARG
+# Converts the path ARG from $build format to $host format. Return result
+# in func_to_host_path_result.
+func_to_host_path ()
+{
+ $opt_debug
+ func_init_to_host_path_cmd
+ $to_host_path_cmd "$1"
+}
+# end func_to_host_path
+
+
+# func_convert_path_noop ARG
+# Copy ARG to func_to_host_path_result.
+func_convert_path_noop ()
+{
+ func_to_host_path_result="$1"
+}
+# end func_convert_path_noop
+
+
+# func_convert_path_msys_to_w32 ARG
+# Convert path ARG from (mingw) MSYS to (mingw) w32 format; automatic
+# conversion to w32 is not available inside the cwrapper. Returns result in
+# func_to_host_path_result.
+func_convert_path_msys_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from ARG. MSYS
+ # behavior is inconsistent here; cygpath turns them into '.;' and ';.';
+ # and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result="$func_convert_core_msys_to_w32_result"
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_msys_to_w32
+
+
+# func_convert_path_cygwin_to_w32 ARG
+# Convert path ARG from Cygwin to w32 format. Returns result in
+# func_to_host_file_result.
+func_convert_path_cygwin_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_to_host_path_result=`cygpath -m -p "$func_to_host_path_tmp1"`
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_cygwin_to_w32
+
+
+# func_convert_path_nix_to_w32 ARG
+# Convert path ARG from *nix to w32 format. Requires a wine environment and
+# a working winepath. Returns result in func_to_host_file_result.
+func_convert_path_nix_to_w32 ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_to_host_path_result="$func_convert_core_path_wine_to_w32_result"
+ func_convert_path_check : ";" \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" ";" "$1"
+ fi
+}
+# end func_convert_path_nix_to_w32
+
+
+# func_convert_path_msys_to_cygwin ARG
+# Convert path ARG from MSYS to Cygwin format. Requires LT_CYGPATH set.
+# Returns result in func_to_host_file_result.
+func_convert_path_msys_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # See func_convert_path_msys_to_w32:
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_msys_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_msys_to_w32_result"
+ func_to_host_path_result="$func_cygpath_result"
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_msys_to_cygwin
+
+
+# func_convert_path_nix_to_cygwin ARG
+# Convert path ARG from *nix to Cygwin format. Requires Cygwin installed in a
+# a wine environment, working winepath, and LT_CYGPATH set. Returns result in
+# func_to_host_file_result.
+func_convert_path_nix_to_cygwin ()
+{
+ $opt_debug
+ func_to_host_path_result="$1"
+ if test -n "$1"; then
+ # Remove leading and trailing path separator characters from
+ # ARG. msys behavior is inconsistent here, cygpath turns them
+ # into '.;' and ';.', and winepath ignores them completely.
+ func_stripname : : "$1"
+ func_to_host_path_tmp1=$func_stripname_result
+ func_convert_core_path_wine_to_w32 "$func_to_host_path_tmp1"
+ func_cygpath -u -p "$func_convert_core_path_wine_to_w32_result"
+ func_to_host_path_result="$func_cygpath_result"
+ func_convert_path_check : : \
+ "$func_to_host_path_tmp1" "$func_to_host_path_result"
+ func_convert_path_front_back_pathsep ":*" "*:" : "$1"
+ fi
+}
+# end func_convert_path_nix_to_cygwin
+
+
+# func_mode_compile arg...
+func_mode_compile ()
+{
+ $opt_debug
+ # Get the compilation command and the source file.
+ base_compile=
+ srcfile="$nonopt" # always keep a non-empty value in "srcfile"
+ suppress_opt=yes
+ suppress_output=
+ arg_mode=normal
+ libobj=
+ later=
+ pie_flag=
+
+ for arg
+ do
+ case $arg_mode in
+ arg )
+ # do not "continue". Instead, add this to base_compile
+ lastarg="$arg"
+ arg_mode=normal
+ ;;
+
+ target )
+ libobj="$arg"
+ arg_mode=normal
+ continue
+ ;;
+
+ normal )
+ # Accept any command-line options.
+ case $arg in
+ -o)
+ test -n "$libobj" && \
+ func_fatal_error "you cannot specify \`-o' more than once"
+ arg_mode=target
+ continue
+ ;;
+
+ -pie | -fpie | -fPIE)
+ func_append pie_flag " $arg"
+ continue
+ ;;
+
+ -shared | -static | -prefer-pic | -prefer-non-pic)
+ func_append later " $arg"
+ continue
+ ;;
+
+ -no-suppress)
+ suppress_opt=no
+ continue
+ ;;
+
+ -Xcompiler)
+ arg_mode=arg # the next one goes into the "base_compile" arg list
+ continue # The current "srcfile" will either be retained or
+ ;; # replaced later. I would guess that would be a bug.
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ lastarg=
+ save_ifs="$IFS"; IFS=','
+ for arg in $args; do
+ IFS="$save_ifs"
+ func_append_quoted lastarg "$arg"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$lastarg"
+ lastarg=$func_stripname_result
+
+ # Add the arguments to base_compile.
+ func_append base_compile " $lastarg"
+ continue
+ ;;
+
+ *)
+ # Accept the current argument as the source file.
+ # The previous "srcfile" becomes the current argument.
+ #
+ lastarg="$srcfile"
+ srcfile="$arg"
+ ;;
+ esac # case $arg
+ ;;
+ esac # case $arg_mode
+
+ # Aesthetically quote the previous argument.
+ func_append_quoted base_compile "$lastarg"
+ done # for arg
+
+ case $arg_mode in
+ arg)
+ func_fatal_error "you must specify an argument for -Xcompile"
+ ;;
+ target)
+ func_fatal_error "you must specify a target with \`-o'"
+ ;;
+ *)
+ # Get the name of the library object.
+ test -z "$libobj" && {
+ func_basename "$srcfile"
+ libobj="$func_basename_result"
+ }
+ ;;
+ esac
+
+ # Recognize several different file suffixes.
+ # If the user specifies -o file.o, it is replaced with file.lo
+ case $libobj in
+ *.[cCFSifmso] | \
+ *.ada | *.adb | *.ads | *.asm | \
+ *.c++ | *.cc | *.ii | *.class | *.cpp | *.cxx | \
+ *.[fF][09]? | *.for | *.java | *.go | *.obj | *.sx | *.cu | *.cup)
+ func_xform "$libobj"
+ libobj=$func_xform_result
+ ;;
+ esac
+
+ case $libobj in
+ *.lo) func_lo2o "$libobj"; obj=$func_lo2o_result ;;
+ *)
+ func_fatal_error "cannot determine name of library object from \`$libobj'"
+ ;;
+ esac
+
+ func_infer_tag $base_compile
+
+ for arg in $later; do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ continue
+ ;;
+
+ -static)
+ build_libtool_libs=no
+ build_old_libs=yes
+ continue
+ ;;
+
+ -prefer-pic)
+ pic_mode=yes
+ continue
+ ;;
+
+ -prefer-non-pic)
+ pic_mode=no
+ continue
+ ;;
+ esac
+ done
+
+ func_quote_for_eval "$libobj"
+ test "X$libobj" != "X$func_quote_for_eval_result" \
+ && $ECHO "X$libobj" | $GREP '[]~#^*{};<>?"'"'"' &()|`$[]' \
+ && func_warning "libobj name \`$libobj' may not contain shell special characters."
+ func_dirname_and_basename "$obj" "/" ""
+ objname="$func_basename_result"
+ xdir="$func_dirname_result"
+ lobj=${xdir}$objdir/$objname
+
+ test -z "$base_compile" && \
+ func_fatal_help "you must specify a compilation command"
+
+ # Delete any leftover library objects.
+ if test "$build_old_libs" = yes; then
+ removelist="$obj $lobj $libobj ${libobj}T"
+ else
+ removelist="$lobj $libobj ${libobj}T"
+ fi
+
+ # On Cygwin there's no "real" PIC flag so we must build both object types
+ case $host_os in
+ cygwin* | mingw* | pw32* | os2* | cegcc*)
+ pic_mode=default
+ ;;
+ esac
+ if test "$pic_mode" = no && test "$deplibs_check_method" != pass_all; then
+ # non-PIC code in shared libraries is not supported
+ pic_mode=default
+ fi
+
+ # Calculate the filename of the output object if compiler does
+ # not support -o with -c
+ if test "$compiler_c_o" = no; then
+ output_obj=`$ECHO "$srcfile" | $SED 's%^.*/%%; s%\.[^.]*$%%'`.${objext}
+ lockfile="$output_obj.lock"
+ else
+ output_obj=
+ need_locks=no
+ lockfile=
+ fi
+
+ # Lock this critical section if it is needed
+ # We use this script file to make the link, it avoids creating a new file
+ if test "$need_locks" = yes; then
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ elif test "$need_locks" = warn; then
+ if test -f "$lockfile"; then
+ $ECHO "\
+*** ERROR, $lockfile exists and contains:
+`cat $lockfile 2>/dev/null`
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+ func_append removelist " $output_obj"
+ $ECHO "$srcfile" > "$lockfile"
+ fi
+
+ $opt_dry_run || $RM $removelist
+ func_append removelist " $lockfile"
+ trap '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE' 1 2 15
+
+ func_to_tool_file "$srcfile" func_convert_file_msys_to_w32
+ srcfile=$func_to_tool_file_result
+ func_quote_for_eval "$srcfile"
+ qsrcfile=$func_quote_for_eval_result
+
+ # Only build a PIC object if we are building libtool libraries.
+ if test "$build_libtool_libs" = yes; then
+ # Without this assignment, base_compile gets emptied.
+ fbsd_hideous_sh_bug=$base_compile
+
+ if test "$pic_mode" != no; then
+ command="$base_compile $qsrcfile $pic_flag"
+ else
+ # Don't build PIC code
+ command="$base_compile $qsrcfile"
+ fi
+
+ func_mkdir_p "$xdir$objdir"
+
+ if test -z "$output_obj"; then
+ # Place PIC objects in $objdir
+ func_append command " -o $lobj"
+ fi
+
+ func_show_eval_locale "$command" \
+ 'test -n "$output_obj" && $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed, then go on to compile the next one
+ if test -n "$output_obj" && test "X$output_obj" != "X$lobj"; then
+ func_show_eval '$MV "$output_obj" "$lobj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+
+ # Allow error messages only from the first compilation.
+ if test "$suppress_opt" = yes; then
+ suppress_output=' >/dev/null 2>&1'
+ fi
+ fi
+
+ # Only build a position-dependent object if we build old libraries.
+ if test "$build_old_libs" = yes; then
+ if test "$pic_mode" != yes; then
+ # Don't build PIC code
+ command="$base_compile $qsrcfile$pie_flag"
+ else
+ command="$base_compile $qsrcfile $pic_flag"
+ fi
+ if test "$compiler_c_o" = yes; then
+ func_append command " -o $obj"
+ fi
+
+ # Suppress compiler output if we already did a PIC compilation.
+ func_append command "$suppress_output"
+ func_show_eval_locale "$command" \
+ '$opt_dry_run || $RM $removelist; exit $EXIT_FAILURE'
+
+ if test "$need_locks" = warn &&
+ test "X`cat $lockfile 2>/dev/null`" != "X$srcfile"; then
+ $ECHO "\
+*** ERROR, $lockfile contains:
+`cat $lockfile 2>/dev/null`
+
+but it should contain:
+$srcfile
+
+This indicates that another process is trying to use the same
+temporary object file, and libtool could not work around it because
+your compiler does not support \`-c' and \`-o' together. If you
+repeat this compilation, it may succeed, by chance, but you had better
+avoid parallel builds (make -j) in this platform, or get a better
+compiler."
+
+ $opt_dry_run || $RM $removelist
+ exit $EXIT_FAILURE
+ fi
+
+ # Just move the object if needed
+ if test -n "$output_obj" && test "X$output_obj" != "X$obj"; then
+ func_show_eval '$MV "$output_obj" "$obj"' \
+ 'error=$?; $opt_dry_run || $RM $removelist; exit $error'
+ fi
+ fi
+
+ $opt_dry_run || {
+ func_write_libtool_object "$libobj" "$objdir/$objname" "$objname"
+
+ # Unlock the critical section if it was locked
+ if test "$need_locks" != no; then
+ removelist=$lockfile
+ $RM "$lockfile"
+ fi
+ }
+
+ exit $EXIT_SUCCESS
+}
+
+$opt_help || {
+ test "$opt_mode" = compile && func_mode_compile ${1+"$@"}
+}
+
+func_mode_help ()
+{
+ # We need to display help for each of the modes.
+ case $opt_mode in
+ "")
+ # Generic help is extracted from the usage comments
+ # at the start of this file.
+ func_help
+ ;;
+
+ clean)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=clean RM [RM-OPTION]... FILE...
+
+Remove files from the build directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, object or program, all the files associated
+with it are deleted. Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ compile)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=compile COMPILE-COMMAND... SOURCEFILE
+
+Compile a source file into a libtool library object.
+
+This mode accepts the following additional options:
+
+ -o OUTPUT-FILE set the output file name to OUTPUT-FILE
+ -no-suppress do not suppress compiler output for multiple passes
+ -prefer-pic try to build PIC objects only
+ -prefer-non-pic try to build non-PIC objects only
+ -shared do not build a \`.o' file suitable for static linking
+ -static only build a \`.o' file suitable for static linking
+ -Wc,FLAG pass FLAG directly to the compiler
+
+COMPILE-COMMAND is a command to be used in creating a \`standard' object file
+from the given SOURCEFILE.
+
+The output file name is determined by removing the directory component from
+SOURCEFILE, then substituting the C source code suffix \`.c' with the
+library object suffix, \`.lo'."
+ ;;
+
+ execute)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=execute COMMAND [ARGS]...
+
+Automatically set library path, then run a program.
+
+This mode accepts the following additional options:
+
+ -dlopen FILE add the directory containing FILE to the library path
+
+This mode sets the library path environment variable according to \`-dlopen'
+flags.
+
+If any of the ARGS are libtool executable wrappers, then they are translated
+into their corresponding uninstalled binary, and any of their required library
+directories are added to the library path.
+
+Then, COMMAND is executed, with ARGS as arguments."
+ ;;
+
+ finish)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=finish [LIBDIR]...
+
+Complete the installation of libtool libraries.
+
+Each LIBDIR is a directory that contains libtool libraries.
+
+The commands that this mode executes may require superuser privileges. Use
+the \`--dry-run' option if you just want to see what would be executed."
+ ;;
+
+ install)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=install INSTALL-COMMAND...
+
+Install executables or libraries.
+
+INSTALL-COMMAND is the installation command. The first component should be
+either the \`install' or \`cp' program.
+
+The following components of INSTALL-COMMAND are treated specially:
+
+ -inst-prefix-dir PREFIX-DIR Use PREFIX-DIR as a staging area for installation
+
+The rest of the components are interpreted as arguments to that command (only
+BSD-compatible install options are recognized)."
+ ;;
+
+ link)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=link LINK-COMMAND...
+
+Link object files or libraries together to form another library, or to
+create an executable program.
+
+LINK-COMMAND is a command using the C compiler that you would use to create
+a program from several object files.
+
+The following components of LINK-COMMAND are treated specially:
+
+ -all-static do not do any dynamic linking at all
+ -avoid-version do not add a version suffix if possible
+ -bindir BINDIR specify path to binaries directory (for systems where
+ libraries must be found in the PATH setting at runtime)
+ -dlopen FILE \`-dlpreopen' FILE if it cannot be dlopened at runtime
+ -dlpreopen FILE link in FILE and add its symbols to lt_preloaded_symbols
+ -export-dynamic allow symbols from OUTPUT-FILE to be resolved with dlsym(3)
+ -export-symbols SYMFILE
+ try to export only the symbols listed in SYMFILE
+ -export-symbols-regex REGEX
+ try to export only the symbols matching REGEX
+ -LLIBDIR search LIBDIR for required installed libraries
+ -lNAME OUTPUT-FILE requires the installed library libNAME
+ -module build a library that can dlopened
+ -no-fast-install disable the fast-install mode
+ -no-install link a not-installable executable
+ -no-undefined declare that a library does not refer to external symbols
+ -o OUTPUT-FILE create OUTPUT-FILE from the specified objects
+ -objectlist FILE Use a list of object files found in FILE to specify objects
+ -precious-files-regex REGEX
+ don't remove output files matching REGEX
+ -release RELEASE specify package release information
+ -rpath LIBDIR the created library will eventually be installed in LIBDIR
+ -R[ ]LIBDIR add LIBDIR to the runtime path of programs and libraries
+ -shared only do dynamic linking of libtool libraries
+ -shrext SUFFIX override the standard shared library file extension
+ -static do not do any dynamic linking of uninstalled libtool libraries
+ -static-libtool-libs
+ do not do any dynamic linking of libtool libraries
+ -version-info CURRENT[:REVISION[:AGE]]
+ specify library version info [each variable defaults to 0]
+ -weak LIBNAME declare that the target provides the LIBNAME interface
+ -Wc,FLAG
+ -Xcompiler FLAG pass linker-specific FLAG directly to the compiler
+ -Wl,FLAG
+ -Xlinker FLAG pass linker-specific FLAG directly to the linker
+ -XCClinker FLAG pass link-specific FLAG to the compiler driver (CC)
+
+All other options (arguments beginning with \`-') are ignored.
+
+Every other argument is treated as a filename. Files ending in \`.la' are
+treated as uninstalled libtool libraries, other files are standard or library
+object files.
+
+If the OUTPUT-FILE ends in \`.la', then a libtool library is created,
+only library objects (\`.lo' files) may be specified, and \`-rpath' is
+required, except when creating a convenience library.
+
+If OUTPUT-FILE ends in \`.a' or \`.lib', then a standard library is created
+using \`ar' and \`ranlib', or on Windows using \`lib'.
+
+If OUTPUT-FILE ends in \`.lo' or \`.${objext}', then a reloadable object file
+is created, otherwise an executable program is created."
+ ;;
+
+ uninstall)
+ $ECHO \
+"Usage: $progname [OPTION]... --mode=uninstall RM [RM-OPTION]... FILE...
+
+Remove libraries from an installation directory.
+
+RM is the name of the program to use to delete files associated with each FILE
+(typically \`/bin/rm'). RM-OPTIONS are options (such as \`-f') to be passed
+to RM.
+
+If FILE is a libtool library, all the files associated with it are deleted.
+Otherwise, only FILE itself is deleted using RM."
+ ;;
+
+ *)
+ func_fatal_help "invalid operation mode \`$opt_mode'"
+ ;;
+ esac
+
+ echo
+ $ECHO "Try \`$progname --help' for more information about other modes."
+}
+
+# Now that we've collected a possible --mode arg, show help if necessary
+if $opt_help; then
+ if test "$opt_help" = :; then
+ func_mode_help
+ else
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ func_mode_help
+ done
+ } | sed -n '1p; 2,$s/^Usage:/ or: /p'
+ {
+ func_help noexit
+ for opt_mode in compile link execute install finish uninstall clean; do
+ echo
+ func_mode_help
+ done
+ } |
+ sed '1d
+ /^When reporting/,/^Report/{
+ H
+ d
+ }
+ $x
+ /information about other modes/d
+ /more detailed .*MODE/d
+ s/^Usage:.*--mode=\([^ ]*\) .*/Description of \1 mode:/'
+ fi
+ exit $?
+fi
+
+
+# func_mode_execute arg...
+func_mode_execute ()
+{
+ $opt_debug
+ # The first argument is the command name.
+ cmd="$nonopt"
+ test -z "$cmd" && \
+ func_fatal_help "you must specify a COMMAND"
+
+ # Handle -dlopen flags immediately.
+ for file in $opt_dlopen; do
+ test -f "$file" \
+ || func_fatal_help "\`$file' is not a file"
+
+ dir=
+ case $file in
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$lib' is not a valid libtool archive"
+
+ # Read the libtool library.
+ dlname=
+ library_names=
+ func_source "$file"
+
+ # Skip this library if it cannot be dlopened.
+ if test -z "$dlname"; then
+ # Warn if it was a shared library.
+ test -n "$library_names" && \
+ func_warning "\`$file' was not linked with \`-export-dynamic'"
+ continue
+ fi
+
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+
+ if test -f "$dir/$objdir/$dlname"; then
+ func_append dir "/$objdir"
+ else
+ if test ! -f "$dir/$dlname"; then
+ func_fatal_error "cannot find \`$dlname' in \`$dir' or \`$dir/$objdir'"
+ fi
+ fi
+ ;;
+
+ *.lo)
+ # Just add the directory containing the .lo file.
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ ;;
+
+ *)
+ func_warning "\`-dlopen' is ignored for non-libtool libraries and objects"
+ continue
+ ;;
+ esac
+
+ # Get the absolute pathname.
+ absdir=`cd "$dir" && pwd`
+ test -n "$absdir" && dir="$absdir"
+
+ # Now add the directory to shlibpath_var.
+ if eval "test -z \"\$$shlibpath_var\""; then
+ eval "$shlibpath_var=\"\$dir\""
+ else
+ eval "$shlibpath_var=\"\$dir:\$$shlibpath_var\""
+ fi
+ done
+
+ # This variable tells wrapper scripts just to set shlibpath_var
+ # rather than running their programs.
+ libtool_execute_magic="$magic"
+
+ # Check if any of the arguments is a wrapper script.
+ args=
+ for file
+ do
+ case $file in
+ -* | *.la | *.lo ) ;;
+ *)
+ # Do a test to see if this is really a libtool program.
+ if func_ltwrapper_script_p "$file"; then
+ func_source "$file"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ elif func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ func_source "$func_ltwrapper_scriptname_result"
+ # Transform arg to wrapped name.
+ file="$progdir/$program"
+ fi
+ ;;
+ esac
+ # Quote arguments (to preserve shell metacharacters).
+ func_append_quoted args "$file"
+ done
+
+ if test "X$opt_dry_run" = Xfalse; then
+ if test -n "$shlibpath_var"; then
+ # Export the shlibpath_var.
+ eval "export $shlibpath_var"
+ fi
+
+ # Restore saved environment variables
+ for lt_var in LANG LANGUAGE LC_ALL LC_CTYPE LC_COLLATE LC_MESSAGES
+ do
+ eval "if test \"\${save_$lt_var+set}\" = set; then
+ $lt_var=\$save_$lt_var; export $lt_var
+ else
+ $lt_unset $lt_var
+ fi"
+ done
+
+ # Now prepare to actually exec the command.
+ exec_cmd="\$cmd$args"
+ else
+ # Display what would be done.
+ if test -n "$shlibpath_var"; then
+ eval "\$ECHO \"\$shlibpath_var=\$$shlibpath_var\""
+ echo "export $shlibpath_var"
+ fi
+ $ECHO "$cmd$args"
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$opt_mode" = execute && func_mode_execute ${1+"$@"}
+
+
+# func_mode_finish arg...
+func_mode_finish ()
+{
+ $opt_debug
+ libs=
+ libdirs=
+ admincmds=
+
+ for opt in "$nonopt" ${1+"$@"}
+ do
+ if test -d "$opt"; then
+ func_append libdirs " $opt"
+
+ elif test -f "$opt"; then
+ if func_lalib_unsafe_p "$opt"; then
+ func_append libs " $opt"
+ else
+ func_warning "\`$opt' is not a valid libtool archive"
+ fi
+
+ else
+ func_fatal_error "invalid argument \`$opt'"
+ fi
+ done
+
+ if test -n "$libs"; then
+ if test -n "$lt_sysroot"; then
+ sysroot_regex=`$ECHO "$lt_sysroot" | $SED "$sed_make_literal_regex"`
+ sysroot_cmd="s/\([ ']\)$sysroot_regex/\1/g;"
+ else
+ sysroot_cmd=
+ fi
+
+ # Remove sysroot references
+ if $opt_dry_run; then
+ for lib in $libs; do
+ echo "removing references to $lt_sysroot and \`=' prefixes from $lib"
+ done
+ else
+ tmpdir=`func_mktempdir`
+ for lib in $libs; do
+ sed -e "${sysroot_cmd} s/\([ ']-[LR]\)=/\1/g; s/\([ ']\)=/\1/g" $lib \
+ > $tmpdir/tmp-la
+ mv -f $tmpdir/tmp-la $lib
+ done
+ ${RM}r "$tmpdir"
+ fi
+ fi
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ for libdir in $libdirs; do
+ if test -n "$finish_cmds"; then
+ # Do each command in the finish commands.
+ func_execute_cmds "$finish_cmds" 'admincmds="$admincmds
+'"$cmd"'"'
+ fi
+ if test -n "$finish_eval"; then
+ # Do the single finish_eval.
+ eval cmds=\"$finish_eval\"
+ $opt_dry_run || eval "$cmds" || func_append admincmds "
+ $cmds"
+ fi
+ done
+ fi
+
+ # Exit here if they wanted silent mode.
+ $opt_silent && exit $EXIT_SUCCESS
+
+ if test -n "$finish_cmds$finish_eval" && test -n "$libdirs"; then
+ echo "----------------------------------------------------------------------"
+ echo "Libraries have been installed in:"
+ for libdir in $libdirs; do
+ $ECHO " $libdir"
+ done
+ echo
+ echo "If you ever happen to want to link against installed libraries"
+ echo "in a given directory, LIBDIR, you must either use libtool, and"
+ echo "specify the full pathname of the library, or use the \`-LLIBDIR'"
+ echo "flag during linking and do at least one of the following:"
+ if test -n "$shlibpath_var"; then
+ echo " - add LIBDIR to the \`$shlibpath_var' environment variable"
+ echo " during execution"
+ fi
+ if test -n "$runpath_var"; then
+ echo " - add LIBDIR to the \`$runpath_var' environment variable"
+ echo " during linking"
+ fi
+ if test -n "$hardcode_libdir_flag_spec"; then
+ libdir=LIBDIR
+ eval flag=\"$hardcode_libdir_flag_spec\"
+
+ $ECHO " - use the \`$flag' linker flag"
+ fi
+ if test -n "$admincmds"; then
+ $ECHO " - have your system administrator run these commands:$admincmds"
+ fi
+ if test -f /etc/ld.so.conf; then
+ echo " - have your system administrator add LIBDIR to \`/etc/ld.so.conf'"
+ fi
+ echo
+
+ echo "See any operating system documentation about shared libraries for"
+ case $host in
+ solaris2.[6789]|solaris2.1[0-9])
+ echo "more information, such as the ld(1), crle(1) and ld.so(8) manual"
+ echo "pages."
+ ;;
+ *)
+ echo "more information, such as the ld(1) and ld.so(8) manual pages."
+ ;;
+ esac
+ echo "----------------------------------------------------------------------"
+ fi
+ exit $EXIT_SUCCESS
+}
+
+test "$opt_mode" = finish && func_mode_finish ${1+"$@"}
+
+
+# func_mode_install arg...
+func_mode_install ()
+{
+ $opt_debug
+ # There may be an optional sh(1) argument at the beginning of
+ # install_prog (especially on Windows NT).
+ if test "$nonopt" = "$SHELL" || test "$nonopt" = /bin/sh ||
+ # Allow the use of GNU shtool's install command.
+ case $nonopt in *shtool*) :;; *) false;; esac; then
+ # Aesthetically quote it.
+ func_quote_for_eval "$nonopt"
+ install_prog="$func_quote_for_eval_result "
+ arg=$1
+ shift
+ else
+ install_prog=
+ arg=$nonopt
+ fi
+
+ # The real first argument should be the name of the installation program.
+ # Aesthetically quote it.
+ func_quote_for_eval "$arg"
+ func_append install_prog "$func_quote_for_eval_result"
+ install_shared_prog=$install_prog
+ case " $install_prog " in
+ *[\\\ /]cp\ *) install_cp=: ;;
+ *) install_cp=false ;;
+ esac
+
+ # We need to accept at least all the BSD install flags.
+ dest=
+ files=
+ opts=
+ prev=
+ install_type=
+ isdir=no
+ stripme=
+ no_mode=:
+ for arg
+ do
+ arg2=
+ if test -n "$dest"; then
+ func_append files " $dest"
+ dest=$arg
+ continue
+ fi
+
+ case $arg in
+ -d) isdir=yes ;;
+ -f)
+ if $install_cp; then :; else
+ prev=$arg
+ fi
+ ;;
+ -g | -m | -o)
+ prev=$arg
+ ;;
+ -s)
+ stripme=" -s"
+ continue
+ ;;
+ -*)
+ ;;
+ *)
+ # If the previous option needed an argument, then skip it.
+ if test -n "$prev"; then
+ if test "x$prev" = x-m && test -n "$install_override_mode"; then
+ arg2=$install_override_mode
+ no_mode=false
+ fi
+ prev=
+ else
+ dest=$arg
+ continue
+ fi
+ ;;
+ esac
+
+ # Aesthetically quote the argument.
+ func_quote_for_eval "$arg"
+ func_append install_prog " $func_quote_for_eval_result"
+ if test -n "$arg2"; then
+ func_quote_for_eval "$arg2"
+ fi
+ func_append install_shared_prog " $func_quote_for_eval_result"
+ done
+
+ test -z "$install_prog" && \
+ func_fatal_help "you must specify an install program"
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prev' option requires an argument"
+
+ if test -n "$install_override_mode" && $no_mode; then
+ if $install_cp; then :; else
+ func_quote_for_eval "$install_override_mode"
+ func_append install_shared_prog " -m $func_quote_for_eval_result"
+ fi
+ fi
+
+ if test -z "$files"; then
+ if test -z "$dest"; then
+ func_fatal_help "no file or destination specified"
+ else
+ func_fatal_help "you must specify a destination"
+ fi
+ fi
+
+ # Strip any trailing slash from the destination.
+ func_stripname '' '/' "$dest"
+ dest=$func_stripname_result
+
+ # Check to see that the destination is a directory.
+ test -d "$dest" && isdir=yes
+ if test "$isdir" = yes; then
+ destdir="$dest"
+ destname=
+ else
+ func_dirname_and_basename "$dest" "" "."
+ destdir="$func_dirname_result"
+ destname="$func_basename_result"
+
+ # Not a directory, so check to see that there is only one file specified.
+ set dummy $files; shift
+ test "$#" -gt 1 && \
+ func_fatal_help "\`$dest' is not a directory"
+ fi
+ case $destdir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ for file in $files; do
+ case $file in
+ *.lo) ;;
+ *)
+ func_fatal_help "\`$destdir' must be an absolute directory name"
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ staticlibs=
+ future_libdirs=
+ current_libdirs=
+ for file in $files; do
+
+ # Do each installation.
+ case $file in
+ *.$libext)
+ # Do the static libraries later.
+ func_append staticlibs " $file"
+ ;;
+
+ *.la)
+ func_resolve_sysroot "$file"
+ file=$func_resolve_sysroot_result
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$file" \
+ || func_fatal_help "\`$file' is not a valid libtool archive"
+
+ library_names=
+ old_library=
+ relink_command=
+ func_source "$file"
+
+ # Add the libdir to current_libdirs if it is the destination.
+ if test "X$destdir" = "X$libdir"; then
+ case "$current_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append current_libdirs " $libdir" ;;
+ esac
+ else
+ # Note the libdir as a future libdir.
+ case "$future_libdirs " in
+ *" $libdir "*) ;;
+ *) func_append future_libdirs " $libdir" ;;
+ esac
+ fi
+
+ func_dirname "$file" "/" ""
+ dir="$func_dirname_result"
+ func_append dir "$objdir"
+
+ if test -n "$relink_command"; then
+ # Determine the prefix the user has applied to our future dir.
+ inst_prefix_dir=`$ECHO "$destdir" | $SED -e "s%$libdir\$%%"`
+
+ # Don't allow the user to place us outside of our expected
+ # location b/c this prevents finding dependent libraries that
+ # are installed to the same prefix.
+ # At present, this check doesn't affect windows .dll's that
+ # are installed into $libdir/../bin (currently, that works fine)
+ # but it's something to keep an eye on.
+ test "$inst_prefix_dir" = "$destdir" && \
+ func_fatal_error "error: cannot install \`$file' to a directory not ending in $libdir"
+
+ if test -n "$inst_prefix_dir"; then
+ # Stick the inst_prefix_dir data into the link command.
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%-inst-prefix-dir $inst_prefix_dir%"`
+ else
+ relink_command=`$ECHO "$relink_command" | $SED "s%@inst_prefix_dir@%%"`
+ fi
+
+ func_warning "relinking \`$file'"
+ func_show_eval "$relink_command" \
+ 'func_fatal_error "error: relink \`$file'\'' with the above command before installing it"'
+ fi
+
+ # See the names of the shared library.
+ set dummy $library_names; shift
+ if test -n "$1"; then
+ realname="$1"
+ shift
+
+ srcname="$realname"
+ test -n "$relink_command" && srcname="$realname"T
+
+ # Install the shared library and build the symlinks.
+ func_show_eval "$install_shared_prog $dir/$srcname $destdir/$realname" \
+ 'exit $?'
+ tstripme="$stripme"
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $realname in
+ *.dll.a)
+ tstripme=""
+ ;;
+ esac
+ ;;
+ esac
+ if test -n "$tstripme" && test -n "$striplib"; then
+ func_show_eval "$striplib $destdir/$realname" 'exit $?'
+ fi
+
+ if test "$#" -gt 0; then
+ # Delete the old symlinks, and create new ones.
+ # Try `ln -sf' first, because the `ln' binary might depend on
+ # the symlink we replace! Solaris /bin/ln does not understand -f,
+ # so we also need to try rm && ln -s.
+ for linkname
+ do
+ test "$linkname" != "$realname" \
+ && func_show_eval "(cd $destdir && { $LN_S -f $realname $linkname || { $RM $linkname && $LN_S $realname $linkname; }; })"
+ done
+ fi
+
+ # Do each command in the postinstall commands.
+ lib="$destdir/$realname"
+ func_execute_cmds "$postinstall_cmds" 'exit $?'
+ fi
+
+ # Install the pseudo-library for information purposes.
+ func_basename "$file"
+ name="$func_basename_result"
+ instname="$dir/$name"i
+ func_show_eval "$install_prog $instname $destdir/$name" 'exit $?'
+
+ # Maybe install the static library, too.
+ test -n "$old_library" && func_append staticlibs " $dir/$old_library"
+ ;;
+
+ *.lo)
+ # Install (i.e. copy) a libtool object.
+
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # Deduce the name of the destination old-style object file.
+ case $destfile in
+ *.lo)
+ func_lo2o "$destfile"
+ staticdest=$func_lo2o_result
+ ;;
+ *.$objext)
+ staticdest="$destfile"
+ destfile=
+ ;;
+ *)
+ func_fatal_help "cannot copy a libtool object to \`$destfile'"
+ ;;
+ esac
+
+ # Install the libtool object if requested.
+ test -n "$destfile" && \
+ func_show_eval "$install_prog $file $destfile" 'exit $?'
+
+ # Install the old object if enabled.
+ if test "$build_old_libs" = yes; then
+ # Deduce the name of the old-style object file.
+ func_lo2o "$file"
+ staticobj=$func_lo2o_result
+ func_show_eval "$install_prog \$staticobj \$staticdest" 'exit $?'
+ fi
+ exit $EXIT_SUCCESS
+ ;;
+
+ *)
+ # Figure out destination file name, if it wasn't already specified.
+ if test -n "$destname"; then
+ destfile="$destdir/$destname"
+ else
+ func_basename "$file"
+ destfile="$func_basename_result"
+ destfile="$destdir/$destfile"
+ fi
+
+ # If the file is missing, and there is a .exe on the end, strip it
+ # because it is most likely a libtool script we actually want to
+ # install
+ stripped_ext=""
+ case $file in
+ *.exe)
+ if test ! -f "$file"; then
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ stripped_ext=".exe"
+ fi
+ ;;
+ esac
+
+ # Do a test to see if this is really a libtool program.
+ case $host in
+ *cygwin* | *mingw*)
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ wrapper=$func_ltwrapper_scriptname_result
+ else
+ func_stripname '' '.exe' "$file"
+ wrapper=$func_stripname_result
+ fi
+ ;;
+ *)
+ wrapper=$file
+ ;;
+ esac
+ if func_ltwrapper_script_p "$wrapper"; then
+ notinst_deplibs=
+ relink_command=
+
+ func_source "$wrapper"
+
+ # Check the variables that should have been set.
+ test -z "$generated_by_libtool_version" && \
+ func_fatal_error "invalid libtool wrapper script \`$wrapper'"
+
+ finalize=yes
+ for lib in $notinst_deplibs; do
+ # Check to see that each library is installed.
+ libdir=
+ if test -f "$lib"; then
+ func_source "$lib"
+ fi
+ libfile="$libdir/"`$ECHO "$lib" | $SED 's%^.*/%%g'` ### testsuite: skip nested quoting test
+ if test -n "$libdir" && test ! -f "$libfile"; then
+ func_warning "\`$lib' has not been installed in \`$libdir'"
+ finalize=no
+ fi
+ done
+
+ relink_command=
+ func_source "$wrapper"
+
+ outputname=
+ if test "$fast_install" = no && test -n "$relink_command"; then
+ $opt_dry_run || {
+ if test "$finalize" = yes; then
+ tmpdir=`func_mktempdir`
+ func_basename "$file$stripped_ext"
+ file="$func_basename_result"
+ outputname="$tmpdir/$file"
+ # Replace the output file specification.
+ relink_command=`$ECHO "$relink_command" | $SED 's%@OUTPUT@%'"$outputname"'%g'`
+
+ $opt_silent || {
+ func_quote_for_expand "$relink_command"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ if eval "$relink_command"; then :
+ else
+ func_error "error: relink \`$file' with the above command before installing it"
+ $opt_dry_run || ${RM}r "$tmpdir"
+ continue
+ fi
+ file="$outputname"
+ else
+ func_warning "cannot relink \`$file'"
+ fi
+ }
+ else
+ # Install the binary that we compiled earlier.
+ file=`$ECHO "$file$stripped_ext" | $SED "s%\([^/]*\)$%$objdir/\1%"`
+ fi
+ fi
+
+ # remove .exe since cygwin /usr/bin/install will append another
+ # one anyway
+ case $install_prog,$host in
+ */usr/bin/install*,*cygwin*)
+ case $file:$destfile in
+ *.exe:*.exe)
+ # this is ok
+ ;;
+ *.exe:*)
+ destfile=$destfile.exe
+ ;;
+ *:*.exe)
+ func_stripname '' '.exe' "$destfile"
+ destfile=$func_stripname_result
+ ;;
+ esac
+ ;;
+ esac
+ func_show_eval "$install_prog\$stripme \$file \$destfile" 'exit $?'
+ $opt_dry_run || if test -n "$outputname"; then
+ ${RM}r "$tmpdir"
+ fi
+ ;;
+ esac
+ done
+
+ for file in $staticlibs; do
+ func_basename "$file"
+ name="$func_basename_result"
+
+ # Set up the ranlib parameters.
+ oldlib="$destdir/$name"
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+
+ func_show_eval "$install_prog \$file \$oldlib" 'exit $?'
+
+ if test -n "$stripme" && test -n "$old_striplib"; then
+ func_show_eval "$old_striplib $tool_oldlib" 'exit $?'
+ fi
+
+ # Do each command in the postinstall commands.
+ func_execute_cmds "$old_postinstall_cmds" 'exit $?'
+ done
+
+ test -n "$future_libdirs" && \
+ func_warning "remember to run \`$progname --finish$future_libdirs'"
+
+ if test -n "$current_libdirs"; then
+ # Maybe just do a dry run.
+ $opt_dry_run && current_libdirs=" -n$current_libdirs"
+ exec_cmd='$SHELL $progpath $preserve_args --finish$current_libdirs'
+ else
+ exit $EXIT_SUCCESS
+ fi
+}
+
+test "$opt_mode" = install && func_mode_install ${1+"$@"}
+
+
+# func_generate_dlsyms outputname originator pic_p
+# Extract symbols from dlprefiles and create ${outputname}S.o with
+# a dlpreopen symbol table.
+func_generate_dlsyms ()
+{
+ $opt_debug
+ my_outputname="$1"
+ my_originator="$2"
+ my_pic_p="${3-no}"
+ my_prefix=`$ECHO "$my_originator" | sed 's%[^a-zA-Z0-9]%_%g'`
+ my_dlsyms=
+
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ if test -n "$NM" && test -n "$global_symbol_pipe"; then
+ my_dlsyms="${my_outputname}S.c"
+ else
+ func_error "not configured to extract global symbols from dlpreopened files"
+ fi
+ fi
+
+ if test -n "$my_dlsyms"; then
+ case $my_dlsyms in
+ "") ;;
+ *.c)
+ # Discover the nlist of each of the dlfiles.
+ nlist="$output_objdir/${my_outputname}.nm"
+
+ func_show_eval "$RM $nlist ${nlist}S ${nlist}T"
+
+ # Parse the name list into a source file.
+ func_verbose "creating $output_objdir/$my_dlsyms"
+
+ $opt_dry_run || $ECHO > "$output_objdir/$my_dlsyms" "\
+/* $my_dlsyms - symbol resolution table for \`$my_outputname' dlsym emulation. */
+/* Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION */
+
+#ifdef __cplusplus
+extern \"C\" {
+#endif
+
+#if defined(__GNUC__) && (((__GNUC__ == 4) && (__GNUC_MINOR__ >= 4)) || (__GNUC__ > 4))
+#pragma GCC diagnostic ignored \"-Wstrict-prototypes\"
+#endif
+
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+/* External symbol declarations for the compiler. */\
+"
+
+ if test "$dlself" = yes; then
+ func_verbose "generating symbol list for \`$output'"
+
+ $opt_dry_run || echo ': @PROGRAM@ ' > "$nlist"
+
+ # Add our own program objects to the symbol list.
+ progfiles=`$ECHO "$objs$old_deplibs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ for progfile in $progfiles; do
+ func_to_tool_file "$progfile" func_convert_file_msys_to_w32
+ func_verbose "extracting global C symbols from \`$func_to_tool_file_result'"
+ $opt_dry_run || eval "$NM $func_to_tool_file_result | $global_symbol_pipe >> '$nlist'"
+ done
+
+ if test -n "$exclude_expsyms"; then
+ $opt_dry_run || {
+ eval '$EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ if test -n "$export_symbols_regex"; then
+ $opt_dry_run || {
+ eval '$EGREP -e "$export_symbols_regex" "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ }
+ fi
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ export_symbols="$output_objdir/$outputname.exp"
+ $opt_dry_run || {
+ $RM $export_symbols
+ eval "${SED} -n -e '/^: @PROGRAM@ $/d' -e 's/^.* \(.*\)$/\1/p' "'< "$nlist" > "$export_symbols"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$export_symbols" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ else
+ $opt_dry_run || {
+ eval "${SED} -e 's/\([].[*^$]\)/\\\\\1/g' -e 's/^/ /' -e 's/$/$/'"' < "$export_symbols" > "$output_objdir/$outputname.exp"'
+ eval '$GREP -f "$output_objdir/$outputname.exp" < "$nlist" > "$nlist"T'
+ eval '$MV "$nlist"T "$nlist"'
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ eval "echo EXPORTS "'> "$output_objdir/$outputname.def"'
+ eval 'cat "$nlist" >> "$output_objdir/$outputname.def"'
+ ;;
+ esac
+ }
+ fi
+ fi
+
+ for dlprefile in $dlprefiles; do
+ func_verbose "extracting global C symbols from \`$dlprefile'"
+ func_basename "$dlprefile"
+ name="$func_basename_result"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ # if an import library, we need to obtain dlname
+ if func_win32_import_lib_p "$dlprefile"; then
+ func_tr_sh "$dlprefile"
+ eval "curr_lafile=\$libfile_$func_tr_sh_result"
+ dlprefile_dlbasename=""
+ if test -n "$curr_lafile" && func_lalib_p "$curr_lafile"; then
+ # Use subshell, to avoid clobbering current variable values
+ dlprefile_dlname=`source "$curr_lafile" && echo "$dlname"`
+ if test -n "$dlprefile_dlname" ; then
+ func_basename "$dlprefile_dlname"
+ dlprefile_dlbasename="$func_basename_result"
+ else
+ # no lafile. user explicitly requested -dlpreopen <import library>.
+ $sharedlib_from_linklib_cmd "$dlprefile"
+ dlprefile_dlbasename=$sharedlib_from_linklib_result
+ fi
+ fi
+ $opt_dry_run || {
+ if test -n "$dlprefile_dlbasename" ; then
+ eval '$ECHO ": $dlprefile_dlbasename" >> "$nlist"'
+ else
+ func_warning "Could not compute DLL name from $name"
+ eval '$ECHO ": $name " >> "$nlist"'
+ fi
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe |
+ $SED -e '/I __imp/d' -e 's/I __nm_/D /;s/_nm__//' >> '$nlist'"
+ }
+ else # not an import lib
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ fi
+ ;;
+ *)
+ $opt_dry_run || {
+ eval '$ECHO ": $name " >> "$nlist"'
+ func_to_tool_file "$dlprefile" func_convert_file_msys_to_w32
+ eval "$NM \"$func_to_tool_file_result\" 2>/dev/null | $global_symbol_pipe >> '$nlist'"
+ }
+ ;;
+ esac
+ done
+
+ $opt_dry_run || {
+ # Make sure we have at least an empty file.
+ test -f "$nlist" || : > "$nlist"
+
+ if test -n "$exclude_expsyms"; then
+ $EGREP -v " ($exclude_expsyms)$" "$nlist" > "$nlist"T
+ $MV "$nlist"T "$nlist"
+ fi
+
+ # Try sorting and uniquifying the output.
+ if $GREP -v "^: " < "$nlist" |
+ if sort -k 3 </dev/null >/dev/null 2>&1; then
+ sort -k 3
+ else
+ sort +2
+ fi |
+ uniq > "$nlist"S; then
+ :
+ else
+ $GREP -v "^: " < "$nlist" > "$nlist"S
+ fi
+
+ if test -f "$nlist"S; then
+ eval "$global_symbol_to_cdecl"' < "$nlist"S >> "$output_objdir/$my_dlsyms"'
+ else
+ echo '/* NONE */' >> "$output_objdir/$my_dlsyms"
+ fi
+
+ echo >> "$output_objdir/$my_dlsyms" "\
+
+/* The mapping between symbol names and symbols. */
+typedef struct {
+ const char *name;
+ void *address;
+} lt_dlsymlist;
+extern LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[];
+LT_DLSYM_CONST lt_dlsymlist
+lt_${my_prefix}_LTX_preloaded_symbols[] =
+{\
+ { \"$my_originator\", (void *) 0 },"
+
+ case $need_lib_prefix in
+ no)
+ eval "$global_symbol_to_c_name_address" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ *)
+ eval "$global_symbol_to_c_name_address_lib_prefix" < "$nlist" >> "$output_objdir/$my_dlsyms"
+ ;;
+ esac
+ echo >> "$output_objdir/$my_dlsyms" "\
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt_${my_prefix}_LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif\
+"
+ } # !$opt_dry_run
+
+ pic_flag_for_symtable=
+ case "$compile_command " in
+ *" -static "*) ;;
+ *)
+ case $host in
+ # compiling the symbol table file with pic_flag works around
+ # a FreeBSD bug that causes programs to crash when -lm is
+ # linked before any other PIC object. But we must not use
+ # pic_flag when linking with -static. The problem exists in
+ # FreeBSD 2.2.6 and is fixed in FreeBSD 3.1.
+ *-*-freebsd2.*|*-*-freebsd3.0*|*-*-freebsdelf3.0*)
+ pic_flag_for_symtable=" $pic_flag -DFREEBSD_WORKAROUND" ;;
+ *-*-hpux*)
+ pic_flag_for_symtable=" $pic_flag" ;;
+ *)
+ if test "X$my_pic_p" != Xno; then
+ pic_flag_for_symtable=" $pic_flag"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ symtab_cflags=
+ for arg in $LTCFLAGS; do
+ case $arg in
+ -pie | -fpie | -fPIE) ;;
+ *) func_append symtab_cflags " $arg" ;;
+ esac
+ done
+
+ # Now compile the dynamic symbol file.
+ func_show_eval '(cd $output_objdir && $LTCC$symtab_cflags -c$no_builtin_flag$pic_flag_for_symtable "$my_dlsyms")' 'exit $?'
+
+ # Clean up the generated files.
+ func_show_eval '$RM "$output_objdir/$my_dlsyms" "$nlist" "${nlist}S" "${nlist}T"'
+
+ # Transform the symbol file into the correct name.
+ symfileobj="$output_objdir/${my_outputname}S.$objext"
+ case $host in
+ *cygwin* | *mingw* | *cegcc* )
+ if test -f "$output_objdir/$my_outputname.def"; then
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$output_objdir/$my_outputname.def $symfileobj%"`
+ else
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ fi
+ ;;
+ *)
+ compile_command=`$ECHO "$compile_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s%@SYMFILE@%$symfileobj%"`
+ ;;
+ esac
+ ;;
+ *)
+ func_fatal_error "unknown suffix for \`$my_dlsyms'"
+ ;;
+ esac
+ else
+ # We keep going just in case the user didn't refer to
+ # lt_preloaded_symbols. The linker will fail if global_symbol_pipe
+ # really was required.
+
+ # Nullify the symbol file.
+ compile_command=`$ECHO "$compile_command" | $SED "s% @SYMFILE@%%"`
+ finalize_command=`$ECHO "$finalize_command" | $SED "s% @SYMFILE@%%"`
+ fi
+}
+
+# func_win32_libid arg
+# return the library type of file 'arg'
+#
+# Need a lot of goo to handle *both* DLLs and import libs
+# Has to be a shell function in order to 'eat' the argument
+# that is supplied when $file_magic_command is called.
+# Despite the name, also deal with 64 bit binaries.
+func_win32_libid ()
+{
+ $opt_debug
+ win32_libid_type="unknown"
+ win32_fileres=`file -L $1 2>/dev/null`
+ case $win32_fileres in
+ *ar\ archive\ import\ library*) # definitely import
+ win32_libid_type="x86 archive import"
+ ;;
+ *ar\ archive*) # could be an import, or static
+ # Keep the egrep pattern in sync with the one in _LT_CHECK_MAGIC_METHOD.
+ if eval $OBJDUMP -f $1 | $SED -e '10q' 2>/dev/null |
+ $EGREP 'file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)' >/dev/null; then
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ win32_nmres=`eval $NM -f posix -A \"$func_to_tool_file_result\" |
+ $SED -n -e '
+ 1,100{
+ / I /{
+ s,.*,import,
+ p
+ q
+ }
+ }'`
+ case $win32_nmres in
+ import*) win32_libid_type="x86 archive import";;
+ *) win32_libid_type="x86 archive static";;
+ esac
+ fi
+ ;;
+ *DLL*)
+ win32_libid_type="x86 DLL"
+ ;;
+ *executable*) # but shell scripts are "executable" too...
+ case $win32_fileres in
+ *MS\ Windows\ PE\ Intel*)
+ win32_libid_type="x86 DLL"
+ ;;
+ esac
+ ;;
+ esac
+ $ECHO "$win32_libid_type"
+}
+
+# func_cygming_dll_for_implib ARG
+#
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib ()
+{
+ $opt_debug
+ sharedlib_from_linklib_result=`$DLLTOOL --identify-strict --identify "$1"`
+}
+
+# func_cygming_dll_for_implib_fallback_core SECTION_NAME LIBNAMEs
+#
+# The is the core of a fallback implementation of a
+# platform-specific function to extract the name of the
+# DLL associated with the specified import library LIBNAME.
+#
+# SECTION_NAME is either .idata$6 or .idata$7, depending
+# on the platform and compiler that created the implib.
+#
+# Echos the name of the DLL associated with the
+# specified import library.
+func_cygming_dll_for_implib_fallback_core ()
+{
+ $opt_debug
+ match_literal=`$ECHO "$1" | $SED "$sed_make_literal_regex"`
+ $OBJDUMP -s --section "$1" "$2" 2>/dev/null |
+ $SED '/^Contents of section '"$match_literal"':/{
+ # Place marker at beginning of archive member dllname section
+ s/.*/====MARK====/
+ p
+ d
+ }
+ # These lines can sometimes be longer than 43 characters, but
+ # are always uninteresting
+ /:[ ]*file format pe[i]\{,1\}-/d
+ /^In archive [^:]*:/d
+ # Ensure marker is printed
+ /^====MARK====/p
+ # Remove all lines with less than 43 characters
+ /^.\{43\}/!d
+ # From remaining lines, remove first 43 characters
+ s/^.\{43\}//' |
+ $SED -n '
+ # Join marker and all lines until next marker into a single line
+ /^====MARK====/ b para
+ H
+ $ b para
+ b
+ :para
+ x
+ s/\n//g
+ # Remove the marker
+ s/^====MARK====//
+ # Remove trailing dots and whitespace
+ s/[\. \t]*$//
+ # Print
+ /./p' |
+ # we now have a list, one entry per line, of the stringified
+ # contents of the appropriate section of all members of the
+ # archive which possess that section. Heuristic: eliminate
+ # all those which have a first or second character that is
+ # a '.' (that is, objdump's representation of an unprintable
+ # character.) This should work for all archives with less than
+ # 0x302f exports -- but will fail for DLLs whose name actually
+ # begins with a literal '.' or a single character followed by
+ # a '.'.
+ #
+ # Of those that remain, print the first one.
+ $SED -e '/^\./d;/^.\./d;q'
+}
+
+# func_cygming_gnu_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is a GNU/binutils-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_gnu_implib_p ()
+{
+ $opt_debug
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_gnu_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $EGREP ' (_head_[A-Za-z0-9_]+_[ad]l*|[A-Za-z0-9_]+_[ad]l*_iname)$'`
+ test -n "$func_cygming_gnu_implib_tmp"
+}
+
+# func_cygming_ms_implib_p ARG
+# This predicate returns with zero status (TRUE) if
+# ARG is an MS-style import library. Returns
+# with nonzero status (FALSE) otherwise.
+func_cygming_ms_implib_p ()
+{
+ $opt_debug
+ func_to_tool_file "$1" func_convert_file_msys_to_w32
+ func_cygming_ms_implib_tmp=`$NM "$func_to_tool_file_result" | eval "$global_symbol_pipe" | $GREP '_NULL_IMPORT_DESCRIPTOR'`
+ test -n "$func_cygming_ms_implib_tmp"
+}
+
+# func_cygming_dll_for_implib_fallback ARG
+# Platform-specific function to extract the
+# name of the DLL associated with the specified
+# import library ARG.
+#
+# This fallback implementation is for use when $DLLTOOL
+# does not support the --identify-strict option.
+# Invoked by eval'ing the libtool variable
+# $sharedlib_from_linklib_cmd
+# Result is available in the variable
+# $sharedlib_from_linklib_result
+func_cygming_dll_for_implib_fallback ()
+{
+ $opt_debug
+ if func_cygming_gnu_implib_p "$1" ; then
+ # binutils import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$7' "$1"`
+ elif func_cygming_ms_implib_p "$1" ; then
+ # ms-generated import library
+ sharedlib_from_linklib_result=`func_cygming_dll_for_implib_fallback_core '.idata$6' "$1"`
+ else
+ # unknown
+ sharedlib_from_linklib_result=""
+ fi
+}
+
+
+# func_extract_an_archive dir oldlib
+func_extract_an_archive ()
+{
+ $opt_debug
+ f_ex_an_ar_dir="$1"; shift
+ f_ex_an_ar_oldlib="$1"
+ if test "$lock_old_archive_extraction" = yes; then
+ lockfile=$f_ex_an_ar_oldlib.lock
+ until $opt_dry_run || ln "$progpath" "$lockfile" 2>/dev/null; do
+ func_echo "Waiting for $lockfile to be removed"
+ sleep 2
+ done
+ fi
+ func_show_eval "(cd \$f_ex_an_ar_dir && $AR x \"\$f_ex_an_ar_oldlib\")" \
+ 'stat=$?; rm -f "$lockfile"; exit $stat'
+ if test "$lock_old_archive_extraction" = yes; then
+ $opt_dry_run || rm -f "$lockfile"
+ fi
+ if ($AR t "$f_ex_an_ar_oldlib" | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ func_fatal_error "object name conflicts in archive: $f_ex_an_ar_dir/$f_ex_an_ar_oldlib"
+ fi
+}
+
+
+# func_extract_archives gentop oldlib ...
+func_extract_archives ()
+{
+ $opt_debug
+ my_gentop="$1"; shift
+ my_oldlibs=${1+"$@"}
+ my_oldobjs=""
+ my_xlib=""
+ my_xabs=""
+ my_xdir=""
+
+ for my_xlib in $my_oldlibs; do
+ # Extract the objects.
+ case $my_xlib in
+ [\\/]* | [A-Za-z]:[\\/]*) my_xabs="$my_xlib" ;;
+ *) my_xabs=`pwd`"/$my_xlib" ;;
+ esac
+ func_basename "$my_xlib"
+ my_xlib="$func_basename_result"
+ my_xlib_u=$my_xlib
+ while :; do
+ case " $extracted_archives " in
+ *" $my_xlib_u "*)
+ func_arith $extracted_serial + 1
+ extracted_serial=$func_arith_result
+ my_xlib_u=lt$extracted_serial-$my_xlib ;;
+ *) break ;;
+ esac
+ done
+ extracted_archives="$extracted_archives $my_xlib_u"
+ my_xdir="$my_gentop/$my_xlib_u"
+
+ func_mkdir_p "$my_xdir"
+
+ case $host in
+ *-darwin*)
+ func_verbose "Extracting $my_xabs"
+ # Do not bother doing anything if just a dry run
+ $opt_dry_run || {
+ darwin_orig_dir=`pwd`
+ cd $my_xdir || exit $?
+ darwin_archive=$my_xabs
+ darwin_curdir=`pwd`
+ darwin_base_archive=`basename "$darwin_archive"`
+ darwin_arches=`$LIPO -info "$darwin_archive" 2>/dev/null | $GREP Architectures 2>/dev/null || true`
+ if test -n "$darwin_arches"; then
+ darwin_arches=`$ECHO "$darwin_arches" | $SED -e 's/.*are://'`
+ darwin_arch=
+ func_verbose "$darwin_base_archive has multiple architectures $darwin_arches"
+ for darwin_arch in $darwin_arches ; do
+ func_mkdir_p "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ $LIPO -thin $darwin_arch -output "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}" "${darwin_archive}"
+ cd "unfat-$$/${darwin_base_archive}-${darwin_arch}"
+ func_extract_an_archive "`pwd`" "${darwin_base_archive}"
+ cd "$darwin_curdir"
+ $RM "unfat-$$/${darwin_base_archive}-${darwin_arch}/${darwin_base_archive}"
+ done # $darwin_arches
+ ## Okay now we've a bunch of thin objects, gotta fatten them up :)
+ darwin_filelist=`find unfat-$$ -type f -name \*.o -print -o -name \*.lo -print | $SED -e "$basename" | sort -u`
+ darwin_file=
+ darwin_files=
+ for darwin_file in $darwin_filelist; do
+ darwin_files=`find unfat-$$ -name $darwin_file -print | sort | $NL2SP`
+ $LIPO -create -output "$darwin_file" $darwin_files
+ done # $darwin_filelist
+ $RM -rf unfat-$$
+ cd "$darwin_orig_dir"
+ else
+ cd $darwin_orig_dir
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ fi # $darwin_arches
+ } # !$opt_dry_run
+ ;;
+ *)
+ func_extract_an_archive "$my_xdir" "$my_xabs"
+ ;;
+ esac
+ my_oldobjs="$my_oldobjs "`find $my_xdir -name \*.$objext -print -o -name \*.lo -print | sort | $NL2SP`
+ done
+
+ func_extract_archives_result="$my_oldobjs"
+}
+
+
+# func_emit_wrapper [arg=no]
+#
+# Emit a libtool wrapper script on stdout.
+# Don't directly open a file because we may want to
+# incorporate the script contents within a cygwin/mingw
+# wrapper executable. Must ONLY be called from within
+# func_mode_link because it depends on a number of variables
+# set therein.
+#
+# ARG is the value that the WRAPPER_SCRIPT_BELONGS_IN_OBJDIR
+# variable will take. If 'yes', then the emitted script
+# will assume that the directory in which it is stored is
+# the $objdir directory. This is a cygwin/mingw-specific
+# behavior.
+func_emit_wrapper ()
+{
+ func_emit_wrapper_arg1=${1-no}
+
+ $ECHO "\
+#! $SHELL
+
+# $output - temporary wrapper script for $objdir/$outputname
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# The $output program cannot be directly executed until all the libtool
+# libraries that it depends on are installed.
+#
+# This wrapper script should never be moved out of the build directory.
+# If it is, it will not operate correctly.
+
+# Sed substitution that helps us do robust quoting. It backslashifies
+# metacharacters that are still active within double-quoted strings.
+sed_quote_subst='$sed_quote_subst'
+
+# Be Bourne compatible
+if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then
+ emulate sh
+ NULLCMD=:
+ # Zsh 3.x and 4.x performs word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in *posix*) set -o posix;; esac
+fi
+BIN_SH=xpg4; export BIN_SH # for Tru64
+DUALCASE=1; export DUALCASE # for MKS sh
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+relink_command=\"$relink_command\"
+
+# This environment variable determines our operation mode.
+if test \"\$libtool_install_magic\" = \"$magic\"; then
+ # install mode needs the following variables:
+ generated_by_libtool_version='$macro_version'
+ notinst_deplibs='$notinst_deplibs'
+else
+ # When we are sourced in execute mode, \$file and \$ECHO are already set.
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ file=\"\$0\""
+
+ qECHO=`$ECHO "$ECHO" | $SED "$sed_quote_subst"`
+ $ECHO "\
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+ ECHO=\"$qECHO\"
+ fi
+
+# Very basic option parsing. These options are (a) specific to
+# the libtool wrapper, (b) are identical between the wrapper
+# /script/ and the wrapper /executable/ which is used only on
+# windows platforms, and (c) all begin with the string "--lt-"
+# (application programs are unlikely to have options which match
+# this pattern).
+#
+# There are only two supported options: --lt-debug and
+# --lt-dump-script. There is, deliberately, no --lt-help.
+#
+# The first argument to this parsing function should be the
+# script's $0 value, followed by "$@".
+lt_option_debug=
+func_parse_lt_options ()
+{
+ lt_script_arg0=\$0
+ shift
+ for lt_opt
+ do
+ case \"\$lt_opt\" in
+ --lt-debug) lt_option_debug=1 ;;
+ --lt-dump-script)
+ lt_dump_D=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%/[^/]*$%%'\`
+ test \"X\$lt_dump_D\" = \"X\$lt_script_arg0\" && lt_dump_D=.
+ lt_dump_F=\`\$ECHO \"X\$lt_script_arg0\" | $SED -e 's/^X//' -e 's%^.*/%%'\`
+ cat \"\$lt_dump_D/\$lt_dump_F\"
+ exit 0
+ ;;
+ --lt-*)
+ \$ECHO \"Unrecognized --lt- option: '\$lt_opt'\" 1>&2
+ exit 1
+ ;;
+ esac
+ done
+
+ # Print the debug banner immediately:
+ if test -n \"\$lt_option_debug\"; then
+ echo \"${outputname}:${output}:\${LINENO}: libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\" 1>&2
+ fi
+}
+
+# Used when --lt-debug. Prints its arguments to stdout
+# (redirection is the responsibility of the caller)
+func_lt_dump_args ()
+{
+ lt_dump_args_N=1;
+ for lt_arg
+ do
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[\$lt_dump_args_N]: \$lt_arg\"
+ lt_dump_args_N=\`expr \$lt_dump_args_N + 1\`
+ done
+}
+
+# Core function for launching the target application
+func_exec_program_core ()
+{
+"
+ case $host in
+ # Backslashes separate directories on plain windows
+ *-*-mingw | *-*-os2* | *-cegcc*)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir\\\\\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir\\\\\$program\" \${1+\"\$@\"}
+"
+ ;;
+
+ *)
+ $ECHO "\
+ if test -n \"\$lt_option_debug\"; then
+ \$ECHO \"${outputname}:${output}:\${LINENO}: newargv[0]: \$progdir/\$program\" 1>&2
+ func_lt_dump_args \${1+\"\$@\"} 1>&2
+ fi
+ exec \"\$progdir/\$program\" \${1+\"\$@\"}
+"
+ ;;
+ esac
+ $ECHO "\
+ \$ECHO \"\$0: cannot exec \$program \$*\" 1>&2
+ exit 1
+}
+
+# A function to encapsulate launching the target application
+# Strips options in the --lt-* namespace from \$@ and
+# launches target application with the remaining arguments.
+func_exec_program ()
+{
+ case \" \$* \" in
+ *\\ --lt-*)
+ for lt_wr_arg
+ do
+ case \$lt_wr_arg in
+ --lt-*) ;;
+ *) set x \"\$@\" \"\$lt_wr_arg\"; shift;;
+ esac
+ shift
+ done ;;
+ esac
+ func_exec_program_core \${1+\"\$@\"}
+}
+
+ # Parse options
+ func_parse_lt_options \"\$0\" \${1+\"\$@\"}
+
+ # Find the directory that this script lives in.
+ thisdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*$%%'\`
+ test \"x\$thisdir\" = \"x\$file\" && thisdir=.
+
+ # Follow symbolic links until we get to the real thisdir.
+ file=\`ls -ld \"\$file\" | $SED -n 's/.*-> //p'\`
+ while test -n \"\$file\"; do
+ destdir=\`\$ECHO \"\$file\" | $SED 's%/[^/]*\$%%'\`
+
+ # If there was a directory component, then change thisdir.
+ if test \"x\$destdir\" != \"x\$file\"; then
+ case \"\$destdir\" in
+ [\\\\/]* | [A-Za-z]:[\\\\/]*) thisdir=\"\$destdir\" ;;
+ *) thisdir=\"\$thisdir/\$destdir\" ;;
+ esac
+ fi
+
+ file=\`\$ECHO \"\$file\" | $SED 's%^.*/%%'\`
+ file=\`ls -ld \"\$thisdir/\$file\" | $SED -n 's/.*-> //p'\`
+ done
+
+ # Usually 'no', except on cygwin/mingw when embedded into
+ # the cwrapper.
+ WRAPPER_SCRIPT_BELONGS_IN_OBJDIR=$func_emit_wrapper_arg1
+ if test \"\$WRAPPER_SCRIPT_BELONGS_IN_OBJDIR\" = \"yes\"; then
+ # special case for '.'
+ if test \"\$thisdir\" = \".\"; then
+ thisdir=\`pwd\`
+ fi
+ # remove .libs from thisdir
+ case \"\$thisdir\" in
+ *[\\\\/]$objdir ) thisdir=\`\$ECHO \"\$thisdir\" | $SED 's%[\\\\/][^\\\\/]*$%%'\` ;;
+ $objdir ) thisdir=. ;;
+ esac
+ fi
+
+ # Try to get the absolute directory name.
+ absdir=\`cd \"\$thisdir\" && pwd\`
+ test -n \"\$absdir\" && thisdir=\"\$absdir\"
+"
+
+ if test "$fast_install" = yes; then
+ $ECHO "\
+ program=lt-'$outputname'$exeext
+ progdir=\"\$thisdir/$objdir\"
+
+ if test ! -f \"\$progdir/\$program\" ||
+ { file=\`ls -1dt \"\$progdir/\$program\" \"\$progdir/../\$program\" 2>/dev/null | ${SED} 1q\`; \\
+ test \"X\$file\" != \"X\$progdir/\$program\"; }; then
+
+ file=\"\$\$-\$program\"
+
+ if test ! -d \"\$progdir\"; then
+ $MKDIR \"\$progdir\"
+ else
+ $RM \"\$progdir/\$file\"
+ fi"
+
+ $ECHO "\
+
+ # relink executable if necessary
+ if test -n \"\$relink_command\"; then
+ if relink_command_output=\`eval \$relink_command 2>&1\`; then :
+ else
+ $ECHO \"\$relink_command_output\" >&2
+ $RM \"\$progdir/\$file\"
+ exit 1
+ fi
+ fi
+
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\" 2>/dev/null ||
+ { $RM \"\$progdir/\$program\";
+ $MV \"\$progdir/\$file\" \"\$progdir/\$program\"; }
+ $RM \"\$progdir/\$file\"
+ fi"
+ else
+ $ECHO "\
+ program='$outputname'
+ progdir=\"\$thisdir/$objdir\"
+"
+ fi
+
+ $ECHO "\
+
+ if test -f \"\$progdir/\$program\"; then"
+
+ # fixup the dll searchpath if we need to.
+ #
+ # Fix the DLL searchpath if we need to. Do this before prepending
+ # to shlibpath, because on Windows, both are PATH and uninstalled
+ # libraries must come first.
+ if test -n "$dllsearchpath"; then
+ $ECHO "\
+ # Add the dll search path components to the executable PATH
+ PATH=$dllsearchpath:\$PATH
+"
+ fi
+
+ # Export our shlibpath_var if we have one.
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ $ECHO "\
+ # Add our own library path to $shlibpath_var
+ $shlibpath_var=\"$temp_rpath\$$shlibpath_var\"
+
+ # Some systems cannot cope with colon-terminated $shlibpath_var
+ # The second colon is a workaround for a bug in BeOS R4 sed
+ $shlibpath_var=\`\$ECHO \"\$$shlibpath_var\" | $SED 's/::*\$//'\`
+
+ export $shlibpath_var
+"
+ fi
+
+ $ECHO "\
+ if test \"\$libtool_execute_magic\" != \"$magic\"; then
+ # Run the actual program with our arguments.
+ func_exec_program \${1+\"\$@\"}
+ fi
+ else
+ # The program doesn't exist.
+ \$ECHO \"\$0: error: \\\`\$progdir/\$program' does not exist\" 1>&2
+ \$ECHO \"This script is just a wrapper for \$program.\" 1>&2
+ \$ECHO \"See the $PACKAGE documentation for more information.\" 1>&2
+ exit 1
+ fi
+fi\
+"
+}
+
+
+# func_emit_cwrapperexe_src
+# emit the source code for a wrapper executable on stdout
+# Must ONLY be called from within func_mode_link because
+# it depends on a number of variable set therein.
+func_emit_cwrapperexe_src ()
+{
+ cat <<EOF
+
+/* $cwrappersource - temporary wrapper executable for $objdir/$outputname
+ Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+
+ The $output program cannot be directly executed until all the libtool
+ libraries that it depends on are installed.
+
+ This wrapper executable should never be moved out of the build directory.
+ If it is, it will not operate correctly.
+*/
+EOF
+ cat <<"EOF"
+#ifdef _MSC_VER
+# define _CRT_SECURE_NO_DEPRECATE 1
+#endif
+#include <stdio.h>
+#include <stdlib.h>
+#ifdef _MSC_VER
+# include <direct.h>
+# include <process.h>
+# include <io.h>
+#else
+# include <unistd.h>
+# include <stdint.h>
+# ifdef __CYGWIN__
+# include <io.h>
+# endif
+#endif
+#include <malloc.h>
+#include <stdarg.h>
+#include <assert.h>
+#include <string.h>
+#include <ctype.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* declarations of non-ANSI functions */
+#if defined(__MINGW32__)
+# ifdef __STRICT_ANSI__
+int _putenv (const char *);
+# endif
+#elif defined(__CYGWIN__)
+# ifdef __STRICT_ANSI__
+char *realpath (const char *, char *);
+int putenv (char *);
+int setenv (const char *, const char *, int);
+# endif
+/* #elif defined (other platforms) ... */
+#endif
+
+/* portability defines, excluding path handling macros */
+#if defined(_MSC_VER)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+# define S_IXUSR _S_IEXEC
+# ifndef _INTPTR_T_DEFINED
+# define _INTPTR_T_DEFINED
+# define intptr_t int
+# endif
+#elif defined(__MINGW32__)
+# define setmode _setmode
+# define stat _stat
+# define chmod _chmod
+# define getcwd _getcwd
+# define putenv _putenv
+#elif defined(__CYGWIN__)
+# define HAVE_SETENV
+# define FOPEN_WB "wb"
+/* #elif defined (other platforms) ... */
+#endif
+
+#if defined(PATH_MAX)
+# define LT_PATHMAX PATH_MAX
+#elif defined(MAXPATHLEN)
+# define LT_PATHMAX MAXPATHLEN
+#else
+# define LT_PATHMAX 1024
+#endif
+
+#ifndef S_IXOTH
+# define S_IXOTH 0
+#endif
+#ifndef S_IXGRP
+# define S_IXGRP 0
+#endif
+
+/* path handling portability macros */
+#ifndef DIR_SEPARATOR
+# define DIR_SEPARATOR '/'
+# define PATH_SEPARATOR ':'
+#endif
+
+#if defined (_WIN32) || defined (__MSDOS__) || defined (__DJGPP__) || \
+ defined (__OS2__)
+# define HAVE_DOS_BASED_FILE_SYSTEM
+# define FOPEN_WB "wb"
+# ifndef DIR_SEPARATOR_2
+# define DIR_SEPARATOR_2 '\\'
+# endif
+# ifndef PATH_SEPARATOR_2
+# define PATH_SEPARATOR_2 ';'
+# endif
+#endif
+
+#ifndef DIR_SEPARATOR_2
+# define IS_DIR_SEPARATOR(ch) ((ch) == DIR_SEPARATOR)
+#else /* DIR_SEPARATOR_2 */
+# define IS_DIR_SEPARATOR(ch) \
+ (((ch) == DIR_SEPARATOR) || ((ch) == DIR_SEPARATOR_2))
+#endif /* DIR_SEPARATOR_2 */
+
+#ifndef PATH_SEPARATOR_2
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR)
+#else /* PATH_SEPARATOR_2 */
+# define IS_PATH_SEPARATOR(ch) ((ch) == PATH_SEPARATOR_2)
+#endif /* PATH_SEPARATOR_2 */
+
+#ifndef FOPEN_WB
+# define FOPEN_WB "w"
+#endif
+#ifndef _O_BINARY
+# define _O_BINARY 0
+#endif
+
+#define XMALLOC(type, num) ((type *) xmalloc ((num) * sizeof(type)))
+#define XFREE(stale) do { \
+ if (stale) { free ((void *) stale); stale = 0; } \
+} while (0)
+
+#if defined(LT_DEBUGWRAPPER)
+static int lt_debug = 1;
+#else
+static int lt_debug = 0;
+#endif
+
+const char *program_name = "libtool-wrapper"; /* in case xstrdup fails */
+
+void *xmalloc (size_t num);
+char *xstrdup (const char *string);
+const char *base_name (const char *name);
+char *find_executable (const char *wrapper);
+char *chase_symlinks (const char *pathspec);
+int make_executable (const char *path);
+int check_executable (const char *path);
+char *strendzap (char *str, const char *pat);
+void lt_debugprintf (const char *file, int line, const char *fmt, ...);
+void lt_fatal (const char *file, int line, const char *message, ...);
+static const char *nonnull (const char *s);
+static const char *nonempty (const char *s);
+void lt_setenv (const char *name, const char *value);
+char *lt_extend_str (const char *orig_value, const char *add, int to_end);
+void lt_update_exe_path (const char *name, const char *value);
+void lt_update_lib_path (const char *name, const char *value);
+char **prepare_spawn (char **argv);
+void lt_dump_script (FILE *f);
+EOF
+
+ cat <<EOF
+volatile const char * MAGIC_EXE = "$magic_exe";
+const char * LIB_PATH_VARNAME = "$shlibpath_var";
+EOF
+
+ if test "$shlibpath_overrides_runpath" = yes && test -n "$shlibpath_var" && test -n "$temp_rpath"; then
+ func_to_host_path "$temp_rpath"
+ cat <<EOF
+const char * LIB_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * LIB_PATH_VALUE = "";
+EOF
+ fi
+
+ if test -n "$dllsearchpath"; then
+ func_to_host_path "$dllsearchpath:"
+ cat <<EOF
+const char * EXE_PATH_VARNAME = "PATH";
+const char * EXE_PATH_VALUE = "$func_to_host_path_result";
+EOF
+ else
+ cat <<"EOF"
+const char * EXE_PATH_VARNAME = "";
+const char * EXE_PATH_VALUE = "";
+EOF
+ fi
+
+ if test "$fast_install" = yes; then
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "lt-$outputname"; /* hopefully, no .exe */
+EOF
+ else
+ cat <<EOF
+const char * TARGET_PROGRAM_NAME = "$outputname"; /* hopefully, no .exe */
+EOF
+ fi
+
+
+ cat <<"EOF"
+
+#define LTWRAPPER_OPTION_PREFIX "--lt-"
+
+static const char *ltwrapper_option_prefix = LTWRAPPER_OPTION_PREFIX;
+static const char *dumpscript_opt = LTWRAPPER_OPTION_PREFIX "dump-script";
+static const char *debug_opt = LTWRAPPER_OPTION_PREFIX "debug";
+
+int
+main (int argc, char *argv[])
+{
+ char **newargz;
+ int newargc;
+ char *tmp_pathspec;
+ char *actual_cwrapper_path;
+ char *actual_cwrapper_name;
+ char *target_name;
+ char *lt_argv_zero;
+ intptr_t rval = 127;
+
+ int i;
+
+ program_name = (char *) xstrdup (base_name (argv[0]));
+ newargz = XMALLOC (char *, argc + 1);
+
+ /* very simple arg parsing; don't want to rely on getopt
+ * also, copy all non cwrapper options to newargz, except
+ * argz[0], which is handled differently
+ */
+ newargc=0;
+ for (i = 1; i < argc; i++)
+ {
+ if (strcmp (argv[i], dumpscript_opt) == 0)
+ {
+EOF
+ case "$host" in
+ *mingw* | *cygwin* )
+ # make stdout use "unix" line endings
+ echo " setmode(1,_O_BINARY);"
+ ;;
+ esac
+
+ cat <<"EOF"
+ lt_dump_script (stdout);
+ return 0;
+ }
+ if (strcmp (argv[i], debug_opt) == 0)
+ {
+ lt_debug = 1;
+ continue;
+ }
+ if (strcmp (argv[i], ltwrapper_option_prefix) == 0)
+ {
+ /* however, if there is an option in the LTWRAPPER_OPTION_PREFIX
+ namespace, but it is not one of the ones we know about and
+ have already dealt with, above (inluding dump-script), then
+ report an error. Otherwise, targets might begin to believe
+ they are allowed to use options in the LTWRAPPER_OPTION_PREFIX
+ namespace. The first time any user complains about this, we'll
+ need to make LTWRAPPER_OPTION_PREFIX a configure-time option
+ or a configure.ac-settable value.
+ */
+ lt_fatal (__FILE__, __LINE__,
+ "unrecognized %s option: '%s'",
+ ltwrapper_option_prefix, argv[i]);
+ }
+ /* otherwise ... */
+ newargz[++newargc] = xstrdup (argv[i]);
+ }
+ newargz[++newargc] = NULL;
+
+EOF
+ cat <<EOF
+ /* The GNU banner must be the first non-error debug message */
+ lt_debugprintf (__FILE__, __LINE__, "libtool wrapper (GNU $PACKAGE$TIMESTAMP) $VERSION\n");
+EOF
+ cat <<"EOF"
+ lt_debugprintf (__FILE__, __LINE__, "(main) argv[0]: %s\n", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__, "(main) program_name: %s\n", program_name);
+
+ tmp_pathspec = find_executable (argv[0]);
+ if (tmp_pathspec == NULL)
+ lt_fatal (__FILE__, __LINE__, "couldn't find %s", argv[0]);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (before symlink chase) at: %s\n",
+ tmp_pathspec);
+
+ actual_cwrapper_path = chase_symlinks (tmp_pathspec);
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) found exe (after symlink chase) at: %s\n",
+ actual_cwrapper_path);
+ XFREE (tmp_pathspec);
+
+ actual_cwrapper_name = xstrdup (base_name (actual_cwrapper_path));
+ strendzap (actual_cwrapper_path, actual_cwrapper_name);
+
+ /* wrapper name transforms */
+ strendzap (actual_cwrapper_name, ".exe");
+ tmp_pathspec = lt_extend_str (actual_cwrapper_name, ".exe", 1);
+ XFREE (actual_cwrapper_name);
+ actual_cwrapper_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ /* target_name transforms -- use actual target program name; might have lt- prefix */
+ target_name = xstrdup (base_name (TARGET_PROGRAM_NAME));
+ strendzap (target_name, ".exe");
+ tmp_pathspec = lt_extend_str (target_name, ".exe", 1);
+ XFREE (target_name);
+ target_name = tmp_pathspec;
+ tmp_pathspec = 0;
+
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) libtool target name: %s\n",
+ target_name);
+EOF
+
+ cat <<EOF
+ newargz[0] =
+ XMALLOC (char, (strlen (actual_cwrapper_path) +
+ strlen ("$objdir") + 1 + strlen (actual_cwrapper_name) + 1));
+ strcpy (newargz[0], actual_cwrapper_path);
+ strcat (newargz[0], "$objdir");
+ strcat (newargz[0], "/");
+EOF
+
+ cat <<"EOF"
+ /* stop here, and copy so we don't have to do this twice */
+ tmp_pathspec = xstrdup (newargz[0]);
+
+ /* do NOT want the lt- prefix here, so use actual_cwrapper_name */
+ strcat (newargz[0], actual_cwrapper_name);
+
+ /* DO want the lt- prefix here if it exists, so use target_name */
+ lt_argv_zero = lt_extend_str (tmp_pathspec, target_name, 1);
+ XFREE (tmp_pathspec);
+ tmp_pathspec = NULL;
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ {
+ char* p;
+ while ((p = strchr (newargz[0], '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ while ((p = strchr (lt_argv_zero, '\\')) != NULL)
+ {
+ *p = '/';
+ }
+ }
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+ XFREE (target_name);
+ XFREE (actual_cwrapper_path);
+ XFREE (actual_cwrapper_name);
+
+ lt_setenv ("BIN_SH", "xpg4"); /* for Tru64 */
+ lt_setenv ("DUALCASE", "1"); /* for MSK sh */
+ /* Update the DLL searchpath. EXE_PATH_VALUE ($dllsearchpath) must
+ be prepended before (that is, appear after) LIB_PATH_VALUE ($temp_rpath)
+ because on Windows, both *_VARNAMEs are PATH but uninstalled
+ libraries must come first. */
+ lt_update_exe_path (EXE_PATH_VARNAME, EXE_PATH_VALUE);
+ lt_update_lib_path (LIB_PATH_VARNAME, LIB_PATH_VALUE);
+
+ lt_debugprintf (__FILE__, __LINE__, "(main) lt_argv_zero: %s\n",
+ nonnull (lt_argv_zero));
+ for (i = 0; i < newargc; i++)
+ {
+ lt_debugprintf (__FILE__, __LINE__, "(main) newargz[%d]: %s\n",
+ i, nonnull (newargz[i]));
+ }
+
+EOF
+
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+ /* execv doesn't actually work on mingw as expected on unix */
+ newargz = prepare_spawn (newargz);
+ rval = _spawnv (_P_WAIT, lt_argv_zero, (const char * const *) newargz);
+ if (rval == -1)
+ {
+ /* failed to start process */
+ lt_debugprintf (__FILE__, __LINE__,
+ "(main) failed to launch target \"%s\": %s\n",
+ lt_argv_zero, nonnull (strerror (errno)));
+ return 127;
+ }
+ return rval;
+EOF
+ ;;
+ *)
+ cat <<"EOF"
+ execv (lt_argv_zero, newargz);
+ return rval; /* =127, but avoids unused variable warning */
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+}
+
+void *
+xmalloc (size_t num)
+{
+ void *p = (void *) malloc (num);
+ if (!p)
+ lt_fatal (__FILE__, __LINE__, "memory exhausted");
+
+ return p;
+}
+
+char *
+xstrdup (const char *string)
+{
+ return string ? strcpy ((char *) xmalloc (strlen (string) + 1),
+ string) : NULL;
+}
+
+const char *
+base_name (const char *name)
+{
+ const char *base;
+
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ /* Skip over the disk name in MSDOS pathnames. */
+ if (isalpha ((unsigned char) name[0]) && name[1] == ':')
+ name += 2;
+#endif
+
+ for (base = name; *name; name++)
+ if (IS_DIR_SEPARATOR (*name))
+ base = name + 1;
+ return base;
+}
+
+int
+check_executable (const char *path)
+{
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(check_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if ((stat (path, &st) >= 0)
+ && (st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)))
+ return 1;
+ else
+ return 0;
+}
+
+int
+make_executable (const char *path)
+{
+ int rval = 0;
+ struct stat st;
+
+ lt_debugprintf (__FILE__, __LINE__, "(make_executable): %s\n",
+ nonempty (path));
+ if ((!path) || (!*path))
+ return 0;
+
+ if (stat (path, &st) >= 0)
+ {
+ rval = chmod (path, st.st_mode | S_IXOTH | S_IXGRP | S_IXUSR);
+ }
+ return rval;
+}
+
+/* Searches for the full path of the wrapper. Returns
+ newly allocated full path name if found, NULL otherwise
+ Does not chase symlinks, even on platforms that support them.
+*/
+char *
+find_executable (const char *wrapper)
+{
+ int has_slash = 0;
+ const char *p;
+ const char *p_next;
+ /* static buffer for getcwd */
+ char tmp[LT_PATHMAX + 1];
+ int tmp_len;
+ char *concat_name;
+
+ lt_debugprintf (__FILE__, __LINE__, "(find_executable): %s\n",
+ nonempty (wrapper));
+
+ if ((wrapper == NULL) || (*wrapper == '\0'))
+ return NULL;
+
+ /* Absolute path? */
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ if (isalpha ((unsigned char) wrapper[0]) && wrapper[1] == ':')
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ else
+ {
+#endif
+ if (IS_DIR_SEPARATOR (wrapper[0]))
+ {
+ concat_name = xstrdup (wrapper);
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+#if defined (HAVE_DOS_BASED_FILE_SYSTEM)
+ }
+#endif
+
+ for (p = wrapper; *p; p++)
+ if (*p == '/')
+ {
+ has_slash = 1;
+ break;
+ }
+ if (!has_slash)
+ {
+ /* no slashes; search PATH */
+ const char *path = getenv ("PATH");
+ if (path != NULL)
+ {
+ for (p = path; *p; p = p_next)
+ {
+ const char *q;
+ size_t p_len;
+ for (q = p; *q; q++)
+ if (IS_PATH_SEPARATOR (*q))
+ break;
+ p_len = q - p;
+ p_next = (*q == '\0' ? q : q + 1);
+ if (p_len == 0)
+ {
+ /* empty path: current directory */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name =
+ XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+ }
+ else
+ {
+ concat_name =
+ XMALLOC (char, p_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, p, p_len);
+ concat_name[p_len] = '/';
+ strcpy (concat_name + p_len + 1, wrapper);
+ }
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ }
+ }
+ /* not found in PATH; assume curdir */
+ }
+ /* Relative path | not found in path: prepend cwd */
+ if (getcwd (tmp, LT_PATHMAX) == NULL)
+ lt_fatal (__FILE__, __LINE__, "getcwd failed: %s",
+ nonnull (strerror (errno)));
+ tmp_len = strlen (tmp);
+ concat_name = XMALLOC (char, tmp_len + 1 + strlen (wrapper) + 1);
+ memcpy (concat_name, tmp, tmp_len);
+ concat_name[tmp_len] = '/';
+ strcpy (concat_name + tmp_len + 1, wrapper);
+
+ if (check_executable (concat_name))
+ return concat_name;
+ XFREE (concat_name);
+ return NULL;
+}
+
+char *
+chase_symlinks (const char *pathspec)
+{
+#ifndef S_ISLNK
+ return xstrdup (pathspec);
+#else
+ char buf[LT_PATHMAX];
+ struct stat s;
+ char *tmp_pathspec = xstrdup (pathspec);
+ char *p;
+ int has_symlinks = 0;
+ while (strlen (tmp_pathspec) && !has_symlinks)
+ {
+ lt_debugprintf (__FILE__, __LINE__,
+ "checking path component for symlinks: %s\n",
+ tmp_pathspec);
+ if (lstat (tmp_pathspec, &s) == 0)
+ {
+ if (S_ISLNK (s.st_mode) != 0)
+ {
+ has_symlinks = 1;
+ break;
+ }
+
+ /* search backwards for last DIR_SEPARATOR */
+ p = tmp_pathspec + strlen (tmp_pathspec) - 1;
+ while ((p > tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ p--;
+ if ((p == tmp_pathspec) && (!IS_DIR_SEPARATOR (*p)))
+ {
+ /* no more DIR_SEPARATORS left */
+ break;
+ }
+ *p = '\0';
+ }
+ else
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "error accessing file \"%s\": %s",
+ tmp_pathspec, nonnull (strerror (errno)));
+ }
+ }
+ XFREE (tmp_pathspec);
+
+ if (!has_symlinks)
+ {
+ return xstrdup (pathspec);
+ }
+
+ tmp_pathspec = realpath (pathspec, buf);
+ if (tmp_pathspec == 0)
+ {
+ lt_fatal (__FILE__, __LINE__,
+ "could not follow symlinks for %s", pathspec);
+ }
+ return xstrdup (tmp_pathspec);
+#endif
+}
+
+char *
+strendzap (char *str, const char *pat)
+{
+ size_t len, patlen;
+
+ assert (str != NULL);
+ assert (pat != NULL);
+
+ len = strlen (str);
+ patlen = strlen (pat);
+
+ if (patlen <= len)
+ {
+ str += len - patlen;
+ if (strcmp (str, pat) == 0)
+ *str = '\0';
+ }
+ return str;
+}
+
+void
+lt_debugprintf (const char *file, int line, const char *fmt, ...)
+{
+ va_list args;
+ if (lt_debug)
+ {
+ (void) fprintf (stderr, "%s:%s:%d: ", program_name, file, line);
+ va_start (args, fmt);
+ (void) vfprintf (stderr, fmt, args);
+ va_end (args);
+ }
+}
+
+static void
+lt_error_core (int exit_status, const char *file,
+ int line, const char *mode,
+ const char *message, va_list ap)
+{
+ fprintf (stderr, "%s:%s:%d: %s: ", program_name, file, line, mode);
+ vfprintf (stderr, message, ap);
+ fprintf (stderr, ".\n");
+
+ if (exit_status >= 0)
+ exit (exit_status);
+}
+
+void
+lt_fatal (const char *file, int line, const char *message, ...)
+{
+ va_list ap;
+ va_start (ap, message);
+ lt_error_core (EXIT_FAILURE, file, line, "FATAL", message, ap);
+ va_end (ap);
+}
+
+static const char *
+nonnull (const char *s)
+{
+ return s ? s : "(null)";
+}
+
+static const char *
+nonempty (const char *s)
+{
+ return (s && !*s) ? "(empty)" : nonnull (s);
+}
+
+void
+lt_setenv (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_setenv) setting '%s' to '%s'\n",
+ nonnull (name), nonnull (value));
+ {
+#ifdef HAVE_SETENV
+ /* always make a copy, for consistency with !HAVE_SETENV */
+ char *str = xstrdup (value);
+ setenv (name, str, 1);
+#else
+ int len = strlen (name) + 1 + strlen (value) + 1;
+ char *str = XMALLOC (char, len);
+ sprintf (str, "%s=%s", name, value);
+ if (putenv (str) != EXIT_SUCCESS)
+ {
+ XFREE (str);
+ }
+#endif
+ }
+}
+
+char *
+lt_extend_str (const char *orig_value, const char *add, int to_end)
+{
+ char *new_value;
+ if (orig_value && *orig_value)
+ {
+ int orig_value_len = strlen (orig_value);
+ int add_len = strlen (add);
+ new_value = XMALLOC (char, add_len + orig_value_len + 1);
+ if (to_end)
+ {
+ strcpy (new_value, orig_value);
+ strcpy (new_value + orig_value_len, add);
+ }
+ else
+ {
+ strcpy (new_value, add);
+ strcpy (new_value + add_len, orig_value);
+ }
+ }
+ else
+ {
+ new_value = xstrdup (add);
+ }
+ return new_value;
+}
+
+void
+lt_update_exe_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_exe_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ /* some systems can't cope with a ':'-terminated path #' */
+ int len = strlen (new_value);
+ while (((len = strlen (new_value)) > 0) && IS_PATH_SEPARATOR (new_value[len-1]))
+ {
+ new_value[len-1] = '\0';
+ }
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+void
+lt_update_lib_path (const char *name, const char *value)
+{
+ lt_debugprintf (__FILE__, __LINE__,
+ "(lt_update_lib_path) modifying '%s' by prepending '%s'\n",
+ nonnull (name), nonnull (value));
+
+ if (name && *name && value && *value)
+ {
+ char *new_value = lt_extend_str (getenv (name), value, 0);
+ lt_setenv (name, new_value);
+ XFREE (new_value);
+ }
+}
+
+EOF
+ case $host_os in
+ mingw*)
+ cat <<"EOF"
+
+/* Prepares an argument vector before calling spawn().
+ Note that spawn() does not by itself call the command interpreter
+ (getenv ("COMSPEC") != NULL ? getenv ("COMSPEC") :
+ ({ OSVERSIONINFO v; v.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&v);
+ v.dwPlatformId == VER_PLATFORM_WIN32_NT;
+ }) ? "cmd.exe" : "command.com").
+ Instead it simply concatenates the arguments, separated by ' ', and calls
+ CreateProcess(). We must quote the arguments since Win32 CreateProcess()
+ interprets characters like ' ', '\t', '\\', '"' (but not '<' and '>') in a
+ special way:
+ - Space and tab are interpreted as delimiters. They are not treated as
+ delimiters if they are surrounded by double quotes: "...".
+ - Unescaped double quotes are removed from the input. Their only effect is
+ that within double quotes, space and tab are treated like normal
+ characters.
+ - Backslashes not followed by double quotes are not special.
+ - But 2*n+1 backslashes followed by a double quote become
+ n backslashes followed by a double quote (n >= 0):
+ \" -> "
+ \\\" -> \"
+ \\\\\" -> \\"
+ */
+#define SHELL_SPECIAL_CHARS "\"\\ \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+#define SHELL_SPACE_CHARS " \001\002\003\004\005\006\007\010\011\012\013\014\015\016\017\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
+char **
+prepare_spawn (char **argv)
+{
+ size_t argc;
+ char **new_argv;
+ size_t i;
+
+ /* Count number of arguments. */
+ for (argc = 0; argv[argc] != NULL; argc++)
+ ;
+
+ /* Allocate new argument vector. */
+ new_argv = XMALLOC (char *, argc + 1);
+
+ /* Put quoted arguments into the new argument vector. */
+ for (i = 0; i < argc; i++)
+ {
+ const char *string = argv[i];
+
+ if (string[0] == '\0')
+ new_argv[i] = xstrdup ("\"\"");
+ else if (strpbrk (string, SHELL_SPECIAL_CHARS) != NULL)
+ {
+ int quote_around = (strpbrk (string, SHELL_SPACE_CHARS) != NULL);
+ size_t length;
+ unsigned int backslashes;
+ const char *s;
+ char *quoted_string;
+ char *p;
+
+ length = 0;
+ backslashes = 0;
+ if (quote_around)
+ length++;
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ length += backslashes + 1;
+ length++;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ length += backslashes + 1;
+
+ quoted_string = XMALLOC (char, length + 1);
+
+ p = quoted_string;
+ backslashes = 0;
+ if (quote_around)
+ *p++ = '"';
+ for (s = string; *s != '\0'; s++)
+ {
+ char c = *s;
+ if (c == '"')
+ {
+ unsigned int j;
+ for (j = backslashes + 1; j > 0; j--)
+ *p++ = '\\';
+ }
+ *p++ = c;
+ if (c == '\\')
+ backslashes++;
+ else
+ backslashes = 0;
+ }
+ if (quote_around)
+ {
+ unsigned int j;
+ for (j = backslashes; j > 0; j--)
+ *p++ = '\\';
+ *p++ = '"';
+ }
+ *p = '\0';
+
+ new_argv[i] = quoted_string;
+ }
+ else
+ new_argv[i] = (char *) string;
+ }
+ new_argv[argc] = NULL;
+
+ return new_argv;
+}
+EOF
+ ;;
+ esac
+
+ cat <<"EOF"
+void lt_dump_script (FILE* f)
+{
+EOF
+ func_emit_wrapper yes |
+ $SED -n -e '
+s/^\(.\{79\}\)\(..*\)/\1\
+\2/
+h
+s/\([\\"]\)/\\\1/g
+s/$/\\n/
+s/\([^\n]*\).*/ fputs ("\1", f);/p
+g
+D'
+ cat <<"EOF"
+}
+EOF
+}
+# end: func_emit_cwrapperexe_src
+
+# func_win32_import_lib_p ARG
+# True if ARG is an import lib, as indicated by $file_magic_cmd
+func_win32_import_lib_p ()
+{
+ $opt_debug
+ case `eval $file_magic_cmd \"\$1\" 2>/dev/null | $SED -e 10q` in
+ *import*) : ;;
+ *) false ;;
+ esac
+}
+
+# func_mode_link arg...
+func_mode_link ()
+{
+ $opt_debug
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ # It is impossible to link a dll without this setting, and
+ # we shouldn't force the makefile maintainer to figure out
+ # which system we are compiling for in order to pass an extra
+ # flag for every libtool invocation.
+ # allow_undefined=no
+
+ # FIXME: Unfortunately, there are problems with the above when trying
+ # to make a dll which has undefined symbols, in which case not
+ # even a static library is built. For now, we need to specify
+ # -no-undefined on the libtool link line when we can be certain
+ # that all symbols are satisfied, otherwise we get a static library.
+ allow_undefined=yes
+ ;;
+ *)
+ allow_undefined=yes
+ ;;
+ esac
+ libtool_args=$nonopt
+ base_compile="$nonopt $@"
+ compile_command=$nonopt
+ finalize_command=$nonopt
+
+ compile_rpath=
+ finalize_rpath=
+ compile_shlibpath=
+ finalize_shlibpath=
+ convenience=
+ old_convenience=
+ deplibs=
+ old_deplibs=
+ compiler_flags=
+ linker_flags=
+ dllsearchpath=
+ lib_search_path=`pwd`
+ inst_prefix_dir=
+ new_inherited_linker_flags=
+
+ avoid_version=no
+ bindir=
+ dlfiles=
+ dlprefiles=
+ dlself=no
+ export_dynamic=no
+ export_symbols=
+ export_symbols_regex=
+ generated=
+ libobjs=
+ ltlibs=
+ module=no
+ no_install=no
+ objs=
+ non_pic_objects=
+ precious_files_regex=
+ prefer_static_libs=no
+ preload=no
+ prev=
+ prevarg=
+ release=
+ rpath=
+ xrpath=
+ perm_rpath=
+ temp_rpath=
+ thread_safe=no
+ vinfo=
+ vinfo_number=no
+ weak_libs=
+ single_module="${wl}-single_module"
+ func_infer_tag $base_compile
+
+ # We need to know -static, to get the right output filenames.
+ for arg
+ do
+ case $arg in
+ -shared)
+ test "$build_libtool_libs" != yes && \
+ func_fatal_configuration "can not build a shared library"
+ build_old_libs=no
+ break
+ ;;
+ -all-static | -static | -static-libtool-libs)
+ case $arg in
+ -all-static)
+ if test "$build_libtool_libs" = yes && test -z "$link_static_flag"; then
+ func_warning "complete static linking is impossible in this configuration"
+ fi
+ if test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ -static)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=built
+ ;;
+ -static-libtool-libs)
+ if test -z "$pic_flag" && test -n "$link_static_flag"; then
+ dlopen_self=$dlopen_self_static
+ fi
+ prefer_static_libs=yes
+ ;;
+ esac
+ build_libtool_libs=no
+ build_old_libs=yes
+ break
+ ;;
+ esac
+ done
+
+ # See if our shared archives depend on static archives.
+ test -n "$old_archive_from_new_cmds" && build_old_libs=yes
+
+ # Go through the arguments, transforming them on the way.
+ while test "$#" -gt 0; do
+ arg="$1"
+ shift
+ func_quote_for_eval "$arg"
+ qarg=$func_quote_for_eval_unquoted_result
+ func_append libtool_args " $func_quote_for_eval_result"
+
+ # If the previous option needs an argument, assign it.
+ if test -n "$prev"; then
+ case $prev in
+ output)
+ func_append compile_command " @OUTPUT@"
+ func_append finalize_command " @OUTPUT@"
+ ;;
+ esac
+
+ case $prev in
+ bindir)
+ bindir="$arg"
+ prev=
+ continue
+ ;;
+ dlfiles|dlprefiles)
+ if test "$preload" = no; then
+ # Add the symbol object into the linking commands.
+ func_append compile_command " @SYMFILE@"
+ func_append finalize_command " @SYMFILE@"
+ preload=yes
+ fi
+ case $arg in
+ *.la | *.lo) ;; # We handle these cases below.
+ force)
+ if test "$dlself" = no; then
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ self)
+ if test "$prev" = dlprefiles; then
+ dlself=yes
+ elif test "$prev" = dlfiles && test "$dlopen_self" != yes; then
+ dlself=yes
+ else
+ dlself=needless
+ export_dynamic=yes
+ fi
+ prev=
+ continue
+ ;;
+ *)
+ if test "$prev" = dlfiles; then
+ func_append dlfiles " $arg"
+ else
+ func_append dlprefiles " $arg"
+ fi
+ prev=
+ continue
+ ;;
+ esac
+ ;;
+ expsyms)
+ export_symbols="$arg"
+ test -f "$arg" \
+ || func_fatal_error "symbol file \`$arg' does not exist"
+ prev=
+ continue
+ ;;
+ expsyms_regex)
+ export_symbols_regex="$arg"
+ prev=
+ continue
+ ;;
+ framework)
+ case $host in
+ *-*-darwin*)
+ case "$deplibs " in
+ *" $qarg.ltframework "*) ;;
+ *) func_append deplibs " $qarg.ltframework" # this is fixed later
+ ;;
+ esac
+ ;;
+ esac
+ prev=
+ continue
+ ;;
+ inst_prefix)
+ inst_prefix_dir="$arg"
+ prev=
+ continue
+ ;;
+ objectlist)
+ if test -f "$arg"; then
+ save_arg=$arg
+ moreargs=
+ for fil in `cat "$save_arg"`
+ do
+# func_append moreargs " $fil"
+ arg=$fil
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ done
+ else
+ func_fatal_error "link input file \`$arg' does not exist"
+ fi
+ arg=$save_arg
+ prev=
+ continue
+ ;;
+ precious_regex)
+ precious_files_regex="$arg"
+ prev=
+ continue
+ ;;
+ release)
+ release="-$arg"
+ prev=
+ continue
+ ;;
+ rpath | xrpath)
+ # We need an absolute path.
+ case $arg in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ if test "$prev" = rpath; then
+ case "$rpath " in
+ *" $arg "*) ;;
+ *) func_append rpath " $arg" ;;
+ esac
+ else
+ case "$xrpath " in
+ *" $arg "*) ;;
+ *) func_append xrpath " $arg" ;;
+ esac
+ fi
+ prev=
+ continue
+ ;;
+ shrext)
+ shrext_cmds="$arg"
+ prev=
+ continue
+ ;;
+ weak)
+ func_append weak_libs " $arg"
+ prev=
+ continue
+ ;;
+ xcclinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xcompiler)
+ func_append compiler_flags " $qarg"
+ prev=
+ func_append compile_command " $qarg"
+ func_append finalize_command " $qarg"
+ continue
+ ;;
+ xlinker)
+ func_append linker_flags " $qarg"
+ func_append compiler_flags " $wl$qarg"
+ prev=
+ func_append compile_command " $wl$qarg"
+ func_append finalize_command " $wl$qarg"
+ continue
+ ;;
+ *)
+ eval "$prev=\"\$arg\""
+ prev=
+ continue
+ ;;
+ esac
+ fi # test -n "$prev"
+
+ prevarg="$arg"
+
+ case $arg in
+ -all-static)
+ if test -n "$link_static_flag"; then
+ # See comment for -static flag below, for more details.
+ func_append compile_command " $link_static_flag"
+ func_append finalize_command " $link_static_flag"
+ fi
+ continue
+ ;;
+
+ -allow-undefined)
+ # FIXME: remove this flag sometime in the future.
+ func_fatal_error "\`-allow-undefined' must not be used because it is the default"
+ ;;
+
+ -avoid-version)
+ avoid_version=yes
+ continue
+ ;;
+
+ -bindir)
+ prev=bindir
+ continue
+ ;;
+
+ -dlopen)
+ prev=dlfiles
+ continue
+ ;;
+
+ -dlpreopen)
+ prev=dlprefiles
+ continue
+ ;;
+
+ -export-dynamic)
+ export_dynamic=yes
+ continue
+ ;;
+
+ -export-symbols | -export-symbols-regex)
+ if test -n "$export_symbols" || test -n "$export_symbols_regex"; then
+ func_fatal_error "more than one -exported-symbols argument is not allowed"
+ fi
+ if test "X$arg" = "X-export-symbols"; then
+ prev=expsyms
+ else
+ prev=expsyms_regex
+ fi
+ continue
+ ;;
+
+ -framework)
+ prev=framework
+ continue
+ ;;
+
+ -inst-prefix-dir)
+ prev=inst_prefix
+ continue
+ ;;
+
+ # The native IRIX linker understands -LANG:*, -LIST:* and -LNO:*
+ # so, if we see these flags be careful not to treat them like -L
+ -L[A-Z][A-Z]*:*)
+ case $with_gcc/$host in
+ no/*-*-irix* | /*-*-irix*)
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ ;;
+ esac
+ continue
+ ;;
+
+ -L*)
+ func_stripname "-L" '' "$arg"
+ if test -z "$func_stripname_result"; then
+ if test "$#" -gt 0; then
+ func_fatal_error "require no space between \`-L' and \`$1'"
+ else
+ func_fatal_error "need path for \`-L' option"
+ fi
+ fi
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ test -z "$absdir" && \
+ func_fatal_error "cannot determine absolute directory name of \`$dir'"
+ dir="$absdir"
+ ;;
+ esac
+ case "$deplibs " in
+ *" -L$dir "* | *" $arg "*)
+ # Will only happen for absolute or sysroot arguments
+ ;;
+ *)
+ # Preserve sysroot, but never include relative directories
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]* | =*) func_append deplibs " $arg" ;;
+ *) func_append deplibs " -L$dir" ;;
+ esac
+ func_append lib_search_path " $dir"
+ ;;
+ esac
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`$ECHO "$dir" | $SED 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$dir:"*) ;;
+ ::) dllsearchpath=$dir;;
+ *) func_append dllsearchpath ":$dir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ continue
+ ;;
+
+ -l*)
+ if test "X$arg" = "X-lc" || test "X$arg" = "X-lm"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # These systems don't actually have a C or math library (as such)
+ continue
+ ;;
+ *-*-os2*)
+ # These systems don't actually have a C library (as such)
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C and math libraries are in the System framework
+ func_append deplibs " System.ltframework"
+ continue
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ test "X$arg" = "X-lc" && continue
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ test "X$arg" = "X-lc" && continue
+ ;;
+ esac
+ elif test "X$arg" = "X-lc_r"; then
+ case $host in
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc_r directly, use -pthread flag.
+ continue
+ ;;
+ esac
+ fi
+ func_append deplibs " $arg"
+ continue
+ ;;
+
+ -module)
+ module=yes
+ continue
+ ;;
+
+ # Tru64 UNIX uses -model [arg] to determine the layout of C++
+ # classes, name mangling, and exception handling.
+ # Darwin uses the -arch flag to determine output architecture.
+ -model|-arch|-isysroot|--sysroot)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ prev=xcompiler
+ continue
+ ;;
+
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ func_append compiler_flags " $arg"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ case "$new_inherited_linker_flags " in
+ *" $arg "*) ;;
+ * ) func_append new_inherited_linker_flags " $arg" ;;
+ esac
+ continue
+ ;;
+
+ -multi_module)
+ single_module="${wl}-multi_module"
+ continue
+ ;;
+
+ -no-fast-install)
+ fast_install=no
+ continue
+ ;;
+
+ -no-install)
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-darwin* | *-cegcc*)
+ # The PATH hackery in wrapper scripts is required on Windows
+ # and Darwin in order for the loader to find any dlls it needs.
+ func_warning "\`-no-install' is ignored for $host"
+ func_warning "assuming \`-no-fast-install' instead"
+ fast_install=no
+ ;;
+ *) no_install=yes ;;
+ esac
+ continue
+ ;;
+
+ -no-undefined)
+ allow_undefined=no
+ continue
+ ;;
+
+ -objectlist)
+ prev=objectlist
+ continue
+ ;;
+
+ -o) prev=output ;;
+
+ -precious-files-regex)
+ prev=precious_regex
+ continue
+ ;;
+
+ -release)
+ prev=release
+ continue
+ ;;
+
+ -rpath)
+ prev=rpath
+ continue
+ ;;
+
+ -R)
+ prev=xrpath
+ continue
+ ;;
+
+ -R*)
+ func_stripname '-R' '' "$arg"
+ dir=$func_stripname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) ;;
+ =*)
+ func_stripname '=' '' "$dir"
+ dir=$lt_sysroot$func_stripname_result
+ ;;
+ *)
+ func_fatal_error "only absolute run-paths are allowed"
+ ;;
+ esac
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ continue
+ ;;
+
+ -shared)
+ # The effects of -shared are defined in a previous loop.
+ continue
+ ;;
+
+ -shrext)
+ prev=shrext
+ continue
+ ;;
+
+ -static | -static-libtool-libs)
+ # The effects of -static are defined in a previous loop.
+ # We used to do the same as -all-static on platforms that
+ # didn't have a PIC flag, but the assumption that the effects
+ # would be equivalent was wrong. It would break on at least
+ # Digital Unix and AIX.
+ continue
+ ;;
+
+ -thread-safe)
+ thread_safe=yes
+ continue
+ ;;
+
+ -version-info)
+ prev=vinfo
+ continue
+ ;;
+
+ -version-number)
+ prev=vinfo
+ vinfo_number=yes
+ continue
+ ;;
+
+ -weak)
+ prev=weak
+ continue
+ ;;
+
+ -Wc,*)
+ func_stripname '-Wc,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ func_append arg " $func_quote_for_eval_result"
+ func_append compiler_flags " $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Wl,*)
+ func_stripname '-Wl,' '' "$arg"
+ args=$func_stripname_result
+ arg=
+ save_ifs="$IFS"; IFS=','
+ for flag in $args; do
+ IFS="$save_ifs"
+ func_quote_for_eval "$flag"
+ func_append arg " $wl$func_quote_for_eval_result"
+ func_append compiler_flags " $wl$func_quote_for_eval_result"
+ func_append linker_flags " $func_quote_for_eval_result"
+ done
+ IFS="$save_ifs"
+ func_stripname ' ' '' "$arg"
+ arg=$func_stripname_result
+ ;;
+
+ -Xcompiler)
+ prev=xcompiler
+ continue
+ ;;
+
+ -Xlinker)
+ prev=xlinker
+ continue
+ ;;
+
+ -XCClinker)
+ prev=xcclinker
+ continue
+ ;;
+
+ # -msg_* for osf cc
+ -msg_*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ # Flags to be passed through unchanged, with rationale:
+ # -64, -mips[0-9] enable 64-bit mode for the SGI compiler
+ # -r[0-9][0-9]* specify processor for the SGI compiler
+ # -xarch=*, -xtarget=* enable 64-bit mode for the Sun compiler
+ # +DA*, +DD* enable 64-bit mode for the HP compiler
+ # -q* compiler args for the IBM compiler
+ # -m*, -t[45]*, -txscale* architecture-specific flags for GCC
+ # -F/path path to uninstalled frameworks, gcc on darwin
+ # -p, -pg, --coverage, -fprofile-* profiling flags for GCC
+ # @file GCC response files
+ # -tp=* Portland pgcc target processor selection
+ # --sysroot=* for sysroot support
+ # -O*, -flto*, -fwhopr*, -fuse-linker-plugin GCC link-time optimization
+ -64|-mips[0-9]|-r[0-9][0-9]*|-xarch=*|-xtarget=*|+DA*|+DD*|-q*|-m*| \
+ -t[45]*|-txscale*|-p|-pg|--coverage|-fprofile-*|-F*|@*|-tp=*|--sysroot=*| \
+ -O*|-flto*|-fwhopr*|-fuse-linker-plugin)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ func_append compiler_flags " $arg"
+ continue
+ ;;
+
+ # Some other compiler flag.
+ -* | +*)
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+
+ *.$objext)
+ # A standard object.
+ func_append objs " $arg"
+ ;;
+
+ *.lo)
+ # A libtool-controlled object.
+
+ # Check to see that this really is a libtool object.
+ if func_lalib_unsafe_p "$arg"; then
+ pic_object=
+ non_pic_object=
+
+ # Read the .lo file
+ func_source "$arg"
+
+ if test -z "$pic_object" ||
+ test -z "$non_pic_object" ||
+ test "$pic_object" = none &&
+ test "$non_pic_object" = none; then
+ func_fatal_error "cannot find name of object for \`$arg'"
+ fi
+
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ if test "$pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ pic_object="$xdir$pic_object"
+
+ if test "$prev" = dlfiles; then
+ if test "$build_libtool_libs" = yes && test "$dlopen_support" = yes; then
+ func_append dlfiles " $pic_object"
+ prev=
+ continue
+ else
+ # If libtool objects are unsupported, then we need to preload.
+ prev=dlprefiles
+ fi
+ fi
+
+ # CHECK ME: I think I busted this. -Ossama
+ if test "$prev" = dlprefiles; then
+ # Preload the old-style object.
+ func_append dlprefiles " $pic_object"
+ prev=
+ fi
+
+ # A PIC object.
+ func_append libobjs " $pic_object"
+ arg="$pic_object"
+ fi
+
+ # Non-PIC object.
+ if test "$non_pic_object" != none; then
+ # Prepend the subdirectory the object is found in.
+ non_pic_object="$xdir$non_pic_object"
+
+ # A standard non-PIC object
+ func_append non_pic_objects " $non_pic_object"
+ if test -z "$pic_object" || test "$pic_object" = none ; then
+ arg="$non_pic_object"
+ fi
+ else
+ # If the PIC object exists, use it instead.
+ # $xdir was prepended to $pic_object above.
+ non_pic_object="$pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ fi
+ else
+ # Only an error if not doing a dry-run.
+ if $opt_dry_run; then
+ # Extract subdirectory from the argument.
+ func_dirname "$arg" "/" ""
+ xdir="$func_dirname_result"
+
+ func_lo2o "$arg"
+ pic_object=$xdir$objdir/$func_lo2o_result
+ non_pic_object=$xdir$func_lo2o_result
+ func_append libobjs " $pic_object"
+ func_append non_pic_objects " $non_pic_object"
+ else
+ func_fatal_error "\`$arg' is not a valid libtool object"
+ fi
+ fi
+ ;;
+
+ *.$libext)
+ # An archive.
+ func_append deplibs " $arg"
+ func_append old_deplibs " $arg"
+ continue
+ ;;
+
+ *.la)
+ # A libtool-controlled library.
+
+ func_resolve_sysroot "$arg"
+ if test "$prev" = dlfiles; then
+ # This library was specified with -dlopen.
+ func_append dlfiles " $func_resolve_sysroot_result"
+ prev=
+ elif test "$prev" = dlprefiles; then
+ # The library was specified with -dlpreopen.
+ func_append dlprefiles " $func_resolve_sysroot_result"
+ prev=
+ else
+ func_append deplibs " $func_resolve_sysroot_result"
+ fi
+ continue
+ ;;
+
+ # Some other compiler argument.
+ *)
+ # Unknown arguments in both finalize_command and compile_command need
+ # to be aesthetically quoted because they are evaled later.
+ func_quote_for_eval "$arg"
+ arg="$func_quote_for_eval_result"
+ ;;
+ esac # arg
+
+ # Now actually substitute the argument into the commands.
+ if test -n "$arg"; then
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+ done # argument parsing loop
+
+ test -n "$prev" && \
+ func_fatal_help "the \`$prevarg' option requires an argument"
+
+ if test "$export_dynamic" = yes && test -n "$export_dynamic_flag_spec"; then
+ eval arg=\"$export_dynamic_flag_spec\"
+ func_append compile_command " $arg"
+ func_append finalize_command " $arg"
+ fi
+
+ oldlibs=
+ # calculate the name of the file, without its directory
+ func_basename "$output"
+ outputname="$func_basename_result"
+ libobjs_save="$libobjs"
+
+ if test -n "$shlibpath_var"; then
+ # get the directories listed in $shlibpath_var
+ eval shlib_search_path=\`\$ECHO \"\${$shlibpath_var}\" \| \$SED \'s/:/ /g\'\`
+ else
+ shlib_search_path=
+ fi
+ eval sys_lib_search_path=\"$sys_lib_search_path_spec\"
+ eval sys_lib_dlsearch_path=\"$sys_lib_dlsearch_path_spec\"
+
+ func_dirname "$output" "/" ""
+ output_objdir="$func_dirname_result$objdir"
+ func_to_tool_file "$output_objdir/"
+ tool_output_objdir=$func_to_tool_file_result
+ # Create the object directory.
+ func_mkdir_p "$output_objdir"
+
+ # Determine the type of output
+ case $output in
+ "")
+ func_fatal_help "you must specify an output file"
+ ;;
+ *.$libext) linkmode=oldlib ;;
+ *.lo | *.$objext) linkmode=obj ;;
+ *.la) linkmode=lib ;;
+ *) linkmode=prog ;; # Anything else should be a program.
+ esac
+
+ specialdeplibs=
+
+ libs=
+ # Find all interdependent deplibs by searching for libraries
+ # that are linked more than once (e.g. -la -lb -la)
+ for deplib in $deplibs; do
+ if $opt_preserve_dup_deps ; then
+ case "$libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append libs " $deplib"
+ done
+
+ if test "$linkmode" = lib; then
+ libs="$predeps $libs $compiler_lib_search_path $postdeps"
+
+ # Compute libraries that are listed more than once in $predeps
+ # $postdeps and mark them as special (i.e., whose duplicates are
+ # not to be eliminated).
+ pre_post_deps=
+ if $opt_duplicate_compiler_generated_deps; then
+ for pre_post_dep in $predeps $postdeps; do
+ case "$pre_post_deps " in
+ *" $pre_post_dep "*) func_append specialdeplibs " $pre_post_deps" ;;
+ esac
+ func_append pre_post_deps " $pre_post_dep"
+ done
+ fi
+ pre_post_deps=
+ fi
+
+ deplibs=
+ newdependency_libs=
+ newlib_search_path=
+ need_relink=no # whether we're linking any uninstalled libtool libraries
+ notinst_deplibs= # not-installed libtool libraries
+ notinst_path= # paths that contain not-installed libtool libraries
+
+ case $linkmode in
+ lib)
+ passes="conv dlpreopen link"
+ for file in $dlfiles $dlprefiles; do
+ case $file in
+ *.la) ;;
+ *)
+ func_fatal_help "libraries can \`-dlopen' only libtool libraries: $file"
+ ;;
+ esac
+ done
+ ;;
+ prog)
+ compile_deplibs=
+ finalize_deplibs=
+ alldeplibs=no
+ newdlfiles=
+ newdlprefiles=
+ passes="conv scan dlopen dlpreopen link"
+ ;;
+ *) passes="conv"
+ ;;
+ esac
+
+ for pass in $passes; do
+ # The preopen pass in lib mode reverses $deplibs; put it back here
+ # so that -L comes before libs that need it for instance...
+ if test "$linkmode,$pass" = "lib,link"; then
+ ## FIXME: Find the place where the list is rebuilt in the wrong
+ ## order, and fix it there properly
+ tmp_deplibs=
+ for deplib in $deplibs; do
+ tmp_deplibs="$deplib $tmp_deplibs"
+ done
+ deplibs="$tmp_deplibs"
+ fi
+
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan"; then
+ libs="$deplibs"
+ deplibs=
+ fi
+ if test "$linkmode" = prog; then
+ case $pass in
+ dlopen) libs="$dlfiles" ;;
+ dlpreopen) libs="$dlprefiles" ;;
+ link)
+ libs="$deplibs %DEPLIBS%"
+ test "X$link_all_deplibs" != Xno && libs="$libs $dependency_libs"
+ ;;
+ esac
+ fi
+ if test "$linkmode,$pass" = "lib,dlpreopen"; then
+ # Collect and forward deplibs of preopened libtool libs
+ for lib in $dlprefiles; do
+ # Ignore non-libtool-libs
+ dependency_libs=
+ func_resolve_sysroot "$lib"
+ case $lib in
+ *.la) func_source "$func_resolve_sysroot_result" ;;
+ esac
+
+ # Collect preopened libtool deplibs, except any this library
+ # has declared as weak libs
+ for deplib in $dependency_libs; do
+ func_basename "$deplib"
+ deplib_base=$func_basename_result
+ case " $weak_libs " in
+ *" $deplib_base "*) ;;
+ *) func_append deplibs " $deplib" ;;
+ esac
+ done
+ done
+ libs="$dlprefiles"
+ fi
+ if test "$pass" = dlopen; then
+ # Collect dlpreopened libraries
+ save_deplibs="$deplibs"
+ deplibs=
+ fi
+
+ for deplib in $libs; do
+ lib=
+ found=no
+ case $deplib in
+ -mt|-mthreads|-kthread|-Kthread|-pthread|-pthreads|--thread-safe \
+ |-threads|-fopenmp|-openmp|-mp|-xopenmp|-omp|-qsmp=*)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append compiler_flags " $deplib"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -l*)
+ if test "$linkmode" != lib && test "$linkmode" != prog; then
+ func_warning "\`-l' is ignored for archives/objects"
+ continue
+ fi
+ func_stripname '-l' '' "$deplib"
+ name=$func_stripname_result
+ if test "$linkmode" = lib; then
+ searchdirs="$newlib_search_path $lib_search_path $compiler_lib_search_dirs $sys_lib_search_path $shlib_search_path"
+ else
+ searchdirs="$newlib_search_path $lib_search_path $sys_lib_search_path $shlib_search_path"
+ fi
+ for searchdir in $searchdirs; do
+ for search_ext in .la $std_shrext .so .a; do
+ # Search the libtool library
+ lib="$searchdir/lib${name}${search_ext}"
+ if test -f "$lib"; then
+ if test "$search_ext" = ".la"; then
+ found=yes
+ else
+ found=no
+ fi
+ break 2
+ fi
+ done
+ done
+ if test "$found" != yes; then
+ # deplib doesn't seem to be a libtool library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ else # deplib is a libtool library
+ # If $allow_libtool_libs_with_static_runtimes && $deplib is a stdlib,
+ # We need to do some special things here, and not later.
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $deplib "*)
+ if func_lalib_p "$lib"; then
+ library_names=
+ old_library=
+ func_source "$lib"
+ for l in $old_library $library_names; do
+ ll="$l"
+ done
+ if test "X$ll" = "X$old_library" ; then # only static version available
+ found=no
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+ lib=$ladir/$old_library
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ test "$linkmode" = lib && newdependency_libs="$deplib $newdependency_libs"
+ fi
+ continue
+ fi
+ fi
+ ;;
+ *) ;;
+ esac
+ fi
+ fi
+ ;; # -l
+ *.ltframework)
+ if test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ deplibs="$deplib $deplibs"
+ if test "$linkmode" = lib ; then
+ case "$new_inherited_linker_flags " in
+ *" $deplib "*) ;;
+ * ) func_append new_inherited_linker_flags " $deplib" ;;
+ esac
+ fi
+ fi
+ continue
+ ;;
+ -L*)
+ case $linkmode in
+ lib)
+ deplibs="$deplib $deplibs"
+ test "$pass" = conv && continue
+ newdependency_libs="$deplib $newdependency_libs"
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ prog)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ if test "$pass" = scan; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ *)
+ func_warning "\`-L' is ignored for archives/objects"
+ ;;
+ esac # linkmode
+ continue
+ ;; # -L
+ -R*)
+ if test "$pass" = link; then
+ func_stripname '-R' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ dir=$func_resolve_sysroot_result
+ # Make sure the xrpath contains only unique directories.
+ case "$xrpath " in
+ *" $dir "*) ;;
+ *) func_append xrpath " $dir" ;;
+ esac
+ fi
+ deplibs="$deplib $deplibs"
+ continue
+ ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ lib=$func_resolve_sysroot_result
+ ;;
+ *.$libext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ continue
+ fi
+ case $linkmode in
+ lib)
+ # Linking convenience modules into shared libraries is allowed,
+ # but linking other static libraries is non-portable.
+ case " $dlpreconveniencelibs " in
+ *" $deplib "*) ;;
+ *)
+ valid_a_lib=no
+ case $deplibs_check_method in
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ if eval "\$ECHO \"$deplib\"" 2>/dev/null | $SED 10q \
+ | $EGREP "$match_pattern_regex" > /dev/null; then
+ valid_a_lib=yes
+ fi
+ ;;
+ pass_all)
+ valid_a_lib=yes
+ ;;
+ esac
+ if test "$valid_a_lib" != yes; then
+ echo
+ $ECHO "*** Warning: Trying to link with static lib archive $deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because the file extensions .$libext of this argument makes me believe"
+ echo "*** that it is just a static archive that I should not use here."
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the"
+ $ECHO "*** static library $deplib is not portable!"
+ deplibs="$deplib $deplibs"
+ fi
+ ;;
+ esac
+ continue
+ ;;
+ prog)
+ if test "$pass" != link; then
+ deplibs="$deplib $deplibs"
+ else
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ fi
+ continue
+ ;;
+ esac # linkmode
+ ;; # *.$libext
+ *.lo | *.$objext)
+ if test "$pass" = conv; then
+ deplibs="$deplib $deplibs"
+ elif test "$linkmode" = prog; then
+ if test "$pass" = dlpreopen || test "$dlopen_support" != yes || test "$build_libtool_libs" = no; then
+ # If there is no dlopen support or we're linking statically,
+ # we need to preload.
+ func_append newdlprefiles " $deplib"
+ compile_deplibs="$deplib $compile_deplibs"
+ finalize_deplibs="$deplib $finalize_deplibs"
+ else
+ func_append newdlfiles " $deplib"
+ fi
+ fi
+ continue
+ ;;
+ %DEPLIBS%)
+ alldeplibs=yes
+ continue
+ ;;
+ esac # case $deplib
+
+ if test "$found" = yes || test -f "$lib"; then :
+ else
+ func_fatal_error "cannot find the library \`$lib' or unhandled argument \`$deplib'"
+ fi
+
+ # Check to see that this really is a libtool archive.
+ func_lalib_unsafe_p "$lib" \
+ || func_fatal_error "\`$lib' is not a valid libtool archive"
+
+ func_dirname "$lib" "" "."
+ ladir="$func_dirname_result"
+
+ dlname=
+ dlopen=
+ dlpreopen=
+ libdir=
+ library_names=
+ old_library=
+ inherited_linker_flags=
+ # If the library was installed with an old release of libtool,
+ # it will not redefine variables installed, or shouldnotlink
+ installed=yes
+ shouldnotlink=no
+ avoidtemprpath=
+
+
+ # Read the .la file
+ func_source "$lib"
+
+ # Convert "-framework foo" to "foo.ltframework"
+ if test -n "$inherited_linker_flags"; then
+ tmp_inherited_linker_flags=`$ECHO "$inherited_linker_flags" | $SED 's/-framework \([^ $]*\)/\1.ltframework/g'`
+ for tmp_inherited_linker_flag in $tmp_inherited_linker_flags; do
+ case " $new_inherited_linker_flags " in
+ *" $tmp_inherited_linker_flag "*) ;;
+ *) func_append new_inherited_linker_flags " $tmp_inherited_linker_flag";;
+ esac
+ done
+ fi
+ dependency_libs=`$ECHO " $dependency_libs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ if test "$linkmode,$pass" = "lib,link" ||
+ test "$linkmode,$pass" = "prog,scan" ||
+ { test "$linkmode" != prog && test "$linkmode" != lib; }; then
+ test -n "$dlopen" && func_append dlfiles " $dlopen"
+ test -n "$dlpreopen" && func_append dlprefiles " $dlpreopen"
+ fi
+
+ if test "$pass" = conv; then
+ # Only check for convenience libraries
+ deplibs="$lib $deplibs"
+ if test -z "$libdir"; then
+ if test -z "$old_library"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+ # It is a libtool convenience library, so add in its objects.
+ func_append convenience " $ladir/$objdir/$old_library"
+ func_append old_convenience " $ladir/$objdir/$old_library"
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ deplibs="$deplib $deplibs"
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done
+ elif test "$linkmode" != prog && test "$linkmode" != lib; then
+ func_fatal_error "\`$lib' is not a convenience library"
+ fi
+ continue
+ fi # $pass = conv
+
+
+ # Get the name of the library we link against.
+ linklib=
+ if test -n "$old_library" &&
+ { test "$prefer_static_libs" = yes ||
+ test "$prefer_static_libs,$installed" = "built,no"; }; then
+ linklib=$old_library
+ else
+ for l in $old_library $library_names; do
+ linklib="$l"
+ done
+ fi
+ if test -z "$linklib"; then
+ func_fatal_error "cannot find name of link library for \`$lib'"
+ fi
+
+ # This library was specified with -dlopen.
+ if test "$pass" = dlopen; then
+ if test -z "$libdir"; then
+ func_fatal_error "cannot -dlopen a convenience library: \`$lib'"
+ fi
+ if test -z "$dlname" ||
+ test "$dlopen_support" != yes ||
+ test "$build_libtool_libs" = no; then
+ # If there is no dlname, no dlopen support or we're linking
+ # statically, we need to preload. We also need to preload any
+ # dependent libraries so libltdl's deplib preloader doesn't
+ # bomb out in the load deplibs phase.
+ func_append dlprefiles " $lib $dependency_libs"
+ else
+ func_append newdlfiles " $lib"
+ fi
+ continue
+ fi # $pass = dlopen
+
+ # We need an absolute path.
+ case $ladir in
+ [\\/]* | [A-Za-z]:[\\/]*) abs_ladir="$ladir" ;;
+ *)
+ abs_ladir=`cd "$ladir" && pwd`
+ if test -z "$abs_ladir"; then
+ func_warning "cannot determine absolute directory name of \`$ladir'"
+ func_warning "passing it literally to the linker, although it might fail"
+ abs_ladir="$ladir"
+ fi
+ ;;
+ esac
+ func_basename "$lib"
+ laname="$func_basename_result"
+
+ # Find the relevant object directory and library name.
+ if test "X$installed" = Xyes; then
+ if test ! -f "$lt_sysroot$libdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ func_warning "library \`$lib' was moved."
+ dir="$ladir"
+ absdir="$abs_ladir"
+ libdir="$abs_ladir"
+ else
+ dir="$lt_sysroot$libdir"
+ absdir="$lt_sysroot$libdir"
+ fi
+ test "X$hardcode_automatic" = Xyes && avoidtemprpath=yes
+ else
+ if test ! -f "$ladir/$objdir/$linklib" && test -f "$abs_ladir/$linklib"; then
+ dir="$ladir"
+ absdir="$abs_ladir"
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ else
+ dir="$ladir/$objdir"
+ absdir="$abs_ladir/$objdir"
+ # Remove this search path later
+ func_append notinst_path " $abs_ladir"
+ fi
+ fi # $installed = yes
+ func_stripname 'lib' '.la' "$laname"
+ name=$func_stripname_result
+
+ # This library was specified with -dlpreopen.
+ if test "$pass" = dlpreopen; then
+ if test -z "$libdir" && test "$linkmode" = prog; then
+ func_fatal_error "only libraries may -dlpreopen a convenience library: \`$lib'"
+ fi
+ case "$host" in
+ # special handling for platforms with PE-DLLs.
+ *cygwin* | *mingw* | *cegcc* )
+ # Linker will automatically link against shared library if both
+ # static and shared are present. Therefore, ensure we extract
+ # symbols from the import library if a shared library is present
+ # (otherwise, the dlopen module name will be incorrect). We do
+ # this by putting the import library name into $newdlprefiles.
+ # We recover the dlopen module name by 'saving' the la file
+ # name in a special purpose variable, and (later) extracting the
+ # dlname from the la file.
+ if test -n "$dlname"; then
+ func_tr_sh "$dir/$linklib"
+ eval "libfile_$func_tr_sh_result=\$abs_ladir/\$laname"
+ func_append newdlprefiles " $dir/$linklib"
+ else
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ fi
+ ;;
+ * )
+ # Prefer using a static library (so that no silly _DYNAMIC symbols
+ # are required to link).
+ if test -n "$old_library"; then
+ func_append newdlprefiles " $dir/$old_library"
+ # Keep a list of preopened convenience libraries to check
+ # that they are being used correctly in the link pass.
+ test -z "$libdir" && \
+ func_append dlpreconveniencelibs " $dir/$old_library"
+ # Otherwise, use the dlname, so that lt_dlopen finds it.
+ elif test -n "$dlname"; then
+ func_append newdlprefiles " $dir/$dlname"
+ else
+ func_append newdlprefiles " $dir/$linklib"
+ fi
+ ;;
+ esac
+ fi # $pass = dlpreopen
+
+ if test -z "$libdir"; then
+ # Link the convenience library
+ if test "$linkmode" = lib; then
+ deplibs="$dir/$old_library $deplibs"
+ elif test "$linkmode,$pass" = "prog,link"; then
+ compile_deplibs="$dir/$old_library $compile_deplibs"
+ finalize_deplibs="$dir/$old_library $finalize_deplibs"
+ else
+ deplibs="$lib $deplibs" # used for prog,scan pass
+ fi
+ continue
+ fi
+
+
+ if test "$linkmode" = prog && test "$pass" != link; then
+ func_append newlib_search_path " $ladir"
+ deplibs="$lib $deplibs"
+
+ linkalldeplibs=no
+ if test "$link_all_deplibs" != no || test -z "$library_names" ||
+ test "$build_libtool_libs" = no; then
+ linkalldeplibs=yes
+ fi
+
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result"
+ func_append newlib_search_path " $func_resolve_sysroot_result"
+ ;;
+ esac
+ # Need to link against all dependency_libs?
+ if test "$linkalldeplibs" = yes; then
+ deplibs="$deplib $deplibs"
+ else
+ # Need to hardcode shared library paths
+ # or/and link against static libraries
+ newdependency_libs="$deplib $newdependency_libs"
+ fi
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $deplib "*) func_append specialdeplibs " $deplib" ;;
+ esac
+ fi
+ func_append tmp_libs " $deplib"
+ done # for deplib
+ continue
+ fi # $linkmode = prog...
+
+ if test "$linkmode,$pass" = "prog,link"; then
+ if test -n "$library_names" &&
+ { { test "$prefer_static_libs" = no ||
+ test "$prefer_static_libs,$installed" = "built,yes"; } ||
+ test -z "$old_library"; }; then
+ # We need to hardcode the library path
+ if test -n "$shlibpath_var" && test -z "$avoidtemprpath" ; then
+ # Make sure the rpath contains only unique directories.
+ case "$temp_rpath:" in
+ *"$absdir:"*) ;;
+ *) func_append temp_rpath "$absdir:" ;;
+ esac
+ fi
+
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi # $linkmode,$pass = prog,link...
+
+ if test "$alldeplibs" = yes &&
+ { test "$deplibs_check_method" = pass_all ||
+ { test "$build_libtool_libs" = yes &&
+ test -n "$library_names"; }; }; then
+ # We only need to search for static libraries
+ continue
+ fi
+ fi
+
+ link_static=no # Whether the deplib will be linked statically
+ use_static_libs=$prefer_static_libs
+ if test "$use_static_libs" = built && test "$installed" = yes; then
+ use_static_libs=no
+ fi
+ if test -n "$library_names" &&
+ { test "$use_static_libs" = no || test -z "$old_library"; }; then
+ case $host in
+ *cygwin* | *mingw* | *cegcc*)
+ # No point in relinking DLLs because paths are not encoded
+ func_append notinst_deplibs " $lib"
+ need_relink=no
+ ;;
+ *)
+ if test "$installed" = no; then
+ func_append notinst_deplibs " $lib"
+ need_relink=yes
+ fi
+ ;;
+ esac
+ # This is a shared library
+
+ # Warn about portability, can't link against -module's on some
+ # systems (darwin). Don't bleat about dlopened modules though!
+ dlopenmodule=""
+ for dlpremoduletest in $dlprefiles; do
+ if test "X$dlpremoduletest" = "X$lib"; then
+ dlopenmodule="$dlpremoduletest"
+ break
+ fi
+ done
+ if test -z "$dlopenmodule" && test "$shouldnotlink" = yes && test "$pass" = link; then
+ echo
+ if test "$linkmode" = prog; then
+ $ECHO "*** Warning: Linking the executable $output against the loadable module"
+ else
+ $ECHO "*** Warning: Linking the shared library $output against the loadable module"
+ fi
+ $ECHO "*** $linklib is not portable!"
+ fi
+ if test "$linkmode" = lib &&
+ test "$hardcode_into_libs" = yes; then
+ # Hardcode the library path.
+ # Skip directories that are in the system default run-time
+ # search path.
+ case " $sys_lib_dlsearch_path " in
+ *" $absdir "*) ;;
+ *)
+ case "$compile_rpath " in
+ *" $absdir "*) ;;
+ *) func_append compile_rpath " $absdir" ;;
+ esac
+ ;;
+ esac
+ case " $sys_lib_dlsearch_path " in
+ *" $libdir "*) ;;
+ *)
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ ;;
+ esac
+ fi
+
+ if test -n "$old_archive_from_expsyms_cmds"; then
+ # figure out the soname
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ # use dlname if we got it. it's perfectly good, no?
+ if test -n "$dlname"; then
+ soname="$dlname"
+ elif test -n "$soname_spec"; then
+ # bleh windows
+ case $host in
+ *cygwin* | mingw* | *cegcc*)
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+ esac
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+
+ # Make a new name for the extract_expsyms_cmds to use
+ soroot="$soname"
+ func_basename "$soroot"
+ soname="$func_basename_result"
+ func_stripname 'lib' '.dll' "$soname"
+ newlib=libimp-$func_stripname_result.a
+
+ # If the library has no export list, then create one now
+ if test -f "$output_objdir/$soname-def"; then :
+ else
+ func_verbose "extracting exported symbol list from \`$soname'"
+ func_execute_cmds "$extract_expsyms_cmds" 'exit $?'
+ fi
+
+ # Create $newlib
+ if test -f "$output_objdir/$newlib"; then :; else
+ func_verbose "generating import library for \`$soname'"
+ func_execute_cmds "$old_archive_from_expsyms_cmds" 'exit $?'
+ fi
+ # make sure the library variables are pointing to the new library
+ dir=$output_objdir
+ linklib=$newlib
+ fi # test -n "$old_archive_from_expsyms_cmds"
+
+ if test "$linkmode" = prog || test "$opt_mode" != relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ lib_linked=yes
+ case $hardcode_action in
+ immediate | unsupported)
+ if test "$hardcode_direct" = no; then
+ add="$dir/$linklib"
+ case $host in
+ *-*-sco3.2v5.0.[024]*) add_dir="-L$dir" ;;
+ *-*-sysv4*uw2*) add_dir="-L$dir" ;;
+ *-*-sysv5OpenUNIX* | *-*-sysv5UnixWare7.[01].[10]* | \
+ *-*-unixware7*) add_dir="-L$dir" ;;
+ *-*-darwin* )
+ # if the lib is a (non-dlopened) module then we can not
+ # link against it, someone is ignoring the earlier warnings
+ if /usr/bin/file -L $add 2> /dev/null |
+ $GREP ": [^:]* bundle" >/dev/null ; then
+ if test "X$dlopenmodule" != "X$lib"; then
+ $ECHO "*** Warning: lib $linklib is a module, not a shared library"
+ if test -z "$old_library" ; then
+ echo
+ echo "*** And there doesn't seem to be a static archive available"
+ echo "*** The link will probably fail, sorry"
+ else
+ add="$dir/$old_library"
+ fi
+ elif test -n "$old_library"; then
+ add="$dir/$old_library"
+ fi
+ fi
+ esac
+ elif test "$hardcode_minus_L" = no; then
+ case $host in
+ *-*-sunos*) add_shlibpath="$dir" ;;
+ esac
+ add_dir="-L$dir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = no; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ relink)
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$dir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$absdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ add_shlibpath="$dir"
+ add="-l$name"
+ else
+ lib_linked=no
+ fi
+ ;;
+ *) lib_linked=no ;;
+ esac
+
+ if test "$lib_linked" != yes; then
+ func_fatal_configuration "unsupported hardcode properties"
+ fi
+
+ if test -n "$add_shlibpath"; then
+ case :$compile_shlibpath: in
+ *":$add_shlibpath:"*) ;;
+ *) func_append compile_shlibpath "$add_shlibpath:" ;;
+ esac
+ fi
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && compile_deplibs="$add_dir $compile_deplibs"
+ test -n "$add" && compile_deplibs="$add $compile_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ if test "$hardcode_direct" != yes &&
+ test "$hardcode_minus_L" != yes &&
+ test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ fi
+ fi
+ fi
+
+ if test "$linkmode" = prog || test "$opt_mode" = relink; then
+ add_shlibpath=
+ add_dir=
+ add=
+ # Finalize command for both is simple: just hardcode it.
+ if test "$hardcode_direct" = yes &&
+ test "$hardcode_direct_absolute" = no; then
+ add="$libdir/$linklib"
+ elif test "$hardcode_minus_L" = yes; then
+ add_dir="-L$libdir"
+ add="-l$name"
+ elif test "$hardcode_shlibpath_var" = yes; then
+ case :$finalize_shlibpath: in
+ *":$libdir:"*) ;;
+ *) func_append finalize_shlibpath "$libdir:" ;;
+ esac
+ add="-l$name"
+ elif test "$hardcode_automatic" = yes; then
+ if test -n "$inst_prefix_dir" &&
+ test -f "$inst_prefix_dir$libdir/$linklib" ; then
+ add="$inst_prefix_dir$libdir/$linklib"
+ else
+ add="$libdir/$linklib"
+ fi
+ else
+ # We cannot seem to hardcode it, guess we'll fake it.
+ add_dir="-L$libdir"
+ # Try looking first in the location we're being installed to.
+ if test -n "$inst_prefix_dir"; then
+ case $libdir in
+ [\\/]*)
+ func_append add_dir " -L$inst_prefix_dir$libdir"
+ ;;
+ esac
+ fi
+ add="-l$name"
+ fi
+
+ if test "$linkmode" = prog; then
+ test -n "$add_dir" && finalize_deplibs="$add_dir $finalize_deplibs"
+ test -n "$add" && finalize_deplibs="$add $finalize_deplibs"
+ else
+ test -n "$add_dir" && deplibs="$add_dir $deplibs"
+ test -n "$add" && deplibs="$add $deplibs"
+ fi
+ fi
+ elif test "$linkmode" = prog; then
+ # Here we assume that one of hardcode_direct or hardcode_minus_L
+ # is not unsupported. This is valid on all known static and
+ # shared platforms.
+ if test "$hardcode_direct" != unsupported; then
+ test -n "$old_library" && linklib="$old_library"
+ compile_deplibs="$dir/$linklib $compile_deplibs"
+ finalize_deplibs="$dir/$linklib $finalize_deplibs"
+ else
+ compile_deplibs="-l$name -L$dir $compile_deplibs"
+ finalize_deplibs="-l$name -L$dir $finalize_deplibs"
+ fi
+ elif test "$build_libtool_libs" = yes; then
+ # Not a shared library
+ if test "$deplibs_check_method" != pass_all; then
+ # We're trying link a shared library against a static one
+ # but the system doesn't support it.
+
+ # Just print a warning and add the library to dependency_libs so
+ # that the program can be linked against the static library.
+ echo
+ $ECHO "*** Warning: This system can not link to static lib archive $lib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have."
+ if test "$module" = yes; then
+ echo "*** But as you try to build a module library, libtool will still create "
+ echo "*** a static module, that should work as long as the dlopening application"
+ echo "*** is linked with the -dlopen flag to resolve symbols at runtime."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ else
+ deplibs="$dir/$old_library $deplibs"
+ link_static=yes
+ fi
+ fi # link shared/static library?
+
+ if test "$linkmode" = lib; then
+ if test -n "$dependency_libs" &&
+ { test "$hardcode_into_libs" != yes ||
+ test "$build_old_libs" = yes ||
+ test "$link_static" = yes; }; then
+ # Extract -R from dependency_libs
+ temp_deplibs=
+ for libdir in $dependency_libs; do
+ case $libdir in
+ -R*) func_stripname '-R' '' "$libdir"
+ temp_xrpath=$func_stripname_result
+ case " $xrpath " in
+ *" $temp_xrpath "*) ;;
+ *) func_append xrpath " $temp_xrpath";;
+ esac;;
+ *) func_append temp_deplibs " $libdir";;
+ esac
+ done
+ dependency_libs="$temp_deplibs"
+ fi
+
+ func_append newlib_search_path " $absdir"
+ # Link against this library
+ test "$link_static" = no && newdependency_libs="$abs_ladir/$laname $newdependency_libs"
+ # ... and its dependency_libs
+ tmp_libs=
+ for deplib in $dependency_libs; do
+ newdependency_libs="$deplib $newdependency_libs"
+ case $deplib in
+ -L*) func_stripname '-L' '' "$deplib"
+ func_resolve_sysroot "$func_stripname_result";;
+ *) func_resolve_sysroot "$deplib" ;;
+ esac
+ if $opt_preserve_dup_deps ; then
+ case "$tmp_libs " in
+ *" $func_resolve_sysroot_result "*)
+ func_append specialdeplibs " $func_resolve_sysroot_result" ;;
+ esac
+ fi
+ func_append tmp_libs " $func_resolve_sysroot_result"
+ done
+
+ if test "$link_all_deplibs" != no; then
+ # Add the search paths of all dependency libraries
+ for deplib in $dependency_libs; do
+ path=
+ case $deplib in
+ -L*) path="$deplib" ;;
+ *.la)
+ func_resolve_sysroot "$deplib"
+ deplib=$func_resolve_sysroot_result
+ func_dirname "$deplib" "" "."
+ dir=$func_dirname_result
+ # We need an absolute path.
+ case $dir in
+ [\\/]* | [A-Za-z]:[\\/]*) absdir="$dir" ;;
+ *)
+ absdir=`cd "$dir" && pwd`
+ if test -z "$absdir"; then
+ func_warning "cannot determine absolute directory name of \`$dir'"
+ absdir="$dir"
+ fi
+ ;;
+ esac
+ if $GREP "^installed=no" $deplib > /dev/null; then
+ case $host in
+ *-*-darwin*)
+ depdepl=
+ eval deplibrary_names=`${SED} -n -e 's/^library_names=\(.*\)$/\1/p' $deplib`
+ if test -n "$deplibrary_names" ; then
+ for tmp in $deplibrary_names ; do
+ depdepl=$tmp
+ done
+ if test -f "$absdir/$objdir/$depdepl" ; then
+ depdepl="$absdir/$objdir/$depdepl"
+ darwin_install_name=`${OTOOL} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ if test -z "$darwin_install_name"; then
+ darwin_install_name=`${OTOOL64} -L $depdepl | awk '{if (NR == 2) {print $1;exit}}'`
+ fi
+ func_append compiler_flags " ${wl}-dylib_file ${wl}${darwin_install_name}:${depdepl}"
+ func_append linker_flags " -dylib_file ${darwin_install_name}:${depdepl}"
+ path=
+ fi
+ fi
+ ;;
+ *)
+ path="-L$absdir/$objdir"
+ ;;
+ esac
+ else
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $deplib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ test "$absdir" != "$libdir" && \
+ func_warning "\`$deplib' seems to be moved"
+
+ path="-L$absdir"
+ fi
+ ;;
+ esac
+ case " $deplibs " in
+ *" $path "*) ;;
+ *) deplibs="$path $deplibs" ;;
+ esac
+ done
+ fi # link_all_deplibs != no
+ fi # linkmode = lib
+ done # for deplib in $libs
+ if test "$pass" = link; then
+ if test "$linkmode" = "prog"; then
+ compile_deplibs="$new_inherited_linker_flags $compile_deplibs"
+ finalize_deplibs="$new_inherited_linker_flags $finalize_deplibs"
+ else
+ compiler_flags="$compiler_flags "`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ fi
+ fi
+ dependency_libs="$newdependency_libs"
+ if test "$pass" = dlpreopen; then
+ # Link the dlpreopened libraries before other libraries
+ for deplib in $save_deplibs; do
+ deplibs="$deplib $deplibs"
+ done
+ fi
+ if test "$pass" != dlopen; then
+ if test "$pass" != conv; then
+ # Make sure lib_search_path contains only unique directories.
+ lib_search_path=
+ for dir in $newlib_search_path; do
+ case "$lib_search_path " in
+ *" $dir "*) ;;
+ *) func_append lib_search_path " $dir" ;;
+ esac
+ done
+ newlib_search_path=
+ fi
+
+ if test "$linkmode,$pass" != "prog,link"; then
+ vars="deplibs"
+ else
+ vars="compile_deplibs finalize_deplibs"
+ fi
+ for var in $vars dependency_libs; do
+ # Add libraries to $var in reverse order
+ eval tmp_libs=\"\$$var\"
+ new_libs=
+ for deplib in $tmp_libs; do
+ # FIXME: Pedantically, this is the right thing to do, so
+ # that some nasty dependency loop isn't accidentally
+ # broken:
+ #new_libs="$deplib $new_libs"
+ # Pragmatically, this seems to cause very few problems in
+ # practice:
+ case $deplib in
+ -L*) new_libs="$deplib $new_libs" ;;
+ -R*) ;;
+ *)
+ # And here is the reason: when a library appears more
+ # than once as an explicit dependence of a library, or
+ # is implicitly linked in more than once by the
+ # compiler, it is considered special, and multiple
+ # occurrences thereof are not removed. Compare this
+ # with having the same library being listed as a
+ # dependency of multiple other libraries: in this case,
+ # we know (pedantically, we assume) the library does not
+ # need to be listed more than once, so we keep only the
+ # last copy. This is not always right, but it is rare
+ # enough that we require users that really mean to play
+ # such unportable linking tricks to link the library
+ # using -Wl,-lname, so that libtool does not consider it
+ # for duplicate removal.
+ case " $specialdeplibs " in
+ *" $deplib "*) new_libs="$deplib $new_libs" ;;
+ *)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) new_libs="$deplib $new_libs" ;;
+ esac
+ ;;
+ esac
+ ;;
+ esac
+ done
+ tmp_libs=
+ for deplib in $new_libs; do
+ case $deplib in
+ -L*)
+ case " $tmp_libs " in
+ *" $deplib "*) ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append tmp_libs " $deplib" ;;
+ esac
+ done
+ eval $var=\"$tmp_libs\"
+ done # for var
+ fi
+ # Last step: remove runtime libs from dependency_libs
+ # (they stay in deplibs)
+ tmp_libs=
+ for i in $dependency_libs ; do
+ case " $predeps $postdeps $compiler_lib_search_path " in
+ *" $i "*)
+ i=""
+ ;;
+ esac
+ if test -n "$i" ; then
+ func_append tmp_libs " $i"
+ fi
+ done
+ dependency_libs=$tmp_libs
+ done # for pass
+ if test "$linkmode" = prog; then
+ dlfiles="$newdlfiles"
+ fi
+ if test "$linkmode" = prog || test "$linkmode" = lib; then
+ dlprefiles="$newdlprefiles"
+ fi
+
+ case $linkmode in
+ oldlib)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for archives"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for archives" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for archives"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for archives"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for archives"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for archives"
+
+ test -n "$export_symbols$export_symbols_regex" && \
+ func_warning "\`-export-symbols' is ignored for archives"
+
+ # Now set the variables for building old libraries.
+ build_libtool_libs=no
+ oldlibs="$output"
+ func_append objs "$old_deplibs"
+ ;;
+
+ lib)
+ # Make sure we only generate libraries of the form `libNAME.la'.
+ case $outputname in
+ lib*)
+ func_stripname 'lib' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ ;;
+ *)
+ test "$module" = no && \
+ func_fatal_help "libtool library \`$output' must begin with \`lib'"
+
+ if test "$need_lib_prefix" != no; then
+ # Add the "lib" prefix for modules if required
+ func_stripname '' '.la' "$outputname"
+ name=$func_stripname_result
+ eval shared_ext=\"$shrext_cmds\"
+ eval libname=\"$libname_spec\"
+ else
+ func_stripname '' '.la' "$outputname"
+ libname=$func_stripname_result
+ fi
+ ;;
+ esac
+
+ if test -n "$objs"; then
+ if test "$deplibs_check_method" != pass_all; then
+ func_fatal_error "cannot build libtool library \`$output' from non-libtool objects on this host:$objs"
+ else
+ echo
+ $ECHO "*** Warning: Linking the shared library $output against the non-libtool"
+ $ECHO "*** objects $objs is not portable!"
+ func_append libobjs " $objs"
+ fi
+ fi
+
+ test "$dlself" != no && \
+ func_warning "\`-dlopen self' is ignored for libtool libraries"
+
+ set dummy $rpath
+ shift
+ test "$#" -gt 1 && \
+ func_warning "ignoring multiple \`-rpath's for a libtool library"
+
+ install_libdir="$1"
+
+ oldlibs=
+ if test -z "$rpath"; then
+ if test "$build_libtool_libs" = yes; then
+ # Building a libtool convenience library.
+ # Some compilers have problems with a `.al' extension so
+ # convenience libraries should have the same extension an
+ # archive normally would.
+ oldlibs="$output_objdir/$libname.$libext $oldlibs"
+ build_libtool_libs=convenience
+ build_old_libs=yes
+ fi
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info/-version-number' is ignored for convenience libraries"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for convenience libraries"
+ else
+
+ # Parse the version information argument.
+ save_ifs="$IFS"; IFS=':'
+ set dummy $vinfo 0 0 0
+ shift
+ IFS="$save_ifs"
+
+ test -n "$7" && \
+ func_fatal_help "too many parameters to \`-version-info'"
+
+ # convert absolute version numbers to libtool ages
+ # this retains compatibility with .la files and attempts
+ # to make the code below a bit more comprehensible
+
+ case $vinfo_number in
+ yes)
+ number_major="$1"
+ number_minor="$2"
+ number_revision="$3"
+ #
+ # There are really only two kinds -- those that
+ # use the current revision as the major version
+ # and those that subtract age and use age as
+ # a minor version. But, then there is irix
+ # which has an extra 1 added just for fun
+ #
+ case $version_type in
+ # correct linux to gnu/linux during the next big refactor
+ darwin|linux|osf|windows|none)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_revision"
+ ;;
+ freebsd-aout|freebsd-elf|qnx|sunos)
+ current="$number_major"
+ revision="$number_minor"
+ age="0"
+ ;;
+ irix|nonstopux)
+ func_arith $number_major + $number_minor
+ current=$func_arith_result
+ age="$number_minor"
+ revision="$number_minor"
+ lt_irix_increment=no
+ ;;
+ *)
+ func_fatal_configuration "$modename: unknown library version type \`$version_type'"
+ ;;
+ esac
+ ;;
+ no)
+ current="$1"
+ revision="$2"
+ age="$3"
+ ;;
+ esac
+
+ # Check that each of the things are valid numbers.
+ case $current in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "CURRENT \`$current' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $revision in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "REVISION \`$revision' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ case $age in
+ 0|[1-9]|[1-9][0-9]|[1-9][0-9][0-9]|[1-9][0-9][0-9][0-9]|[1-9][0-9][0-9][0-9][0-9]) ;;
+ *)
+ func_error "AGE \`$age' must be a nonnegative integer"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ ;;
+ esac
+
+ if test "$age" -gt "$current"; then
+ func_error "AGE \`$age' is greater than the current interface number \`$current'"
+ func_fatal_error "\`$vinfo' is not valid version information"
+ fi
+
+ # Calculate the version variables.
+ major=
+ versuffix=
+ verstring=
+ case $version_type in
+ none) ;;
+
+ darwin)
+ # Like Linux, but with the current version available in
+ # verstring for coding it into the library header
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ # Darwin ld doesn't like 0 for these options...
+ func_arith $current + 1
+ minor_current=$func_arith_result
+ xlcverstring="${wl}-compatibility_version ${wl}$minor_current ${wl}-current_version ${wl}$minor_current.$revision"
+ verstring="-compatibility_version $minor_current -current_version $minor_current.$revision"
+ ;;
+
+ freebsd-aout)
+ major=".$current"
+ versuffix=".$current.$revision";
+ ;;
+
+ freebsd-elf)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ irix | nonstopux)
+ if test "X$lt_irix_increment" = "Xno"; then
+ func_arith $current - $age
+ else
+ func_arith $current - $age + 1
+ fi
+ major=$func_arith_result
+
+ case $version_type in
+ nonstopux) verstring_prefix=nonstopux ;;
+ *) verstring_prefix=sgi ;;
+ esac
+ verstring="$verstring_prefix$major.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$revision
+ while test "$loop" -ne 0; do
+ func_arith $revision - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring_prefix$major.$iface:$verstring"
+ done
+
+ # Before this point, $major must not contain `.'.
+ major=.$major
+ versuffix="$major.$revision"
+ ;;
+
+ linux) # correct to gnu/linux during the next big refactor
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix="$major.$age.$revision"
+ ;;
+
+ osf)
+ func_arith $current - $age
+ major=.$func_arith_result
+ versuffix=".$current.$age.$revision"
+ verstring="$current.$age.$revision"
+
+ # Add in all the interfaces that we are compatible with.
+ loop=$age
+ while test "$loop" -ne 0; do
+ func_arith $current - $loop
+ iface=$func_arith_result
+ func_arith $loop - 1
+ loop=$func_arith_result
+ verstring="$verstring:${iface}.0"
+ done
+
+ # Make executables depend on our current version.
+ func_append verstring ":${current}.0"
+ ;;
+
+ qnx)
+ major=".$current"
+ versuffix=".$current"
+ ;;
+
+ sunos)
+ major=".$current"
+ versuffix=".$current.$revision"
+ ;;
+
+ windows)
+ # Use '-' rather than '.', since we only want one
+ # extension on DOS 8.3 filesystems.
+ func_arith $current - $age
+ major=$func_arith_result
+ versuffix="-$major"
+ ;;
+
+ *)
+ func_fatal_configuration "unknown library version type \`$version_type'"
+ ;;
+ esac
+
+ # Clear the version info if we defaulted, and they specified a release.
+ if test -z "$vinfo" && test -n "$release"; then
+ major=
+ case $version_type in
+ darwin)
+ # we can't check for "0.0" in archive_cmds due to quoting
+ # problems, so we reset it completely
+ verstring=
+ ;;
+ *)
+ verstring="0.0"
+ ;;
+ esac
+ if test "$need_version" = no; then
+ versuffix=
+ else
+ versuffix=".0.0"
+ fi
+ fi
+
+ # Remove version info from name if versioning should be avoided
+ if test "$avoid_version" = yes && test "$need_version" = no; then
+ major=
+ versuffix=
+ verstring=""
+ fi
+
+ # Check to see if the archive will have undefined symbols.
+ if test "$allow_undefined" = yes; then
+ if test "$allow_undefined_flag" = unsupported; then
+ func_warning "undefined symbols not allowed in $host shared libraries"
+ build_libtool_libs=no
+ build_old_libs=yes
+ fi
+ else
+ # Don't allow undefined symbols.
+ allow_undefined_flag="$no_undefined_flag"
+ fi
+
+ fi
+
+ func_generate_dlsyms "$libname" "$libname" "yes"
+ func_append libobjs " $symfileobj"
+ test "X$libobjs" = "X " && libobjs=
+
+ if test "$opt_mode" != relink; then
+ # Remove our outputs, but don't remove object files since they
+ # may have been created when compiling PIC objects.
+ removelist=
+ tempremovelist=`$ECHO "$output_objdir/*"`
+ for p in $tempremovelist; do
+ case $p in
+ *.$objext | *.gcno)
+ ;;
+ $output_objdir/$outputname | $output_objdir/$libname.* | $output_objdir/${libname}${release}.*)
+ if test "X$precious_files_regex" != "X"; then
+ if $ECHO "$p" | $EGREP -e "$precious_files_regex" >/dev/null 2>&1
+ then
+ continue
+ fi
+ fi
+ func_append removelist " $p"
+ ;;
+ *) ;;
+ esac
+ done
+ test -n "$removelist" && \
+ func_show_eval "${RM}r \$removelist"
+ fi
+
+ # Now set the variables for building old libraries.
+ if test "$build_old_libs" = yes && test "$build_libtool_libs" != convenience ; then
+ func_append oldlibs " $output_objdir/$libname.$libext"
+
+ # Transform .lo files to .o files.
+ oldobjs="$objs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; $lo2o" | $NL2SP`
+ fi
+
+ # Eliminate all temporary directories.
+ #for path in $notinst_path; do
+ # lib_search_path=`$ECHO "$lib_search_path " | $SED "s% $path % %g"`
+ # deplibs=`$ECHO "$deplibs " | $SED "s% -L$path % %g"`
+ # dependency_libs=`$ECHO "$dependency_libs " | $SED "s% -L$path % %g"`
+ #done
+
+ if test -n "$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ temp_xrpath=
+ for libdir in $xrpath; do
+ func_replace_sysroot "$libdir"
+ func_append temp_xrpath " -R$func_replace_sysroot_result"
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ if test "$hardcode_into_libs" != yes || test "$build_old_libs" = yes; then
+ dependency_libs="$temp_xrpath $dependency_libs"
+ fi
+ fi
+
+ # Make sure dlfiles contains only unique files that won't be dlpreopened
+ old_dlfiles="$dlfiles"
+ dlfiles=
+ for lib in $old_dlfiles; do
+ case " $dlprefiles $dlfiles " in
+ *" $lib "*) ;;
+ *) func_append dlfiles " $lib" ;;
+ esac
+ done
+
+ # Make sure dlprefiles contains only unique files
+ old_dlprefiles="$dlprefiles"
+ dlprefiles=
+ for lib in $old_dlprefiles; do
+ case "$dlprefiles " in
+ *" $lib "*) ;;
+ *) func_append dlprefiles " $lib" ;;
+ esac
+ done
+
+ if test "$build_libtool_libs" = yes; then
+ if test -n "$rpath"; then
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-*-beos* | *-cegcc* | *-*-haiku*)
+ # these systems don't actually have a c library (as such)!
+ ;;
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # Rhapsody C library is in the System framework
+ func_append deplibs " System.ltframework"
+ ;;
+ *-*-netbsd*)
+ # Don't link with libc until the a.out ld.so is fixed.
+ ;;
+ *-*-openbsd* | *-*-freebsd* | *-*-dragonfly*)
+ # Do not include libc due to us having libc/libc_r.
+ ;;
+ *-*-sco3.2v5* | *-*-sco5v6*)
+ # Causes problems with __ctype
+ ;;
+ *-*-sysv4.2uw2* | *-*-sysv5* | *-*-unixware* | *-*-OpenUNIX*)
+ # Compiler inserts libc in the correct place for threads to work
+ ;;
+ *)
+ # Add libc to deplibs on all other systems if necessary.
+ if test "$build_libtool_need_lc" = "yes"; then
+ func_append deplibs " -lc"
+ fi
+ ;;
+ esac
+ fi
+
+ # Transform deplibs into only deplibs that can be linked in shared.
+ name_save=$name
+ libname_save=$libname
+ release_save=$release
+ versuffix_save=$versuffix
+ major_save=$major
+ # I'm not sure if I'm treating the release correctly. I think
+ # release should show up in the -l (ie -lgmp5) so we don't want to
+ # add it in twice. Is that correct?
+ release=""
+ versuffix=""
+ major=""
+ newdeplibs=
+ droppeddeps=no
+ case $deplibs_check_method in
+ pass_all)
+ # Don't check for shared/static. Everything works.
+ # This might be a little naive. We might want to check
+ # whether the library exists or not. But this is on
+ # osf3 & osf4 and I'm not really sure... Just
+ # implementing what was already the behavior.
+ newdeplibs=$deplibs
+ ;;
+ test_compile)
+ # This code stresses the "libraries are programs" paradigm to its
+ # limits. Maybe even breaks it. We compile a program, linking it
+ # against the deplibs as a proxy for the library. Then we can check
+ # whether they linked in statically or dynamically with ldd.
+ $opt_dry_run || $RM conftest.c
+ cat > conftest.c <<EOF
+ int main() { return 0; }
+EOF
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $deplibs; then
+ ldd_output=`ldd conftest`
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which I believe you do not have"
+ echo "*** because a test_compile did reveal that the linker did not use it for"
+ echo "*** its dynamic dependency list that programs get resolved with at runtime."
+ fi
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ else
+ # Error occurred in the first compile. Let's try to salvage
+ # the situation: Compile a separate program for each library.
+ for i in $deplibs; do
+ case $i in
+ -l*)
+ func_stripname -l '' "$i"
+ name=$func_stripname_result
+ $opt_dry_run || $RM conftest
+ if $LTCC $LTCFLAGS -o conftest conftest.c $i; then
+ ldd_output=`ldd conftest`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $i "*)
+ func_append newdeplibs " $i"
+ i=""
+ ;;
+ esac
+ fi
+ if test -n "$i" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ deplib_matches=`eval "\\$ECHO \"$library_names_spec\""`
+ set dummy $deplib_matches; shift
+ deplib_match=$1
+ if test `expr "$ldd_output" : ".*$deplib_match"` -ne 0 ; then
+ func_append newdeplibs " $i"
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: dynamic linker does not accept needed library $i."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because a test_compile did reveal that the linker did not use this one"
+ echo "*** as a dynamic dependency that programs can get resolved with at runtime."
+ fi
+ fi
+ else
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning! Library $i is needed by this library but I was not able to"
+ echo "*** make it link in! You will probably need to install it or some"
+ echo "*** library that it depends on before this library will be fully"
+ echo "*** functional. Installing it before continuing would be even better."
+ fi
+ ;;
+ *)
+ func_append newdeplibs " $i"
+ ;;
+ esac
+ done
+ fi
+ ;;
+ file_magic*)
+ set dummy $deplibs_check_method; shift
+ file_magic_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ if test -n "$file_magic_glob"; then
+ libnameglob=`func_echo_all "$libname" | $SED -e $file_magic_glob`
+ else
+ libnameglob=$libname
+ fi
+ test "$want_nocaseglob" = yes && nocaseglob=`shopt -p nocaseglob`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ if test "$want_nocaseglob" = yes; then
+ shopt -s nocaseglob
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ $nocaseglob
+ else
+ potential_libs=`ls $i/$libnameglob[.-]* 2>/dev/null`
+ fi
+ for potent_lib in $potential_libs; do
+ # Follow soft links.
+ if ls -lLd "$potent_lib" 2>/dev/null |
+ $GREP " -> " >/dev/null; then
+ continue
+ fi
+ # The statement above tries to avoid entering an
+ # endless loop below, in case of cyclic links.
+ # We might still enter an endless loop, since a link
+ # loop can be closed while we follow links,
+ # but so what?
+ potlib="$potent_lib"
+ while test -h "$potlib" 2>/dev/null; do
+ potliblink=`ls -ld $potlib | ${SED} 's/.* -> //'`
+ case $potliblink in
+ [\\/]* | [A-Za-z]:[\\/]*) potlib="$potliblink";;
+ *) potlib=`$ECHO "$potlib" | $SED 's,[^/]*$,,'`"$potliblink";;
+ esac
+ done
+ if eval $file_magic_cmd \"\$potlib\" 2>/dev/null |
+ $SED -e 10q |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for file magic test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a file magic. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ match_pattern*)
+ set dummy $deplibs_check_method; shift
+ match_pattern_regex=`expr "$deplibs_check_method" : "$1 \(.*\)"`
+ for a_deplib in $deplibs; do
+ case $a_deplib in
+ -l*)
+ func_stripname -l '' "$a_deplib"
+ name=$func_stripname_result
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ case " $predeps $postdeps " in
+ *" $a_deplib "*)
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ ;;
+ esac
+ fi
+ if test -n "$a_deplib" ; then
+ libname=`eval "\\$ECHO \"$libname_spec\""`
+ for i in $lib_search_path $sys_lib_search_path $shlib_search_path; do
+ potential_libs=`ls $i/$libname[.-]* 2>/dev/null`
+ for potent_lib in $potential_libs; do
+ potlib="$potent_lib" # see symlink-check above in file_magic test
+ if eval "\$ECHO \"$potent_lib\"" 2>/dev/null | $SED 10q | \
+ $EGREP "$match_pattern_regex" > /dev/null; then
+ func_append newdeplibs " $a_deplib"
+ a_deplib=""
+ break 2
+ fi
+ done
+ done
+ fi
+ if test -n "$a_deplib" ; then
+ droppeddeps=yes
+ echo
+ $ECHO "*** Warning: linker path does not have real file for library $a_deplib."
+ echo "*** I have the capability to make that library automatically link in when"
+ echo "*** you link to this library. But I can only do this if you have a"
+ echo "*** shared version of the library, which you do not appear to have"
+ echo "*** because I did check the linker path looking for a file starting"
+ if test -z "$potlib" ; then
+ $ECHO "*** with $libname but no candidates were found. (...for regex pattern test)"
+ else
+ $ECHO "*** with $libname and none of the candidates passed a file format test"
+ $ECHO "*** using a regex pattern. Last file checked: $potlib"
+ fi
+ fi
+ ;;
+ *)
+ # Add a -L argument.
+ func_append newdeplibs " $a_deplib"
+ ;;
+ esac
+ done # Gone through all deplibs.
+ ;;
+ none | unknown | *)
+ newdeplibs=""
+ tmp_deplibs=`$ECHO " $deplibs" | $SED 's/ -lc$//; s/ -[LR][^ ]*//g'`
+ if test "X$allow_libtool_libs_with_static_runtimes" = "Xyes" ; then
+ for i in $predeps $postdeps ; do
+ # can't use Xsed below, because $i might contain '/'
+ tmp_deplibs=`$ECHO " $tmp_deplibs" | $SED "s,$i,,"`
+ done
+ fi
+ case $tmp_deplibs in
+ *[!\ \ ]*)
+ echo
+ if test "X$deplibs_check_method" = "Xnone"; then
+ echo "*** Warning: inter-library dependencies are not supported in this platform."
+ else
+ echo "*** Warning: inter-library dependencies are not known to be supported."
+ fi
+ echo "*** All declared inter-library dependencies are being dropped."
+ droppeddeps=yes
+ ;;
+ esac
+ ;;
+ esac
+ versuffix=$versuffix_save
+ major=$major_save
+ release=$release_save
+ libname=$libname_save
+ name=$name_save
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library with the System framework
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ if test "$droppeddeps" = yes; then
+ if test "$module" = yes; then
+ echo
+ echo "*** Warning: libtool could not satisfy all declared inter-library"
+ $ECHO "*** dependencies of module $libname. Therefore, libtool will create"
+ echo "*** a static module, that should work as long as the dlopening"
+ echo "*** application is linked with the -dlopen flag."
+ if test -z "$global_symbol_pipe"; then
+ echo
+ echo "*** However, this would only work if libtool was able to extract symbol"
+ echo "*** lists from a program, using \`nm' or equivalent, but libtool could"
+ echo "*** not find such a program. So, this module is probably useless."
+ echo "*** \`nm' from GNU binutils and a full rebuild may help."
+ fi
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ else
+ echo "*** The inter-library dependencies that have been dropped here will be"
+ echo "*** automatically added whenever a program is linked with this library"
+ echo "*** or is declared to -dlopen it."
+
+ if test "$allow_undefined" = no; then
+ echo
+ echo "*** Since this library must not contain undefined symbols,"
+ echo "*** because either the platform does not support them or"
+ echo "*** it was explicitly requested with -no-undefined,"
+ echo "*** libtool will only create a static version of it."
+ if test "$build_old_libs" = no; then
+ oldlibs="$output_objdir/$libname.$libext"
+ build_libtool_libs=module
+ build_old_libs=yes
+ else
+ build_libtool_libs=no
+ fi
+ fi
+ fi
+ fi
+ # Done checking deplibs!
+ deplibs=$newdeplibs
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ case $host in
+ *-*-darwin*)
+ newdeplibs=`$ECHO " $newdeplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ new_inherited_linker_flags=`$ECHO " $new_inherited_linker_flags" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ deplibs=`$ECHO " $deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ deplibs="$new_libs"
+
+ # All the library-specific variables (install_libdir is set above).
+ library_names=
+ old_library=
+ dlname=
+
+ # Test again, we may have decided not to build it any more
+ if test "$build_libtool_libs" = yes; then
+ # Remove ${wl} instances when linking with ld.
+ # FIXME: should test the right _cmds variable.
+ case $archive_cmds in
+ *\$LD\ *) wl= ;;
+ esac
+ if test "$hardcode_into_libs" = yes; then
+ # Hardcode the library paths
+ hardcode_libdirs=
+ dep_rpath=
+ rpath="$finalize_rpath"
+ test "$opt_mode" != relink && rpath="$compile_rpath$rpath"
+ for libdir in $rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ func_replace_sysroot "$libdir"
+ libdir=$func_replace_sysroot_result
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append dep_rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval "dep_rpath=\"$hardcode_libdir_flag_spec\""
+ fi
+ if test -n "$runpath_var" && test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ eval "$runpath_var='$rpath\$$runpath_var'; export $runpath_var"
+ fi
+ test -n "$dep_rpath" && deplibs="$dep_rpath $deplibs"
+ fi
+
+ shlibpath="$finalize_shlibpath"
+ test "$opt_mode" != relink && shlibpath="$compile_shlibpath$shlibpath"
+ if test -n "$shlibpath"; then
+ eval "$shlibpath_var='$shlibpath\$$shlibpath_var'; export $shlibpath_var"
+ fi
+
+ # Get the real and link names of the library.
+ eval shared_ext=\"$shrext_cmds\"
+ eval library_names=\"$library_names_spec\"
+ set dummy $library_names
+ shift
+ realname="$1"
+ shift
+
+ if test -n "$soname_spec"; then
+ eval soname=\"$soname_spec\"
+ else
+ soname="$realname"
+ fi
+ if test -z "$dlname"; then
+ dlname=$soname
+ fi
+
+ lib="$output_objdir/$realname"
+ linknames=
+ for link
+ do
+ func_append linknames " $link"
+ done
+
+ # Use standard objects if they are pic
+ test -z "$pic_flag" && libobjs=`$ECHO "$libobjs" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ test "X$libobjs" = "X " && libobjs=
+
+ delfiles=
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ $opt_dry_run || cp "$export_symbols" "$output_objdir/$libname.uexp"
+ export_symbols="$output_objdir/$libname.uexp"
+ func_append delfiles " $export_symbols"
+ fi
+
+ orig_export_symbols=
+ case $host_os in
+ cygwin* | mingw* | cegcc*)
+ if test -n "$export_symbols" && test -z "$export_symbols_regex"; then
+ # exporting using user supplied symfile
+ if test "x`$SED 1q $export_symbols`" != xEXPORTS; then
+ # and it's NOT already a .def file. Must figure out
+ # which of the given symbols are data symbols and tag
+ # them as such. So, trigger use of export_symbols_cmds.
+ # export_symbols gets reassigned inside the "prepare
+ # the list of exported symbols" if statement, so the
+ # include_expsyms logic still works.
+ orig_export_symbols="$export_symbols"
+ export_symbols=
+ always_export_symbols=yes
+ fi
+ fi
+ ;;
+ esac
+
+ # Prepare the list of exported symbols
+ if test -z "$export_symbols"; then
+ if test "$always_export_symbols" = yes || test -n "$export_symbols_regex"; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ cmds=$export_symbols_cmds
+ save_ifs="$IFS"; IFS='~'
+ for cmd1 in $cmds; do
+ IFS="$save_ifs"
+ # Take the normal branch if the nm_file_list_spec branch
+ # doesn't work or if tool conversion is not needed.
+ case $nm_file_list_spec~$to_tool_file_cmd in
+ *~func_convert_file_noop | *~func_convert_file_msys_to_w32 | ~*)
+ try_normal_branch=yes
+ eval cmd=\"$cmd1\"
+ func_len " $cmd"
+ len=$func_len_result
+ ;;
+ *)
+ try_normal_branch=no
+ ;;
+ esac
+ if test "$try_normal_branch" = yes \
+ && { test "$len" -lt "$max_cmd_len" \
+ || test "$max_cmd_len" -le -1; }
+ then
+ func_show_eval "$cmd" 'exit $?'
+ skipped_export=false
+ elif test -n "$nm_file_list_spec"; then
+ func_basename "$output"
+ output_la=$func_basename_result
+ save_libobjs=$libobjs
+ save_output=$output
+ output=${output_objdir}/${output_la}.nm
+ func_to_tool_file "$output"
+ libobjs=$nm_file_list_spec$func_to_tool_file_result
+ func_append delfiles " $output"
+ func_verbose "creating $NM input file list: $output"
+ for obj in $save_libobjs; do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > "$output"
+ eval cmd=\"$cmd1\"
+ func_show_eval "$cmd" 'exit $?'
+ output=$save_output
+ libobjs=$save_libobjs
+ skipped_export=false
+ else
+ # The command line is too long to execute in one step.
+ func_verbose "using reloadable object file for export list..."
+ skipped_export=:
+ # Break out early, otherwise skipped_export may be
+ # set to false by a later but shorter cmd.
+ break
+ fi
+ done
+ IFS="$save_ifs"
+ if test -n "$export_symbols_regex" && test "X$skipped_export" != "X:"; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+ fi
+
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test "X$skipped_export" != "X:" && test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+
+ tmp_deplibs=
+ for test_deplib in $deplibs; do
+ case " $convenience " in
+ *" $test_deplib "*) ;;
+ *)
+ func_append tmp_deplibs " $test_deplib"
+ ;;
+ esac
+ done
+ deplibs="$tmp_deplibs"
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec" &&
+ test "$compiler_needs_object" = yes &&
+ test -z "$libobjs"; then
+ # extract the archives, so we have objects to list.
+ # TODO: could optimize this to just extract one archive.
+ whole_archive_flag_spec=
+ fi
+ if test -n "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ else
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ fi
+
+ if test "$thread_safe" = yes && test -n "$thread_safe_flag_spec"; then
+ eval flag=\"$thread_safe_flag_spec\"
+ func_append linker_flags " $flag"
+ fi
+
+ # Make a backup of the uninstalled library when relinking
+ if test "$opt_mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}U && $MV $realname ${realname}U)' || exit $?
+ fi
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ eval test_cmds=\"$module_expsym_cmds\"
+ cmds=$module_expsym_cmds
+ else
+ eval test_cmds=\"$module_cmds\"
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ eval test_cmds=\"$archive_expsym_cmds\"
+ cmds=$archive_expsym_cmds
+ else
+ eval test_cmds=\"$archive_cmds\"
+ cmds=$archive_cmds
+ fi
+ fi
+
+ if test "X$skipped_export" != "X:" &&
+ func_len " $test_cmds" &&
+ len=$func_len_result &&
+ test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ :
+ else
+ # The command line is too long to link in one step, link piecewise
+ # or, if using GNU ld and skipped_export is not :, use a linker
+ # script.
+
+ # Save the value of $output and $libobjs because we want to
+ # use them later. If we have whole_archive_flag_spec, we
+ # want to use save_libobjs as it was before
+ # whole_archive_flag_spec was expanded, because we can't
+ # assume the linker understands whole_archive_flag_spec.
+ # This may have to be revisited, in case too many
+ # convenience libraries get linked in and end up exceeding
+ # the spec.
+ if test -z "$convenience" || test -z "$whole_archive_flag_spec"; then
+ save_libobjs=$libobjs
+ fi
+ save_output=$output
+ func_basename "$output"
+ output_la=$func_basename_result
+
+ # Clear the reloadable object creation command queue and
+ # initialize k to one.
+ test_cmds=
+ concat_cmds=
+ objlist=
+ last_robj=
+ k=1
+
+ if test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "$with_gnu_ld" = yes; then
+ output=${output_objdir}/${output_la}.lnkscript
+ func_verbose "creating GNU ld script: $output"
+ echo 'INPUT (' > $output
+ for obj in $save_libobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ echo ')' >> $output
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$func_to_tool_file_result
+ elif test -n "$save_libobjs" && test "X$skipped_export" != "X:" && test "X$file_list_spec" != X; then
+ output=${output_objdir}/${output_la}.lnk
+ func_verbose "creating linker input file list: $output"
+ : > $output
+ set x $save_libobjs
+ shift
+ firstobj=
+ if test "$compiler_needs_object" = yes; then
+ firstobj="$1 "
+ shift
+ fi
+ for obj
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result" >> $output
+ done
+ func_append delfiles " $output"
+ func_to_tool_file "$output"
+ output=$firstobj\"$file_list_spec$func_to_tool_file_result\"
+ else
+ if test -n "$save_libobjs"; then
+ func_verbose "creating reloadable object files..."
+ output=$output_objdir/$output_la-${k}.$objext
+ eval test_cmds=\"$reload_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+
+ # Loop over the list of objects to be linked.
+ for obj in $save_libobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ if test "X$objlist" = X ||
+ test "$len" -lt "$max_cmd_len"; then
+ func_append objlist " $obj"
+ else
+ # The command $test_cmds is almost too long, add a
+ # command to the queue.
+ if test "$k" -eq 1 ; then
+ # The first file doesn't have a previous command to add.
+ reload_objs=$objlist
+ eval concat_cmds=\"$reload_cmds\"
+ else
+ # All subsequent reloadable object files will link in
+ # the last one created.
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\$concat_cmds~$reload_cmds~\$RM $last_robj\"
+ fi
+ last_robj=$output_objdir/$output_la-${k}.$objext
+ func_arith $k + 1
+ k=$func_arith_result
+ output=$output_objdir/$output_la-${k}.$objext
+ objlist=" $obj"
+ func_len " $last_robj"
+ func_arith $len0 + $func_len_result
+ len=$func_arith_result
+ fi
+ done
+ # Handle the remaining objects by creating one last
+ # reloadable object file. All subsequent reloadable object
+ # files will link in the last one created.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ reload_objs="$objlist $last_robj"
+ eval concat_cmds=\"\${concat_cmds}$reload_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\${concat_cmds}~\$RM $last_robj\"
+ fi
+ func_append delfiles " $output"
+
+ else
+ output=
+ fi
+
+ if ${skipped_export-false}; then
+ func_verbose "generating symbol list for \`$libname.la'"
+ export_symbols="$output_objdir/$libname.exp"
+ $opt_dry_run || $RM $export_symbols
+ libobjs=$output
+ # Append the command to create the export file.
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\$concat_cmds$export_symbols_cmds\"
+ if test -n "$last_robj"; then
+ eval concat_cmds=\"\$concat_cmds~\$RM $last_robj\"
+ fi
+ fi
+
+ test -n "$save_libobjs" &&
+ func_verbose "creating a temporary reloadable object file: $output"
+
+ # Loop through the commands generated above and execute them.
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $concat_cmds; do
+ IFS="$save_ifs"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ if test -n "$export_symbols_regex" && ${skipped_export-false}; then
+ func_show_eval '$EGREP -e "$export_symbols_regex" "$export_symbols" > "${export_symbols}T"'
+ func_show_eval '$MV "${export_symbols}T" "$export_symbols"'
+ fi
+ fi
+
+ if ${skipped_export-false}; then
+ if test -n "$export_symbols" && test -n "$include_expsyms"; then
+ tmp_export_symbols="$export_symbols"
+ test -n "$orig_export_symbols" && tmp_export_symbols="$orig_export_symbols"
+ $opt_dry_run || eval '$ECHO "$include_expsyms" | $SP2NL >> "$tmp_export_symbols"'
+ fi
+
+ if test -n "$orig_export_symbols"; then
+ # The given exports_symbols file has to be filtered, so filter it.
+ func_verbose "filter symbol list for \`$libname.la' to tag DATA exports"
+ # FIXME: $output_objdir/$libname.filter potentially contains lots of
+ # 's' commands which not all seds can handle. GNU sed should be fine
+ # though. Also, the filter scales superlinearly with the number of
+ # global variables. join(1) would be nice here, but unfortunately
+ # isn't a blessed tool.
+ $opt_dry_run || $SED -e '/[ ,]DATA/!d;s,\(.*\)\([ \,].*\),s|^\1$|\1\2|,' < $export_symbols > $output_objdir/$libname.filter
+ func_append delfiles " $export_symbols $output_objdir/$libname.filter"
+ export_symbols=$output_objdir/$libname.def
+ $opt_dry_run || $SED -f $output_objdir/$libname.filter < $orig_export_symbols > $export_symbols
+ fi
+ fi
+
+ libobjs=$output
+ # Restore the value of output.
+ output=$save_output
+
+ if test -n "$convenience" && test -n "$whole_archive_flag_spec"; then
+ eval libobjs=\"\$libobjs $whole_archive_flag_spec\"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+ # Expand the library linking commands again to reset the
+ # value of $libobjs for piecewise linking.
+
+ # Do each of the archive commands.
+ if test "$module" = yes && test -n "$module_cmds" ; then
+ if test -n "$export_symbols" && test -n "$module_expsym_cmds"; then
+ cmds=$module_expsym_cmds
+ else
+ cmds=$module_cmds
+ fi
+ else
+ if test -n "$export_symbols" && test -n "$archive_expsym_cmds"; then
+ cmds=$archive_expsym_cmds
+ else
+ cmds=$archive_cmds
+ fi
+ fi
+ fi
+
+ if test -n "$delfiles"; then
+ # Append the command to remove temporary files to $cmds.
+ eval cmds=\"\$cmds~\$RM $delfiles\"
+ fi
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append libobjs " $func_extract_archives_result"
+ test "X$libobjs" = "X " && libobjs=
+ fi
+
+ save_ifs="$IFS"; IFS='~'
+ for cmd in $cmds; do
+ IFS="$save_ifs"
+ eval cmd=\"$cmd\"
+ $opt_silent || {
+ func_quote_for_expand "$cmd"
+ eval "func_echo $func_quote_for_expand_result"
+ }
+ $opt_dry_run || eval "$cmd" || {
+ lt_exit=$?
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ ( cd "$output_objdir" && \
+ $RM "${realname}T" && \
+ $MV "${realname}U" "$realname" )
+ fi
+
+ exit $lt_exit
+ }
+ done
+ IFS="$save_ifs"
+
+ # Restore the uninstalled library and exit
+ if test "$opt_mode" = relink; then
+ $opt_dry_run || eval '(cd $output_objdir && $RM ${realname}T && $MV $realname ${realname}T && $MV ${realname}U $realname)' || exit $?
+
+ if test -n "$convenience"; then
+ if test -z "$whole_archive_flag_spec"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ # Create links to the real library.
+ for linkname in $linknames; do
+ if test "$realname" != "$linkname"; then
+ func_show_eval '(cd "$output_objdir" && $RM "$linkname" && $LN_S "$realname" "$linkname")' 'exit $?'
+ fi
+ done
+
+ # If -module or -export-dynamic was specified, set the dlname.
+ if test "$module" = yes || test "$export_dynamic" = yes; then
+ # On all known operating systems, these are identical.
+ dlname="$soname"
+ fi
+ fi
+ ;;
+
+ obj)
+ if test -n "$dlfiles$dlprefiles" || test "$dlself" != no; then
+ func_warning "\`-dlopen' is ignored for objects"
+ fi
+
+ case " $deplibs" in
+ *\ -l* | *\ -L*)
+ func_warning "\`-l' and \`-L' are ignored for objects" ;;
+ esac
+
+ test -n "$rpath" && \
+ func_warning "\`-rpath' is ignored for objects"
+
+ test -n "$xrpath" && \
+ func_warning "\`-R' is ignored for objects"
+
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for objects"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for objects"
+
+ case $output in
+ *.lo)
+ test -n "$objs$old_deplibs" && \
+ func_fatal_error "cannot build library object \`$output' from non-libtool objects"
+
+ libobj=$output
+ func_lo2o "$libobj"
+ obj=$func_lo2o_result
+ ;;
+ *)
+ libobj=
+ obj="$output"
+ ;;
+ esac
+
+ # Delete the old objects.
+ $opt_dry_run || $RM $obj $libobj
+
+ # Objects from convenience libraries. This assumes
+ # single-version convenience libraries. Whenever we create
+ # different ones for PIC/non-PIC, this we'll have to duplicate
+ # the extraction.
+ reload_conv_objs=
+ gentop=
+ # reload_cmds runs $LD directly, so let us get rid of
+ # -Wl from whole_archive_flag_spec and hope we can get by with
+ # turning comma into space..
+ wl=
+
+ if test -n "$convenience"; then
+ if test -n "$whole_archive_flag_spec"; then
+ eval tmp_whole_archive_flags=\"$whole_archive_flag_spec\"
+ reload_conv_objs=$reload_objs\ `$ECHO "$tmp_whole_archive_flags" | $SED 's|,| |g'`
+ else
+ gentop="$output_objdir/${obj}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $convenience
+ reload_conv_objs="$reload_objs $func_extract_archives_result"
+ fi
+ fi
+
+ # If we're not building shared, we need to use non_pic_objs
+ test "$build_libtool_libs" != yes && libobjs="$non_pic_objects"
+
+ # Create the old-style object.
+ reload_objs="$objs$old_deplibs "`$ECHO "$libobjs" | $SP2NL | $SED "/\.${libext}$/d; /\.lib$/d; $lo2o" | $NL2SP`" $reload_conv_objs" ### testsuite: skip nested quoting test
+
+ output="$obj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+
+ # Exit if we aren't doing a library object file.
+ if test -z "$libobj"; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$build_libtool_libs" != yes; then
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ # Create an invalid libtool object if no PIC, so that we don't
+ # accidentally link it into a program.
+ # $show "echo timestamp > $libobj"
+ # $opt_dry_run || eval "echo timestamp > $libobj" || exit $?
+ exit $EXIT_SUCCESS
+ fi
+
+ if test -n "$pic_flag" || test "$pic_mode" != default; then
+ # Only do commands if we really have different PIC objects.
+ reload_objs="$libobjs $reload_conv_objs"
+ output="$libobj"
+ func_execute_cmds "$reload_cmds" 'exit $?'
+ fi
+
+ if test -n "$gentop"; then
+ func_show_eval '${RM}r "$gentop"'
+ fi
+
+ exit $EXIT_SUCCESS
+ ;;
+
+ prog)
+ case $host in
+ *cygwin*) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result.exe;;
+ esac
+ test -n "$vinfo" && \
+ func_warning "\`-version-info' is ignored for programs"
+
+ test -n "$release" && \
+ func_warning "\`-release' is ignored for programs"
+
+ test "$preload" = yes \
+ && test "$dlopen_support" = unknown \
+ && test "$dlopen_self" = unknown \
+ && test "$dlopen_self_static" = unknown && \
+ func_warning "\`LT_INIT([dlopen])' not used. Assuming no dlopen support."
+
+ case $host in
+ *-*-rhapsody* | *-*-darwin1.[012])
+ # On Rhapsody replace the C library is the System framework
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's/ -lc / System.ltframework /'`
+ ;;
+ esac
+
+ case $host in
+ *-*-darwin*)
+ # Don't allow lazy linking, it breaks C++ global constructors
+ # But is supposedly fixed on 10.4 or later (yay!).
+ if test "$tagname" = CXX ; then
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0} in
+ 10.[0123])
+ func_append compile_command " ${wl}-bind_at_load"
+ func_append finalize_command " ${wl}-bind_at_load"
+ ;;
+ esac
+ fi
+ # Time to change all our "foo.ltframework" stuff back to "-framework foo"
+ compile_deplibs=`$ECHO " $compile_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ finalize_deplibs=`$ECHO " $finalize_deplibs" | $SED 's% \([^ $]*\).ltframework% -framework \1%g'`
+ ;;
+ esac
+
+
+ # move library search paths that coincide with paths to not yet
+ # installed libraries to the beginning of the library search list
+ new_libs=
+ for path in $notinst_path; do
+ case " $new_libs " in
+ *" -L$path/$objdir "*) ;;
+ *)
+ case " $compile_deplibs " in
+ *" -L$path/$objdir "*)
+ func_append new_libs " -L$path/$objdir" ;;
+ esac
+ ;;
+ esac
+ done
+ for deplib in $compile_deplibs; do
+ case $deplib in
+ -L*)
+ case " $new_libs " in
+ *" $deplib "*) ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ ;;
+ *) func_append new_libs " $deplib" ;;
+ esac
+ done
+ compile_deplibs="$new_libs"
+
+
+ func_append compile_command " $compile_deplibs"
+ func_append finalize_command " $finalize_deplibs"
+
+ if test -n "$rpath$xrpath"; then
+ # If the user specified any rpath flags, then add them.
+ for libdir in $rpath $xrpath; do
+ # This is the magic to use -rpath.
+ case "$finalize_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_rpath " $libdir" ;;
+ esac
+ done
+ fi
+
+ # Now hardcode the library paths
+ rpath=
+ hardcode_libdirs=
+ for libdir in $compile_rpath $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append perm_rpath " $libdir" ;;
+ esac
+ fi
+ case $host in
+ *-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-os2* | *-cegcc*)
+ testbindir=`${ECHO} "$libdir" | ${SED} -e 's*/lib$*/bin*'`
+ case :$dllsearchpath: in
+ *":$libdir:"*) ;;
+ ::) dllsearchpath=$libdir;;
+ *) func_append dllsearchpath ":$libdir";;
+ esac
+ case :$dllsearchpath: in
+ *":$testbindir:"*) ;;
+ ::) dllsearchpath=$testbindir;;
+ *) func_append dllsearchpath ":$testbindir";;
+ esac
+ ;;
+ esac
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ compile_rpath="$rpath"
+
+ rpath=
+ hardcode_libdirs=
+ for libdir in $finalize_rpath; do
+ if test -n "$hardcode_libdir_flag_spec"; then
+ if test -n "$hardcode_libdir_separator"; then
+ if test -z "$hardcode_libdirs"; then
+ hardcode_libdirs="$libdir"
+ else
+ # Just accumulate the unique libdirs.
+ case $hardcode_libdir_separator$hardcode_libdirs$hardcode_libdir_separator in
+ *"$hardcode_libdir_separator$libdir$hardcode_libdir_separator"*)
+ ;;
+ *)
+ func_append hardcode_libdirs "$hardcode_libdir_separator$libdir"
+ ;;
+ esac
+ fi
+ else
+ eval flag=\"$hardcode_libdir_flag_spec\"
+ func_append rpath " $flag"
+ fi
+ elif test -n "$runpath_var"; then
+ case "$finalize_perm_rpath " in
+ *" $libdir "*) ;;
+ *) func_append finalize_perm_rpath " $libdir" ;;
+ esac
+ fi
+ done
+ # Substitute the hardcoded libdirs into the rpath.
+ if test -n "$hardcode_libdir_separator" &&
+ test -n "$hardcode_libdirs"; then
+ libdir="$hardcode_libdirs"
+ eval rpath=\" $hardcode_libdir_flag_spec\"
+ fi
+ finalize_rpath="$rpath"
+
+ if test -n "$libobjs" && test "$build_old_libs" = yes; then
+ # Transform all the library objects into standard objects.
+ compile_command=`$ECHO "$compile_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ finalize_command=`$ECHO "$finalize_command" | $SP2NL | $SED "$lo2o" | $NL2SP`
+ fi
+
+ func_generate_dlsyms "$outputname" "@PROGRAM@" "no"
+
+ # template prelinking step
+ if test -n "$prelink_cmds"; then
+ func_execute_cmds "$prelink_cmds" 'exit $?'
+ fi
+
+ wrappers_required=yes
+ case $host in
+ *cegcc* | *mingw32ce*)
+ # Disable wrappers for cegcc and mingw32ce hosts, we are cross compiling anyway.
+ wrappers_required=no
+ ;;
+ *cygwin* | *mingw* )
+ if test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ *)
+ if test "$need_relink" = no || test "$build_libtool_libs" != yes; then
+ wrappers_required=no
+ fi
+ ;;
+ esac
+ if test "$wrappers_required" = no; then
+ # Replace the output file specification.
+ compile_command=`$ECHO "$compile_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ link_command="$compile_command$compile_rpath"
+
+ # We have no uninstalled library dependencies, so finalize right now.
+ exit_status=0
+ func_show_eval "$link_command" 'exit_status=$?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Delete the generated files.
+ if test -f "$output_objdir/${outputname}S.${objext}"; then
+ func_show_eval '$RM "$output_objdir/${outputname}S.${objext}"'
+ fi
+
+ exit $exit_status
+ fi
+
+ if test -n "$compile_shlibpath$finalize_shlibpath"; then
+ compile_command="$shlibpath_var=\"$compile_shlibpath$finalize_shlibpath\$$shlibpath_var\" $compile_command"
+ fi
+ if test -n "$finalize_shlibpath"; then
+ finalize_command="$shlibpath_var=\"$finalize_shlibpath\$$shlibpath_var\" $finalize_command"
+ fi
+
+ compile_var=
+ finalize_var=
+ if test -n "$runpath_var"; then
+ if test -n "$perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ compile_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ if test -n "$finalize_perm_rpath"; then
+ # We should set the runpath_var.
+ rpath=
+ for dir in $finalize_perm_rpath; do
+ func_append rpath "$dir:"
+ done
+ finalize_var="$runpath_var=\"$rpath\$$runpath_var\" "
+ fi
+ fi
+
+ if test "$no_install" = yes; then
+ # We don't need to create a wrapper script.
+ link_command="$compile_var$compile_command$compile_rpath"
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output"'%g'`
+ # Delete the old output file.
+ $opt_dry_run || $RM $output
+ # Link the executable and exit
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ exit $EXIT_SUCCESS
+ fi
+
+ if test "$hardcode_action" = relink; then
+ # Fast installation is not supported
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+
+ func_warning "this platform does not like uninstalled shared libraries"
+ func_warning "\`$output' will be relinked during installation"
+ else
+ if test "$fast_install" != no; then
+ link_command="$finalize_var$compile_command$finalize_rpath"
+ if test "$fast_install" = yes; then
+ relink_command=`$ECHO "$compile_var$compile_command$compile_rpath" | $SED 's%@OUTPUT@%\$progdir/\$file%g'`
+ else
+ # fast_install is set to needless
+ relink_command=
+ fi
+ else
+ link_command="$compile_var$compile_command$compile_rpath"
+ relink_command="$finalize_var$finalize_command$finalize_rpath"
+ fi
+ fi
+
+ # Replace the output file specification.
+ link_command=`$ECHO "$link_command" | $SED 's%@OUTPUT@%'"$output_objdir/$outputname"'%g'`
+
+ # Delete the old output files.
+ $opt_dry_run || $RM $output $output_objdir/$outputname $output_objdir/lt-$outputname
+
+ func_show_eval "$link_command" 'exit $?'
+
+ if test -n "$postlink_cmds"; then
+ func_to_tool_file "$output_objdir/$outputname"
+ postlink_cmds=`func_echo_all "$postlink_cmds" | $SED -e 's%@OUTPUT@%'"$output_objdir/$outputname"'%g' -e 's%@TOOL_OUTPUT@%'"$func_to_tool_file_result"'%g'`
+ func_execute_cmds "$postlink_cmds" 'exit $?'
+ fi
+
+ # Now create the wrapper script.
+ func_verbose "creating $output"
+
+ # Quote the relink command for shipping.
+ if test -n "$relink_command"; then
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ relink_command="(cd `pwd`; $relink_command)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ fi
+
+ # Only actually do things if not in dry run mode.
+ $opt_dry_run || {
+ # win32 will think the script is a binary if it has
+ # a .exe suffix, so we strip it off here.
+ case $output in
+ *.exe) func_stripname '' '.exe' "$output"
+ output=$func_stripname_result ;;
+ esac
+ # test for cygwin because mv fails w/o .exe extensions
+ case $host in
+ *cygwin*)
+ exeext=.exe
+ func_stripname '' '.exe' "$outputname"
+ outputname=$func_stripname_result ;;
+ *) exeext= ;;
+ esac
+ case $host in
+ *cygwin* | *mingw* )
+ func_dirname_and_basename "$output" "" "."
+ output_name=$func_basename_result
+ output_path=$func_dirname_result
+ cwrappersource="$output_path/$objdir/lt-$output_name.c"
+ cwrapper="$output_path/$output_name.exe"
+ $RM $cwrappersource $cwrapper
+ trap "$RM $cwrappersource $cwrapper; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_cwrapperexe_src > $cwrappersource
+
+ # The wrapper executable is built using the $host compiler,
+ # because it contains $host paths and files. If cross-
+ # compiling, it, like the target executable, must be
+ # executed on the $host or under an emulation environment.
+ $opt_dry_run || {
+ $LTCC $LTCFLAGS -o $cwrapper $cwrappersource
+ $STRIP $cwrapper
+ }
+
+ # Now, create the wrapper script for func_source use:
+ func_ltwrapper_scriptname $cwrapper
+ $RM $func_ltwrapper_scriptname_result
+ trap "$RM $func_ltwrapper_scriptname_result; exit $EXIT_FAILURE" 1 2 15
+ $opt_dry_run || {
+ # note: this script will not be executed, so do not chmod.
+ if test "x$build" = "x$host" ; then
+ $cwrapper --lt-dump-script > $func_ltwrapper_scriptname_result
+ else
+ func_emit_wrapper no > $func_ltwrapper_scriptname_result
+ fi
+ }
+ ;;
+ * )
+ $RM $output
+ trap "$RM $output; exit $EXIT_FAILURE" 1 2 15
+
+ func_emit_wrapper no > $output
+ chmod +x $output
+ ;;
+ esac
+ }
+ exit $EXIT_SUCCESS
+ ;;
+ esac
+
+ # See if we need to build an old-fashioned archive.
+ for oldlib in $oldlibs; do
+
+ if test "$build_libtool_libs" = convenience; then
+ oldobjs="$libobjs_save $symfileobj"
+ addlibs="$convenience"
+ build_libtool_libs=no
+ else
+ if test "$build_libtool_libs" = module; then
+ oldobjs="$libobjs_save"
+ build_libtool_libs=no
+ else
+ oldobjs="$old_deplibs $non_pic_objects"
+ if test "$preload" = yes && test -f "$symfileobj"; then
+ func_append oldobjs " $symfileobj"
+ fi
+ fi
+ addlibs="$old_convenience"
+ fi
+
+ if test -n "$addlibs"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $addlibs
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # Do each command in the archive commands.
+ if test -n "$old_archive_from_new_cmds" && test "$build_libtool_libs" = yes; then
+ cmds=$old_archive_from_new_cmds
+ else
+
+ # Add any objects from preloaded convenience libraries
+ if test -n "$dlprefiles"; then
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+
+ func_extract_archives $gentop $dlprefiles
+ func_append oldobjs " $func_extract_archives_result"
+ fi
+
+ # POSIX demands no paths to be encoded in archives. We have
+ # to avoid creating archives with duplicate basenames if we
+ # might have to extract them afterwards, e.g., when creating a
+ # static archive out of a convenience library, or when linking
+ # the entirety of a libtool archive into another (currently
+ # not supported by libtool).
+ if (for obj in $oldobjs
+ do
+ func_basename "$obj"
+ $ECHO "$func_basename_result"
+ done | sort | sort -uc >/dev/null 2>&1); then
+ :
+ else
+ echo "copying selected object files to avoid basename conflicts..."
+ gentop="$output_objdir/${outputname}x"
+ func_append generated " $gentop"
+ func_mkdir_p "$gentop"
+ save_oldobjs=$oldobjs
+ oldobjs=
+ counter=1
+ for obj in $save_oldobjs
+ do
+ func_basename "$obj"
+ objbase="$func_basename_result"
+ case " $oldobjs " in
+ " ") oldobjs=$obj ;;
+ *[\ /]"$objbase "*)
+ while :; do
+ # Make sure we don't pick an alternate name that also
+ # overlaps.
+ newobj=lt$counter-$objbase
+ func_arith $counter + 1
+ counter=$func_arith_result
+ case " $oldobjs " in
+ *[\ /]"$newobj "*) ;;
+ *) if test ! -f "$gentop/$newobj"; then break; fi ;;
+ esac
+ done
+ func_show_eval "ln $obj $gentop/$newobj || cp $obj $gentop/$newobj"
+ func_append oldobjs " $gentop/$newobj"
+ ;;
+ *) func_append oldobjs " $obj" ;;
+ esac
+ done
+ fi
+ func_to_tool_file "$oldlib" func_convert_file_msys_to_w32
+ tool_oldlib=$func_to_tool_file_result
+ eval cmds=\"$old_archive_cmds\"
+
+ func_len " $cmds"
+ len=$func_len_result
+ if test "$len" -lt "$max_cmd_len" || test "$max_cmd_len" -le -1; then
+ cmds=$old_archive_cmds
+ elif test -n "$archiver_list_spec"; then
+ func_verbose "using command file archive linking..."
+ for obj in $oldobjs
+ do
+ func_to_tool_file "$obj"
+ $ECHO "$func_to_tool_file_result"
+ done > $output_objdir/$libname.libcmd
+ func_to_tool_file "$output_objdir/$libname.libcmd"
+ oldobjs=" $archiver_list_spec$func_to_tool_file_result"
+ cmds=$old_archive_cmds
+ else
+ # the command line is too long to link in one step, link in parts
+ func_verbose "using piecewise archive linking..."
+ save_RANLIB=$RANLIB
+ RANLIB=:
+ objlist=
+ concat_cmds=
+ save_oldobjs=$oldobjs
+ oldobjs=
+ # Is there a better way of finding the last object in the list?
+ for obj in $save_oldobjs
+ do
+ last_oldobj=$obj
+ done
+ eval test_cmds=\"$old_archive_cmds\"
+ func_len " $test_cmds"
+ len0=$func_len_result
+ len=$len0
+ for obj in $save_oldobjs
+ do
+ func_len " $obj"
+ func_arith $len + $func_len_result
+ len=$func_arith_result
+ func_append objlist " $obj"
+ if test "$len" -lt "$max_cmd_len"; then
+ :
+ else
+ # the above command should be used before it gets too long
+ oldobjs=$objlist
+ if test "$obj" = "$last_oldobj" ; then
+ RANLIB=$save_RANLIB
+ fi
+ test -z "$concat_cmds" || concat_cmds=$concat_cmds~
+ eval concat_cmds=\"\${concat_cmds}$old_archive_cmds\"
+ objlist=
+ len=$len0
+ fi
+ done
+ RANLIB=$save_RANLIB
+ oldobjs=$objlist
+ if test "X$oldobjs" = "X" ; then
+ eval cmds=\"\$concat_cmds\"
+ else
+ eval cmds=\"\$concat_cmds~\$old_archive_cmds\"
+ fi
+ fi
+ fi
+ func_execute_cmds "$cmds" 'exit $?'
+ done
+
+ test -n "$generated" && \
+ func_show_eval "${RM}r$generated"
+
+ # Now create the libtool archive.
+ case $output in
+ *.la)
+ old_library=
+ test "$build_old_libs" = yes && old_library="$libname.$libext"
+ func_verbose "creating $output"
+
+ # Preserve any variables that may affect compiler behavior
+ for var in $variables_saved_for_relink; do
+ if eval test -z \"\${$var+set}\"; then
+ relink_command="{ test -z \"\${$var+set}\" || $lt_unset $var || { $var=; export $var; }; }; $relink_command"
+ elif eval var_value=\$$var; test -z "$var_value"; then
+ relink_command="$var=; export $var; $relink_command"
+ else
+ func_quote_for_eval "$var_value"
+ relink_command="$var=$func_quote_for_eval_result; export $var; $relink_command"
+ fi
+ done
+ # Quote the link command for shipping.
+ relink_command="(cd `pwd`; $SHELL $progpath $preserve_args --mode=relink $libtool_args @inst_prefix_dir@)"
+ relink_command=`$ECHO "$relink_command" | $SED "$sed_quote_subst"`
+ if test "$hardcode_automatic" = yes ; then
+ relink_command=
+ fi
+
+ # Only create the output if not a dry run.
+ $opt_dry_run || {
+ for installed in no yes; do
+ if test "$installed" = yes; then
+ if test -z "$install_libdir"; then
+ break
+ fi
+ output="$output_objdir/$outputname"i
+ # Replace all uninstalled libtool libraries with the installed ones
+ newdependency_libs=
+ for deplib in $dependency_libs; do
+ case $deplib in
+ *.la)
+ func_basename "$deplib"
+ name="$func_basename_result"
+ func_resolve_sysroot "$deplib"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $func_resolve_sysroot_result`
+ test -z "$libdir" && \
+ func_fatal_error "\`$deplib' is not a valid libtool archive"
+ func_append newdependency_libs " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ -L*)
+ func_stripname -L '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -L$func_replace_sysroot_result"
+ ;;
+ -R*)
+ func_stripname -R '' "$deplib"
+ func_replace_sysroot "$func_stripname_result"
+ func_append newdependency_libs " -R$func_replace_sysroot_result"
+ ;;
+ *) func_append newdependency_libs " $deplib" ;;
+ esac
+ done
+ dependency_libs="$newdependency_libs"
+ newdlfiles=
+
+ for lib in $dlfiles; do
+ case $lib in
+ *.la)
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_append newdlfiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ *) func_append newdlfiles " $lib" ;;
+ esac
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ *.la)
+ # Only pass preopened files to the pseudo-archive (for
+ # eventual linking with the app. that links it) if we
+ # didn't already link the preopened objects directly into
+ # the library:
+ func_basename "$lib"
+ name="$func_basename_result"
+ eval libdir=`${SED} -n -e 's/^libdir=\(.*\)$/\1/p' $lib`
+ test -z "$libdir" && \
+ func_fatal_error "\`$lib' is not a valid libtool archive"
+ func_append newdlprefiles " ${lt_sysroot:+=}$libdir/$name"
+ ;;
+ esac
+ done
+ dlprefiles="$newdlprefiles"
+ else
+ newdlfiles=
+ for lib in $dlfiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlfiles " $abs"
+ done
+ dlfiles="$newdlfiles"
+ newdlprefiles=
+ for lib in $dlprefiles; do
+ case $lib in
+ [\\/]* | [A-Za-z]:[\\/]*) abs="$lib" ;;
+ *) abs=`pwd`"/$lib" ;;
+ esac
+ func_append newdlprefiles " $abs"
+ done
+ dlprefiles="$newdlprefiles"
+ fi
+ $RM $output
+ # place dlname in correct position for cygwin
+ # In fact, it would be nice if we could use this code for all target
+ # systems that can't hard-code library paths into their executables
+ # and that have no shared library path variable independent of PATH,
+ # but it turns out we can't easily determine that from inspecting
+ # libtool variables, so we have to hard-code the OSs to which it
+ # applies here; at the moment, that means platforms that use the PE
+ # object format with DLL files. See the long comment at the top of
+ # tests/bindir.at for full details.
+ tdlname=$dlname
+ case $host,$output,$installed,$module,$dlname in
+ *cygwin*,*lai,yes,no,*.dll | *mingw*,*lai,yes,no,*.dll | *cegcc*,*lai,yes,no,*.dll)
+ # If a -bindir argument was supplied, place the dll there.
+ if test "x$bindir" != x ;
+ then
+ func_relative_path "$install_libdir" "$bindir"
+ tdlname=$func_relative_path_result$dlname
+ else
+ # Otherwise fall back on heuristic.
+ tdlname=../bin/$dlname
+ fi
+ ;;
+ esac
+ $ECHO > $output "\
+# $outputname - a libtool library file
+# Generated by $PROGRAM (GNU $PACKAGE$TIMESTAMP) $VERSION
+#
+# Please DO NOT delete this file!
+# It is necessary for linking the library.
+
+# The name that we can dlopen(3).
+dlname='$tdlname'
+
+# Names of this library.
+library_names='$library_names'
+
+# The name of the static archive.
+old_library='$old_library'
+
+# Linker flags that can not go in dependency_libs.
+inherited_linker_flags='$new_inherited_linker_flags'
+
+# Libraries that this one depends upon.
+dependency_libs='$dependency_libs'
+
+# Names of additional weak libraries provided by this library
+weak_library_names='$weak_libs'
+
+# Version information for $libname.
+current=$current
+age=$age
+revision=$revision
+
+# Is this an already installed library?
+installed=$installed
+
+# Should we warn about portability when linking against -modules?
+shouldnotlink=$module
+
+# Files to dlopen/dlpreopen
+dlopen='$dlfiles'
+dlpreopen='$dlprefiles'
+
+# Directory that this library needs to be installed in:
+libdir='$install_libdir'"
+ if test "$installed" = no && test "$need_relink" = yes; then
+ $ECHO >> $output "\
+relink_command=\"$relink_command\""
+ fi
+ done
+ }
+
+ # Do a symbolic link so that the libtool archive can be found in
+ # LD_LIBRARY_PATH before the program is installed.
+ func_show_eval '( cd "$output_objdir" && $RM "$outputname" && $LN_S "../$outputname" "$outputname" )' 'exit $?'
+ ;;
+ esac
+ exit $EXIT_SUCCESS
+}
+
+{ test "$opt_mode" = link || test "$opt_mode" = relink; } &&
+ func_mode_link ${1+"$@"}
+
+
+# func_mode_uninstall arg...
+func_mode_uninstall ()
+{
+ $opt_debug
+ RM="$nonopt"
+ files=
+ rmforce=
+ exit_status=0
+
+ # This variable tells wrapper scripts just to set variables rather
+ # than running their programs.
+ libtool_install_magic="$magic"
+
+ for arg
+ do
+ case $arg in
+ -f) func_append RM " $arg"; rmforce=yes ;;
+ -*) func_append RM " $arg" ;;
+ *) func_append files " $arg" ;;
+ esac
+ done
+
+ test -z "$RM" && \
+ func_fatal_help "you must specify an RM program"
+
+ rmdirs=
+
+ for file in $files; do
+ func_dirname "$file" "" "."
+ dir="$func_dirname_result"
+ if test "X$dir" = X.; then
+ odir="$objdir"
+ else
+ odir="$dir/$objdir"
+ fi
+ func_basename "$file"
+ name="$func_basename_result"
+ test "$opt_mode" = uninstall && odir="$dir"
+
+ # Remember odir for removal later, being careful to avoid duplicates
+ if test "$opt_mode" = clean; then
+ case " $rmdirs " in
+ *" $odir "*) ;;
+ *) func_append rmdirs " $odir" ;;
+ esac
+ fi
+
+ # Don't error if the file doesn't exist and rm -f was used.
+ if { test -L "$file"; } >/dev/null 2>&1 ||
+ { test -h "$file"; } >/dev/null 2>&1 ||
+ test -f "$file"; then
+ :
+ elif test -d "$file"; then
+ exit_status=1
+ continue
+ elif test "$rmforce" = yes; then
+ continue
+ fi
+
+ rmfiles="$file"
+
+ case $name in
+ *.la)
+ # Possibly a libtool archive, so verify it.
+ if func_lalib_p "$file"; then
+ func_source $dir/$name
+
+ # Delete the libtool libraries and symlinks.
+ for n in $library_names; do
+ func_append rmfiles " $odir/$n"
+ done
+ test -n "$old_library" && func_append rmfiles " $odir/$old_library"
+
+ case "$opt_mode" in
+ clean)
+ case " $library_names " in
+ *" $dlname "*) ;;
+ *) test -n "$dlname" && func_append rmfiles " $odir/$dlname" ;;
+ esac
+ test -n "$libdir" && func_append rmfiles " $odir/$name $odir/${name}i"
+ ;;
+ uninstall)
+ if test -n "$library_names"; then
+ # Do each command in the postuninstall commands.
+ func_execute_cmds "$postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+
+ if test -n "$old_library"; then
+ # Do each command in the old_postuninstall commands.
+ func_execute_cmds "$old_postuninstall_cmds" 'test "$rmforce" = yes || exit_status=1'
+ fi
+ # FIXME: should reinstall the best remaining shared library.
+ ;;
+ esac
+ fi
+ ;;
+
+ *.lo)
+ # Possibly a libtool object, so verify it.
+ if func_lalib_p "$file"; then
+
+ # Read the .lo file
+ func_source $dir/$name
+
+ # Add PIC object to the list of files to remove.
+ if test -n "$pic_object" &&
+ test "$pic_object" != none; then
+ func_append rmfiles " $dir/$pic_object"
+ fi
+
+ # Add non-PIC object to the list of files to remove.
+ if test -n "$non_pic_object" &&
+ test "$non_pic_object" != none; then
+ func_append rmfiles " $dir/$non_pic_object"
+ fi
+ fi
+ ;;
+
+ *)
+ if test "$opt_mode" = clean ; then
+ noexename=$name
+ case $file in
+ *.exe)
+ func_stripname '' '.exe' "$file"
+ file=$func_stripname_result
+ func_stripname '' '.exe' "$name"
+ noexename=$func_stripname_result
+ # $file with .exe has already been added to rmfiles,
+ # add $file without .exe
+ func_append rmfiles " $file"
+ ;;
+ esac
+ # Do a test to see if this is a libtool program.
+ if func_ltwrapper_p "$file"; then
+ if func_ltwrapper_executable_p "$file"; then
+ func_ltwrapper_scriptname "$file"
+ relink_command=
+ func_source $func_ltwrapper_scriptname_result
+ func_append rmfiles " $func_ltwrapper_scriptname_result"
+ else
+ relink_command=
+ func_source $dir/$noexename
+ fi
+
+ # note $name still contains .exe if it was in $file originally
+ # as does the version of $file that was added into $rmfiles
+ func_append rmfiles " $odir/$name $odir/${name}S.${objext}"
+ if test "$fast_install" = yes && test -n "$relink_command"; then
+ func_append rmfiles " $odir/lt-$name"
+ fi
+ if test "X$noexename" != "X$name" ; then
+ func_append rmfiles " $odir/lt-${noexename}.c"
+ fi
+ fi
+ fi
+ ;;
+ esac
+ func_show_eval "$RM $rmfiles" 'exit_status=1'
+ done
+
+ # Try to remove the ${objdir}s in the directories where we deleted files
+ for dir in $rmdirs; do
+ if test -d "$dir"; then
+ func_show_eval "rmdir $dir >/dev/null 2>&1"
+ fi
+ done
+
+ exit $exit_status
+}
+
+{ test "$opt_mode" = uninstall || test "$opt_mode" = clean; } &&
+ func_mode_uninstall ${1+"$@"}
+
+test -z "$opt_mode" && {
+ help="$generic_help"
+ func_fatal_help "you must specify a MODE"
+}
+
+test -z "$exec_cmd" && \
+ func_fatal_help "invalid operation mode \`$opt_mode'"
+
+if test -n "$exec_cmd"; then
+ eval exec "$exec_cmd"
+ exit $EXIT_FAILURE
+fi
+
+exit $exit_status
+
+
+# The TAGs below are defined such that we never get into a situation
+# in which we disable both kinds of libraries. Given conflicting
+# choices, we go for a static library, that is the most portable,
+# since we can't tell whether shared libraries were disabled because
+# the user asked for that or because the platform doesn't support
+# them. This is particularly important on AIX, because we don't
+# support having both static and shared libraries enabled at the same
+# time on that platform, so we default to a shared-only configuration.
+# If a disable-shared tag is given, we'll fallback to a static-only
+# configuration. But we'll never go from static-only to shared-only.
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-shared
+build_libtool_libs=no
+build_old_libs=yes
+# ### END LIBTOOL TAG CONFIG: disable-shared
+
+# ### BEGIN LIBTOOL TAG CONFIG: disable-static
+build_old_libs=`case $build_libtool_libs in yes) echo no;; *) echo yes;; esac`
+# ### END LIBTOOL TAG CONFIG: disable-static
+
+# Local Variables:
+# mode:shell-script
+# sh-indentation:2
+# End:
+# vi:sw=2
+
--- /dev/null
+#! /bin/sh
+# Common wrapper for a few potentially missing GNU programs.
+
+scriptversion=2013-10-28.13; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+# Originally written by Fran,cois Pinard <pinard@iro.umontreal.ca>, 1996.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+if test $# -eq 0; then
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+fi
+
+case $1 in
+
+ --is-lightweight)
+ # Used by our autoconf macros to check whether the available missing
+ # script is modern enough.
+ exit 0
+ ;;
+
+ --run)
+ # Back-compat with the calling convention used by older automake.
+ shift
+ ;;
+
+ -h|--h|--he|--hel|--help)
+ echo "\
+$0 [OPTION]... PROGRAM [ARGUMENT]...
+
+Run 'PROGRAM [ARGUMENT]...', returning a proper advice when this fails due
+to PROGRAM being missing or too old.
+
+Options:
+ -h, --help display this help and exit
+ -v, --version output version information and exit
+
+Supported PROGRAM values:
+ aclocal autoconf autoheader autom4te automake makeinfo
+ bison yacc flex lex help2man
+
+Version suffixes to PROGRAM as well as the prefixes 'gnu-', 'gnu', and
+'g' are ignored when checking the name.
+
+Send bug reports to <bug-automake@gnu.org>."
+ exit $?
+ ;;
+
+ -v|--v|--ve|--ver|--vers|--versi|--versio|--version)
+ echo "missing $scriptversion (GNU Automake)"
+ exit $?
+ ;;
+
+ -*)
+ echo 1>&2 "$0: unknown '$1' option"
+ echo 1>&2 "Try '$0 --help' for more information"
+ exit 1
+ ;;
+
+esac
+
+# Run the given program, remember its exit status.
+"$@"; st=$?
+
+# If it succeeded, we are done.
+test $st -eq 0 && exit 0
+
+# Also exit now if we it failed (or wasn't found), and '--version' was
+# passed; such an option is passed most likely to detect whether the
+# program is present and works.
+case $2 in --version|--help) exit $st;; esac
+
+# Exit code 63 means version mismatch. This often happens when the user
+# tries to use an ancient version of a tool on a file that requires a
+# minimum version.
+if test $st -eq 63; then
+ msg="probably too old"
+elif test $st -eq 127; then
+ # Program was missing.
+ msg="missing on your system"
+else
+ # Program was found and executed, but failed. Give up.
+ exit $st
+fi
+
+perl_URL=http://www.perl.org/
+flex_URL=http://flex.sourceforge.net/
+gnu_software_URL=http://www.gnu.org/software
+
+program_details ()
+{
+ case $1 in
+ aclocal|automake)
+ echo "The '$1' program is part of the GNU Automake package:"
+ echo "<$gnu_software_URL/automake>"
+ echo "It also requires GNU Autoconf, GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/autoconf>"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ autoconf|autom4te|autoheader)
+ echo "The '$1' program is part of the GNU Autoconf package:"
+ echo "<$gnu_software_URL/autoconf/>"
+ echo "It also requires GNU m4 and Perl in order to run:"
+ echo "<$gnu_software_URL/m4/>"
+ echo "<$perl_URL>"
+ ;;
+ esac
+}
+
+give_advice ()
+{
+ # Normalize program name to check for.
+ normalized_program=`echo "$1" | sed '
+ s/^gnu-//; t
+ s/^gnu//; t
+ s/^g//; t'`
+
+ printf '%s\n' "'$1' is $msg."
+
+ configure_deps="'configure.ac' or m4 files included by 'configure.ac'"
+ case $normalized_program in
+ autoconf*)
+ echo "You should only need it if you modified 'configure.ac',"
+ echo "or m4 files included by it."
+ program_details 'autoconf'
+ ;;
+ autoheader*)
+ echo "You should only need it if you modified 'acconfig.h' or"
+ echo "$configure_deps."
+ program_details 'autoheader'
+ ;;
+ automake*)
+ echo "You should only need it if you modified 'Makefile.am' or"
+ echo "$configure_deps."
+ program_details 'automake'
+ ;;
+ aclocal*)
+ echo "You should only need it if you modified 'acinclude.m4' or"
+ echo "$configure_deps."
+ program_details 'aclocal'
+ ;;
+ autom4te*)
+ echo "You might have modified some maintainer files that require"
+ echo "the 'autom4te' program to be rebuilt."
+ program_details 'autom4te'
+ ;;
+ bison*|yacc*)
+ echo "You should only need it if you modified a '.y' file."
+ echo "You may want to install the GNU Bison package:"
+ echo "<$gnu_software_URL/bison/>"
+ ;;
+ lex*|flex*)
+ echo "You should only need it if you modified a '.l' file."
+ echo "You may want to install the Fast Lexical Analyzer package:"
+ echo "<$flex_URL>"
+ ;;
+ help2man*)
+ echo "You should only need it if you modified a dependency" \
+ "of a man page."
+ echo "You may want to install the GNU Help2man package:"
+ echo "<$gnu_software_URL/help2man/>"
+ ;;
+ makeinfo*)
+ echo "You should only need it if you modified a '.texi' file, or"
+ echo "any other file indirectly affecting the aspect of the manual."
+ echo "You might want to install the Texinfo package:"
+ echo "<$gnu_software_URL/texinfo/>"
+ echo "The spurious makeinfo call might also be the consequence of"
+ echo "using a buggy 'make' (AIX, DU, IRIX), in which case you might"
+ echo "want to install GNU make:"
+ echo "<$gnu_software_URL/make/>"
+ ;;
+ *)
+ echo "You might have modified some files without having the proper"
+ echo "tools for further handling them. Check the 'README' file, it"
+ echo "often tells you about the needed prerequisites for installing"
+ echo "this package. You may also peek at any GNU archive site, in"
+ echo "case some other package contains this missing '$1' program."
+ ;;
+ esac
+}
+
+give_advice "$1" | sed -e '1s/^/WARNING: /' \
+ -e '2,$s/^/ /' >&2
+
+# Propagate the correct exit status (expected to be 127 for a program
+# not found, 63 for a program that failed due to version mismatch).
+exit $st
+
+# Local variables:
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+#! /bin/sh
+# test-driver - basic testsuite driver script.
+
+scriptversion=2013-07-13.22; # UTC
+
+# Copyright (C) 2011-2013 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+# Make unconditional expansion of undefined variables an error. This
+# helps a lot in preventing typo-related bugs.
+set -u
+
+usage_error ()
+{
+ echo "$0: $*" >&2
+ print_usage >&2
+ exit 2
+}
+
+print_usage ()
+{
+ cat <<END
+Usage:
+ test-driver --test-name=NAME --log-file=PATH --trs-file=PATH
+ [--expect-failure={yes|no}] [--color-tests={yes|no}]
+ [--enable-hard-errors={yes|no}] [--]
+ TEST-SCRIPT [TEST-SCRIPT-ARGUMENTS]
+The '--test-name', '--log-file' and '--trs-file' options are mandatory.
+END
+}
+
+test_name= # Used for reporting.
+log_file= # Where to save the output of the test script.
+trs_file= # Where to save the metadata of the test run.
+expect_failure=no
+color_tests=no
+enable_hard_errors=yes
+while test $# -gt 0; do
+ case $1 in
+ --help) print_usage; exit $?;;
+ --version) echo "test-driver $scriptversion"; exit $?;;
+ --test-name) test_name=$2; shift;;
+ --log-file) log_file=$2; shift;;
+ --trs-file) trs_file=$2; shift;;
+ --color-tests) color_tests=$2; shift;;
+ --expect-failure) expect_failure=$2; shift;;
+ --enable-hard-errors) enable_hard_errors=$2; shift;;
+ --) shift; break;;
+ -*) usage_error "invalid option: '$1'";;
+ *) break;;
+ esac
+ shift
+done
+
+missing_opts=
+test x"$test_name" = x && missing_opts="$missing_opts --test-name"
+test x"$log_file" = x && missing_opts="$missing_opts --log-file"
+test x"$trs_file" = x && missing_opts="$missing_opts --trs-file"
+if test x"$missing_opts" != x; then
+ usage_error "the following mandatory options are missing:$missing_opts"
+fi
+
+if test $# -eq 0; then
+ usage_error "missing argument"
+fi
+
+if test $color_tests = yes; then
+ # Keep this in sync with 'lib/am/check.am:$(am__tty_colors)'.
+ red='\e[0;31m' # Red.
+ grn='\e[0;32m' # Green.
+ lgn='\e[1;32m' # Light green.
+ blu='\e[1;34m' # Blue.
+ mgn='\e[0;35m' # Magenta.
+ std='\e[m' # No color.
+else
+ red= grn= lgn= blu= mgn= std=
+fi
+
+do_exit='rm -f $log_file $trs_file; (exit $st); exit $st'
+trap "st=129; $do_exit" 1
+trap "st=130; $do_exit" 2
+trap "st=141; $do_exit" 13
+trap "st=143; $do_exit" 15
+
+# Test script is run here.
+"$@" >$log_file 2>&1
+estatus=$?
+if test $enable_hard_errors = no && test $estatus -eq 99; then
+ estatus=1
+fi
+
+case $estatus:$expect_failure in
+ 0:yes) col=$red res=XPASS recheck=yes gcopy=yes;;
+ 0:*) col=$grn res=PASS recheck=no gcopy=no;;
+ 77:*) col=$blu res=SKIP recheck=no gcopy=yes;;
+ 99:*) col=$mgn res=ERROR recheck=yes gcopy=yes;;
+ *:yes) col=$lgn res=XFAIL recheck=no gcopy=yes;;
+ *:*) col=$red res=FAIL recheck=yes gcopy=yes;;
+esac
+
+# Report outcome to console.
+echo "${col}${res}${std}: $test_name"
+
+# Register the test result, and other relevant metadata.
+echo ":test-result: $res" > $trs_file
+echo ":global-test-result: $res" >> $trs_file
+echo ":recheck: $recheck" >> $trs_file
+echo ":copy-in-global-log: $gcopy" >> $trs_file
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+#! /bin/sh
+# ylwrap - wrapper for lex/yacc invocations.
+
+scriptversion=2013-01-12.17; # UTC
+
+# Copyright (C) 1996-2013 Free Software Foundation, Inc.
+#
+# Written by Tom Tromey <tromey@cygnus.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2, or (at your option)
+# any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# This file is maintained in Automake, please report
+# bugs to <bug-automake@gnu.org> or send patches to
+# <automake-patches@gnu.org>.
+
+get_dirname ()
+{
+ case $1 in
+ */*|*\\*) printf '%s\n' "$1" | sed -e 's|\([\\/]\)[^\\/]*$|\1|';;
+ # Otherwise, we want the empty string (not ".").
+ esac
+}
+
+# guard FILE
+# ----------
+# The CPP macro used to guard inclusion of FILE.
+guard ()
+{
+ printf '%s\n' "$1" \
+ | sed \
+ -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/' \
+ -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g' \
+ -e 's/__*/_/g'
+}
+
+# quote_for_sed [STRING]
+# ----------------------
+# Return STRING (or stdin) quoted to be used as a sed pattern.
+quote_for_sed ()
+{
+ case $# in
+ 0) cat;;
+ 1) printf '%s\n' "$1";;
+ esac \
+ | sed -e 's|[][\\.*]|\\&|g'
+}
+
+case "$1" in
+ '')
+ echo "$0: No files given. Try '$0 --help' for more information." 1>&2
+ exit 1
+ ;;
+ --basedir)
+ basedir=$2
+ shift 2
+ ;;
+ -h|--h*)
+ cat <<\EOF
+Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
+
+Wrapper for lex/yacc invocations, renaming files as desired.
+
+ INPUT is the input file
+ OUTPUT is one file PROG generates
+ DESIRED is the file we actually want instead of OUTPUT
+ PROGRAM is program to run
+ ARGS are passed to PROG
+
+Any number of OUTPUT,DESIRED pairs may be used.
+
+Report bugs to <bug-automake@gnu.org>.
+EOF
+ exit $?
+ ;;
+ -v|--v*)
+ echo "ylwrap $scriptversion"
+ exit $?
+ ;;
+esac
+
+
+# The input.
+input=$1
+shift
+# We'll later need for a correct munging of "#line" directives.
+input_sub_rx=`get_dirname "$input" | quote_for_sed`
+case $input in
+ [\\/]* | ?:[\\/]*)
+ # Absolute path; do nothing.
+ ;;
+ *)
+ # Relative path. Make it absolute.
+ input=`pwd`/$input
+ ;;
+esac
+input_rx=`get_dirname "$input" | quote_for_sed`
+
+# Since DOS filename conventions don't allow two dots,
+# the DOS version of Bison writes out y_tab.c instead of y.tab.c
+# and y_tab.h instead of y.tab.h. Test to see if this is the case.
+y_tab_nodot=false
+if test -f y_tab.c || test -f y_tab.h; then
+ y_tab_nodot=true
+fi
+
+# The parser itself, the first file, is the destination of the .y.c
+# rule in the Makefile.
+parser=$1
+
+# A sed program to s/FROM/TO/g for all the FROM/TO so that, for
+# instance, we rename #include "y.tab.h" into #include "parse.h"
+# during the conversion from y.tab.c to parse.c.
+sed_fix_filenames=
+
+# Also rename header guards, as Bison 2.7 for instance uses its header
+# guard in its implementation file.
+sed_fix_header_guards=
+
+while test $# -ne 0; do
+ if test x"$1" = x"--"; then
+ shift
+ break
+ fi
+ from=$1
+ # Handle y_tab.c and y_tab.h output by DOS
+ if $y_tab_nodot; then
+ case $from in
+ "y.tab.c") from=y_tab.c;;
+ "y.tab.h") from=y_tab.h;;
+ esac
+ fi
+ shift
+ to=$1
+ shift
+ sed_fix_filenames="${sed_fix_filenames}s|"`quote_for_sed "$from"`"|$to|g;"
+ sed_fix_header_guards="${sed_fix_header_guards}s|"`guard "$from"`"|"`guard "$to"`"|g;"
+done
+
+# The program to run.
+prog=$1
+shift
+# Make any relative path in $prog absolute.
+case $prog in
+ [\\/]* | ?:[\\/]*) ;;
+ *[\\/]*) prog=`pwd`/$prog ;;
+esac
+
+dirname=ylwrap$$
+do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
+trap "ret=129; $do_exit" 1
+trap "ret=130; $do_exit" 2
+trap "ret=141; $do_exit" 13
+trap "ret=143; $do_exit" 15
+mkdir $dirname || exit 1
+
+cd $dirname
+
+case $# in
+ 0) "$prog" "$input" ;;
+ *) "$prog" "$@" "$input" ;;
+esac
+ret=$?
+
+if test $ret -eq 0; then
+ for from in *
+ do
+ to=`printf '%s\n' "$from" | sed "$sed_fix_filenames"`
+ if test -f "$from"; then
+ # If $2 is an absolute path name, then just use that,
+ # otherwise prepend '../'.
+ case $to in
+ [\\/]* | ?:[\\/]*) target=$to;;
+ *) target=../$to;;
+ esac
+
+ # Do not overwrite unchanged header files to avoid useless
+ # recompilations. Always update the parser itself: it is the
+ # destination of the .y.c rule in the Makefile. Divert the
+ # output of all other files to a temporary file so we can
+ # compare them to existing versions.
+ if test $from != $parser; then
+ realtarget=$target
+ target=tmp-`printf '%s\n' "$target" | sed 's|.*[\\/]||g'`
+ fi
+
+ # Munge "#line" or "#" directives. Don't let the resulting
+ # debug information point at an absolute srcdir. Use the real
+ # output file name, not yy.lex.c for instance. Adjust the
+ # include guards too.
+ sed -e "/^#/!b" \
+ -e "s|$input_rx|$input_sub_rx|" \
+ -e "$sed_fix_filenames" \
+ -e "$sed_fix_header_guards" \
+ "$from" >"$target" || ret=$?
+
+ # Check whether files must be updated.
+ if test "$from" != "$parser"; then
+ if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
+ echo "$to is unchanged"
+ rm -f "$target"
+ else
+ echo "updating $to"
+ mv -f "$target" "$realtarget"
+ fi
+ fi
+ else
+ # A missing file is only an error for the parser. This is a
+ # blatant hack to let us support using "yacc -d". If -d is not
+ # specified, don't fail when the header file is "missing".
+ if test "$from" = "$parser"; then
+ ret=1
+ fi
+ fi
+ done
+fi
+
+# Remove the directory.
+cd ..
+rm -rf $dirname
+
+exit $ret
+
+# Local Variables:
+# mode: shell-script
+# sh-indentation: 2
+# eval: (add-hook 'write-file-hooks 'time-stamp)
+# time-stamp-start: "scriptversion="
+# time-stamp-format: "%:y-%02m-%02d.%02H"
+# time-stamp-time-zone: "UTC"
+# time-stamp-end: "; # UTC"
+# End:
--- /dev/null
+codedocs: .
+ doxygen doxygen.conf
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = codedocs
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign codedocs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign codedocs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags-am uninstall uninstall-am
+
+codedocs: .
+ doxygen doxygen.conf
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+# Doxyfile 1.4.0
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME = ahudns
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = ./
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Brazilian, Catalan, Chinese, Chinese-Traditional, Croatian, Czech, Danish,
+# Dutch, Finnish, French, German, Greek, Hungarian, Italian, Japanese,
+# Japanese-en (Japanese with English messages), Korean, Korean-en, Norwegian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Slovak, Slovene, Spanish,
+# Swedish, and Ukrainian.
+
+OUTPUT_LANGUAGE = English
+
+# This tag can be used to specify the encoding used in the generated output.
+# The encoding is not always determined by the language that is chosen,
+# but also whether or not the output is meant for Windows or non-Windows users.
+# In case there is a difference, setting the USE_WINDOWS_ENCODING tag to YES
+# forces the Windows encoding (this is the default for the Windows binary),
+# whereas setting the tag to NO uses a Unix-style encoding (the default for
+# all platforms other than Windows).
+
+USE_WINDOWS_ENCODING = NO
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like the Qt-style comments (thus requiring an
+# explicit @brief command for a brief description.
+
+JAVADOC_AUTOBRIEF = YES
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the DETAILS_AT_TOP tag is set to YES then Doxygen
+# will output the detailed description near the top, like JavaDoc.
+# If set to NO, the detailed description appears after the member
+# documentation.
+
+DETAILS_AT_TOP = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java sources
+# only. Doxygen will then generate output that is more tailored for Java.
+# For instance, namespaces will be presented as packages, qualified scopes
+# will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation.
+
+SHOW_DIRECTORIES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from the
+# version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the progam writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm
+
+FILE_PATTERNS = *.cc \
+ *.hh
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+
+EXCLUDE_PATTERNS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES (the default)
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = YES
+
+# If the REFERENCES_RELATION tag is set to YES (the default)
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = YES
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compressed HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the GENERATE_TREEVIEW tag is set to YES, a side panel will be
+# generated containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (for instance Mozilla 1.0+,
+# Netscape 6.0+, Internet explorer 5.0+, or Konqueror). Windows users are
+# probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = NO
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = NO
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_PREDEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH = ../
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS = *.hh
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = YES
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT tags are set to YES then doxygen will
+# generate a call dependency graph for every global function or class method.
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found on the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The MAX_DOT_GRAPH_WIDTH tag can be used to set the maximum allowed width
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_WIDTH = 1024
+
+# The MAX_DOT_GRAPH_HEIGHT tag can be used to set the maximum allows height
+# (in pixels) of the graphs generated by dot. If a graph becomes larger than
+# this value, doxygen will try to truncate the graph, so that it fits within
+# the specified constraint. Beware that most browsers cannot cope with very
+# large images.
+
+MAX_DOT_GRAPH_HEIGHT = 1024
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that a graph may be further truncated if the graph's
+# image dimensions are not sufficient to fit the graph (see MAX_DOT_GRAPH_WIDTH
+# and MAX_DOT_GRAPH_HEIGHT). If 0 is used for the depth value (the default),
+# the graph is not depth-constrained.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, which results in a white background.
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to the search engine
+#---------------------------------------------------------------------------
+
+# The SEARCHENGINE tag specifies whether or not a search engine should be
+# used. If set to NO the values of all tags below this one will be ignored.
+
+SEARCHENGINE = NO
--- /dev/null
+/* config.h.in. Generated from configure.ac by autoheader. */
+
+/* Set to the user and host that builds PowerDNS */
+#undef BUILD_HOST
+
+/* Define to 1 if you want to enable GSS-TSIG support */
+#undef ENABLE_GSS_TSIG
+
+/* Defined if the requested minimum BOOST version is satisfied */
+#undef HAVE_BOOST
+
+/* Defined if the Boost program_options library is available */
+#undef HAVE_BOOST_PROGRAM_OPTIONS
+
+/* Define to 1 if you have <boost/program_options.hpp> */
+#undef HAVE_BOOST_PROGRAM_OPTIONS_HPP
+
+/* Define to 1 if you have <boost/test/unit_test.hpp> */
+#undef HAVE_BOOST_TEST_UNIT_TEST_HPP
+
+/* Defined if the Boost unit_test_framework library is available */
+#undef HAVE_BOOST_UNIT_TEST_FRAMEWORK
+
+/* Define to 1 if you have botan 1.10 */
+#undef HAVE_BOTAN110
+
+/* Define to 1 if you have the <cdb.h> header file. */
+#undef HAVE_CDB_H
+
+/* Define to 1 if you have clock_gettime */
+#undef HAVE_CLOCK_GETTIME
+
+/* define if the compiler supports basic C++11 syntax */
+#undef HAVE_CXX11
+
+/* Define to 1 if you have the declaration of `NID_secp384r1', and to 0 if you
+ don't. */
+#undef HAVE_DECL_NID_SECP384R1
+
+/* Define to 1 if you have the declaration of `NID_X9_62_prime256v1', and to 0
+ if you don't. */
+#undef HAVE_DECL_NID_X9_62_PRIME256V1
+
+/* Define to 1 if you have the <dlfcn.h> header file. */
+#undef HAVE_DLFCN_H
+
+/* Define to 1 if you have the <inttypes.h> header file. */
+#undef HAVE_INTTYPES_H
+
+/* Define to 1 if you have the <lber.h> header file. */
+#undef HAVE_LBER_H
+
+/* Define to 1 if you have the <ldap.h> header file. */
+#undef HAVE_LDAP_H
+
+/* Define to 1 if you have ldap_initialize */
+#undef HAVE_LDAP_INITIALIZE
+
+/* Define to 1 if you have ldap_sasl_bind */
+#undef HAVE_LDAP_SASL_BIND
+
+/* define to 1 if OpenSSL ecdsa support is available. */
+#undef HAVE_LIBCRYPTO_ECDSA
+
+/* Define to 1 if you have libdecaf */
+#undef HAVE_LIBDECAF
+
+/* Have -lldap */
+#undef HAVE_LIBLDAP
+
+/* Have -lldap_r */
+#undef HAVE_LIBLDAP_R
+
+/* Define to 1 if you have libsodium */
+#undef HAVE_LIBSODIUM
+
+/* Define to 1 if you have libzmq */
+#undef HAVE_LIBZMQ
+
+/* Define to 1 if you have the `localtime_r' function. */
+#undef HAVE_LOCALTIME_R
+
+/* Define to 1 if you have lua */
+#undef HAVE_LUA
+
+/* Define to 1 if you have the <memory.h> header file. */
+#undef HAVE_MEMORY_H
+
+/* Define to 1 if you have mmap */
+#undef HAVE_MMAP
+
+/* Define to 1 if you have the <odbx.h> header file. */
+#undef HAVE_ODBX_H
+
+/* Define to 1 if you have p11-kit-1 */
+#undef HAVE_P11KIT1
+
+/* Define to 1 if you have 0.20 or newer P11-kit */
+#undef HAVE_P11KIT1_V2
+
+/* Define if using protobuf. */
+#undef HAVE_PROTOBUF
+
+/* Define to 1 if you have the `recvmmsg' function. */
+#undef HAVE_RECVMMSG
+
+/* Define to 1 if you have sqlite3 */
+#undef HAVE_SQLITE3
+
+/* Define to 1 if you have the <stdint.h> header file. */
+#undef HAVE_STDINT_H
+
+/* Define to 1 if you have the <stdlib.h> header file. */
+#undef HAVE_STDLIB_H
+
+/* Define to 1 if you have the `strcasestr' function. */
+#undef HAVE_STRCASESTR
+
+/* Define to 1 if you have the <strings.h> header file. */
+#undef HAVE_STRINGS_H
+
+/* Define to 1 if you have the <string.h> header file. */
+#undef HAVE_STRING_H
+
+/* Systemd available and enabled */
+#undef HAVE_SYSTEMD
+
+/* Define to 1 if you have the <sys/mman.h> header file. */
+#undef HAVE_SYS_MMAN_H
+
+/* Define to 1 if you have the <sys/stat.h> header file. */
+#undef HAVE_SYS_STAT_H
+
+/* Define to 1 if you have the <sys/types.h> header file. */
+#undef HAVE_SYS_TYPES_H
+
+/* tm_gmtoff is available. */
+#undef HAVE_TM_GMTOFF
+
+/* Define to 1 if you have the <unistd.h> header file. */
+#undef HAVE_UNISTD_H
+
+/* Define to 1 if the ZeroMQ 3.x or greater API is available */
+#undef HAVE_ZMQ_MSG_SEND
+
+/* Define to the sub-directory in which libtool stores uninstalled libraries.
+ */
+#undef LT_OBJDIR
+
+/* Define to 1 if you want to benefit from malloc trace */
+#undef MALLOC_TRACE
+
+/* If your OS is so broken that it needs an additional prototype */
+#undef NEED_INET_NTOP_PROTO
+
+/* If POSIX typedefs need to be defined */
+#undef NEED_POSIX_TYPEDEF
+
+/* Name of package */
+#undef PACKAGE
+
+/* Set to the package version used for secpoll */
+#undef PACKAGEVERSION
+
+/* Define to the address where bug reports for this package should be sent. */
+#undef PACKAGE_BUGREPORT
+
+/* Define to the full name of this package. */
+#undef PACKAGE_NAME
+
+/* Define to the full name and version of this package. */
+#undef PACKAGE_STRING
+
+/* Define to the one symbol short name of this package. */
+#undef PACKAGE_TARNAME
+
+/* Define to the home page for this package. */
+#undef PACKAGE_URL
+
+/* Define to the version of this package. */
+#undef PACKAGE_VERSION
+
+/* pdns configure arguments */
+#undef PDNS_CONFIG_ARGS
+
+/* Built-in modules */
+#undef PDNS_MODULES
+
+/* Define to 1 if you have the ZeroMQ connector */
+#undef REMOTEBACKEND_ZEROMQ
+
+/* Define to 1 for reproducible builds */
+#undef REPRODUCIBLE
+
+/* Define to 1 if you have the ANSI C header files. */
+#undef STDC_HEADERS
+
+/* Define to 1 if your <sys/time.h> declares `struct tm'. */
+#undef TM_IN_SYS_TIME
+
+/* Define to 1 if verbose logging is enabled */
+#undef VERBOSELOG
+
+/* Version number of package */
+#undef VERSION
+
+/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
+ `char[]'. */
+#undef YYTEXT_POINTER
+
+/* Define _GNU_SOURCE so that we get all necessary prototypes */
+#undef _GNU_SOURCE
--- /dev/null
+#! /bin/sh
+# Guess values for system-dependent variables and create Makefiles.
+# Generated by GNU Autoconf 2.69 for pdns 4.0.4.
+#
+#
+# Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
+#
+#
+# This configure script is free software; the Free Software Foundation
+# gives unlimited permission to copy, distribute and modify it.
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+# Use a proper internal environment variable to ensure we don't fall
+ # into an infinite loop, continuously re-executing ourselves.
+ if test x"${_as_can_reexec}" != xno && test "x$CONFIG_SHELL" != x; then
+ _as_can_reexec=no; export _as_can_reexec;
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+as_fn_exit 255
+ fi
+ # We don't want this to propagate to other subprocesses.
+ { _as_can_reexec=; unset _as_can_reexec;}
+if test "x$CONFIG_SHELL" = x; then
+ as_bourne_compatible="if test -n \"\${ZSH_VERSION+set}\" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on \${1+\"\$@\"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '\${1+\"\$@\"}'='\"\$@\"'
+ setopt NO_GLOB_SUBST
+else
+ case \`(set -o) 2>/dev/null\` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+"
+ as_required="as_fn_return () { (exit \$1); }
+as_fn_success () { as_fn_return 0; }
+as_fn_failure () { as_fn_return 1; }
+as_fn_ret_success () { return 0; }
+as_fn_ret_failure () { return 1; }
+
+exitcode=0
+as_fn_success || { exitcode=1; echo as_fn_success failed.; }
+as_fn_failure && { exitcode=1; echo as_fn_failure succeeded.; }
+as_fn_ret_success || { exitcode=1; echo as_fn_ret_success failed.; }
+as_fn_ret_failure && { exitcode=1; echo as_fn_ret_failure succeeded.; }
+if ( set x; as_fn_ret_success y && test x = \"\$1\" ); then :
+
+else
+ exitcode=1; echo positional parameters were not saved.
+fi
+test x\$exitcode = x0 || exit 1
+test -x / || exit 1"
+ as_suggested=" as_lineno_1=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_1a=\$LINENO
+ as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
+ eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
+ test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
+
+ test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
+ || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
+ if (eval "$as_required") 2>/dev/null; then :
+ as_have_required=yes
+else
+ as_have_required=no
+fi
+ if test x$as_have_required = xyes && (eval "$as_suggested") 2>/dev/null; then :
+
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+as_found=false
+for as_dir in /bin$PATH_SEPARATOR/usr/bin$PATH_SEPARATOR$PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ as_found=:
+ case $as_dir in #(
+ /*)
+ for as_base in sh bash ksh sh5; do
+ # Try only shells that exist, to save several forks.
+ as_shell=$as_dir/$as_base
+ if { test -f "$as_shell" || test -f "$as_shell.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ CONFIG_SHELL=$as_shell as_have_required=yes
+ if { $as_echo "$as_bourne_compatible""$as_suggested" | as_run=a "$as_shell"; } 2>/dev/null; then :
+ break 2
+fi
+fi
+ done;;
+ esac
+ as_found=false
+done
+$as_found || { if { test -f "$SHELL" || test -f "$SHELL.exe"; } &&
+ { $as_echo "$as_bourne_compatible""$as_required" | as_run=a "$SHELL"; } 2>/dev/null; then :
+ CONFIG_SHELL=$SHELL as_have_required=yes
+fi; }
+IFS=$as_save_IFS
+
+
+ if test "x$CONFIG_SHELL" != x; then :
+ export CONFIG_SHELL
+ # We cannot yet assume a decent shell, so we have to provide a
+# neutralization value for shells without unset; and this also
+# works around shells that cannot unset nonexistent variables.
+# Preserve -v and -x to the replacement shell.
+BASH_ENV=/dev/null
+ENV=/dev/null
+(unset BASH_ENV) >/dev/null 2>&1 && unset BASH_ENV ENV
+case $- in # ((((
+ *v*x* | *x*v* ) as_opts=-vx ;;
+ *v* ) as_opts=-v ;;
+ *x* ) as_opts=-x ;;
+ * ) as_opts= ;;
+esac
+exec $CONFIG_SHELL $as_opts "$as_myself" ${1+"$@"}
+# Admittedly, this is quite paranoid, since all the known shells bail
+# out after a failed `exec'.
+$as_echo "$0: could not re-execute with $CONFIG_SHELL" >&2
+exit 255
+fi
+
+ if test x$as_have_required = xno; then :
+ $as_echo "$0: This script requires a shell more modern than all"
+ $as_echo "$0: the shells that I found on your system."
+ if test x${ZSH_VERSION+set} = xset ; then
+ $as_echo "$0: In particular, zsh $ZSH_VERSION has bugs and should"
+ $as_echo "$0: be upgraded to zsh 4.3.4 or later."
+ else
+ $as_echo "$0: Please tell bug-autoconf@gnu.org about your system,
+$0: including any error possibly output before this
+$0: message. Then install a modern shell, or manually run
+$0: the script under such a shell if you do have one."
+ fi
+ exit 1
+fi
+fi
+fi
+SHELL=${CONFIG_SHELL-/bin/sh}
+export SHELL
+# Unset more variables known to interfere with behavior of common tools.
+CLICOLOR_FORCE= GREP_OPTIONS=
+unset CLICOLOR_FORCE GREP_OPTIONS
+
+## --------------------- ##
+## M4sh Shell Functions. ##
+## --------------------- ##
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+
+ as_lineno_1=$LINENO as_lineno_1a=$LINENO
+ as_lineno_2=$LINENO as_lineno_2a=$LINENO
+ eval 'test "x$as_lineno_1'$as_run'" != "x$as_lineno_2'$as_run'" &&
+ test "x`expr $as_lineno_1'$as_run' + 1`" = "x$as_lineno_2'$as_run'"' || {
+ # Blame Lee E. McMahon (1931-1989) for sed's syntax. :-)
+ sed -n '
+ p
+ /[$]LINENO/=
+ ' <$as_myself |
+ sed '
+ s/[$]LINENO.*/&-/
+ t lineno
+ b
+ :lineno
+ N
+ :loop
+ s/[$]LINENO\([^'$as_cr_alnum'_].*\n\)\(.*\)/\2\1\2/
+ t loop
+ s/-\n.*//
+ ' >$as_me.lineno &&
+ chmod +x "$as_me.lineno" ||
+ { $as_echo "$as_me: error: cannot create $as_me.lineno; rerun with a POSIX shell" >&2; as_fn_exit 1; }
+
+ # If we had to re-execute with $CONFIG_SHELL, we're ensured to have
+ # already done that, so ensure we don't try to do so again and fall
+ # in an infinite loop. This has already happened in practice.
+ _as_can_reexec=no; export _as_can_reexec
+ # Don't try to exec as it changes $[0], causing all sort of problems
+ # (the dirname of $[0] is not the place where we might find the
+ # original and so on. Autoconf is especially sensitive to this).
+ . "./$as_me.lineno"
+ # Exit status is that of the last command.
+ exit
+}
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+SHELL=${CONFIG_SHELL-/bin/sh}
+
+
+test -n "$DJDIR" || exec 7<&0 </dev/null
+exec 6>&1
+
+# Name of the host.
+# hostname on some systems (SVR3.2, old GNU/Linux) returns a bogus exit status,
+# so uname gets run too.
+ac_hostname=`(hostname || uname -n) 2>/dev/null | sed 1q`
+
+#
+# Initializations.
+#
+ac_default_prefix=/usr/local
+ac_clean_files=
+ac_config_libobj_dir=.
+LIBOBJS=
+cross_compiling=no
+subdirs=
+MFLAGS=
+MAKEFLAGS=
+
+# Identity of this package.
+PACKAGE_NAME='pdns'
+PACKAGE_TARNAME='pdns'
+PACKAGE_VERSION='4.0.4'
+PACKAGE_STRING='pdns 4.0.4'
+PACKAGE_BUGREPORT=''
+PACKAGE_URL=''
+
+ac_unique_file="pdns/receiver.cc"
+# Factoring default headers for most tests.
+ac_includes_default="\
+#include <stdio.h>
+#ifdef HAVE_SYS_TYPES_H
+# include <sys/types.h>
+#endif
+#ifdef HAVE_SYS_STAT_H
+# include <sys/stat.h>
+#endif
+#ifdef STDC_HEADERS
+# include <stdlib.h>
+# include <stddef.h>
+#else
+# ifdef HAVE_STDLIB_H
+# include <stdlib.h>
+# endif
+#endif
+#ifdef HAVE_STRING_H
+# if !defined STDC_HEADERS && defined HAVE_MEMORY_H
+# include <memory.h>
+# endif
+# include <string.h>
+#endif
+#ifdef HAVE_STRINGS_H
+# include <strings.h>
+#endif
+#ifdef HAVE_INTTYPES_H
+# include <inttypes.h>
+#endif
+#ifdef HAVE_STDINT_H
+# include <stdint.h>
+#endif
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif"
+
+ac_func_list=
+ac_subst_vars='am__EXEEXT_FALSE
+am__EXEEXT_TRUE
+LTLIBOBJS
+LIBOBJS
+PACKAGEVERSION
+YAHTTP_LIBS
+YAHTTP_CFLAGS
+AM_CPPFLAGS
+MALLOC_TRACE_FALSE
+MALLOC_TRACE_TRUE
+WARN_CFLAGS
+SANITIZER_FLAGS
+PROGRAM_LDFLAGS
+HAVE_SYSTEMD_FALSE
+HAVE_SYSTEMD_TRUE
+SYSTEMD_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_MODULES_LOAD
+SYSTEMD_DIR
+systemd
+SQLITE3_FALSE
+SQLITE3_TRUE
+SQLITE3_LIBS
+SQLITE3_CFLAGS
+LDAP_FALSE
+LDAP_TRUE
+ORACLE_FALSE
+ORACLE_TRUE
+HAVE_PROTOC_FALSE
+HAVE_PROTOC_TRUE
+HAVE_PROTOBUF_FALSE
+HAVE_PROTOBUF_TRUE
+PROTOC
+PROTOBUF_LIBS
+PROTOBUF_CFLAGS
+TOOLS_FALSE
+TOOLS_TRUE
+LIBZMQ_LIBS
+LIBZMQ_CFLAGS
+REMOTEBACKEND_ZEROMQ
+REMOTEBACKEND_ZEROMQ_FALSE
+REMOTEBACKEND_ZEROMQ_TRUE
+YAML_LIBS
+YAML_CFLAGS
+GEOIP_LIBS
+GEOIP_CFLAGS
+CDB_LIBS
+CDB_CFLAGS
+CURL
+OPENDBX_LIBS
+OPENDBX_CFLAGS
+LDAP_LIBS
+PGSQL_inc
+PGSQL_lib
+PGSQL_pg_config
+MYSQL_CFLAGS
+MYSQL_LIBS
+MYSQL_config
+UNIXODBC_LIBS
+UNIXODBC_CFLAGS
+UNIXODBC_config
+ORACLE_LIBS
+ORACLE_CFLAGS
+modulelibs
+moduleobjects
+moduledirs
+socketdir
+GSS_LIBS
+GSS_CFLAGS
+GSS_TSIG
+GSS_TSIG_FALSE
+GSS_TSIG_TRUE
+P11KIT1_LIBS
+P11KIT1_CFLAGS
+PKCS11_FALSE
+PKCS11_TRUE
+LIBDL
+HAVE_RECVMMSG_FALSE
+HAVE_RECVMMSG_TRUE
+FROM_GIT_FALSE
+FROM_GIT_TRUE
+HAVE_MANPAGES_FALSE
+HAVE_MANPAGES_TRUE
+HAVE_PANDOC_FALSE
+HAVE_PANDOC_TRUE
+PANDOC
+BOOST_UNIT_TEST_FRAMEWORK_LIBS
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS
+BACKEND_UNIT_TESTS_FALSE
+BACKEND_UNIT_TESTS_TRUE
+UNIT_TESTS_FALSE
+UNIT_TESTS_TRUE
+BOOST_PROGRAM_OPTIONS_LIBS
+BOOST_LDPATH
+BOOST_PROGRAM_OPTIONS_LDPATH
+BOOST_PROGRAM_OPTIONS_LDFLAGS
+HAVE_BOOST_GE_148_FALSE
+HAVE_BOOST_GE_148_TRUE
+BOOST_CPPFLAGS
+DISTCHECK_CONFIGURE_FLAGS
+BOOST_ROOT
+RT_LIBS
+RAGEL
+LIBCRYPTO_LDFLAGS
+LIBCRYPTO_LIBS
+LIBCRYPTO_INCLUDES
+LIBDECAF_LIBS
+LIBDECAF_FALSE
+LIBDECAF_TRUE
+LIBSODIUM_LIBS
+LIBSODIUM_CFLAGS
+LIBSODIUM_FALSE
+LIBSODIUM_TRUE
+BOTAN110_LIBS
+BOTAN110_CFLAGS
+BOTAN110_FALSE
+BOTAN110_TRUE
+OTOOL64
+OTOOL
+LIPO
+NMEDIT
+DSYMUTIL
+MANIFEST_TOOL
+RANLIB
+ac_ct_AR
+AR
+DLLTOOL
+OBJDUMP
+LN_S
+NM
+ac_ct_DUMPBIN
+DUMPBIN
+LD
+FGREP
+SED
+LIBTOOL
+RELRO_LDFLAGS
+PIE_LDFLAGS
+PIE_CFLAGS
+HAVE_CXX11
+HAVE_LUA_HPP_FALSE
+HAVE_LUA_HPP_TRUE
+CXXCPP
+LUA_FALSE
+LUA_TRUE
+LUA_LIBS
+LUA_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+DYNLINKFLAGS
+THREADFLAGS
+HAVE_SOLARIS_FALSE
+HAVE_SOLARIS_TRUE
+HAVE_LINUX_FALSE
+HAVE_LINUX_TRUE
+HAVE_FREEBSD_FALSE
+HAVE_FREEBSD_TRUE
+am__fastdepCXX_FALSE
+am__fastdepCXX_TRUE
+CXXDEPMODE
+ac_ct_CXX
+CXXFLAGS
+CXX
+LEXLIB
+LEX_OUTPUT_ROOT
+LEX
+EGREP
+GREP
+YFLAGS
+YACC
+am__fastdepCC_FALSE
+am__fastdepCC_TRUE
+CCDEPMODE
+am__nodep
+AMDEPBACKSLASH
+AMDEP_FALSE
+AMDEP_TRUE
+am__quote
+am__include
+DEPDIR
+OBJEXT
+EXEEXT
+ac_ct_CC
+CPPFLAGS
+LDFLAGS
+CFLAGS
+CC
+host_os
+host_vendor
+host_cpu
+host
+build_os
+build_vendor
+build_cpu
+build
+AM_BACKSLASH
+AM_DEFAULT_VERBOSITY
+AM_DEFAULT_V
+AM_V
+am__untar
+am__tar
+AMTAR
+am__leading_dot
+SET_MAKE
+AWK
+mkdir_p
+MKDIR_P
+INSTALL_STRIP_PROGRAM
+STRIP
+install_sh
+MAKEINFO
+AUTOHEADER
+AUTOMAKE
+AUTOCONF
+ACLOCAL
+VERSION
+PACKAGE
+CYGPATH_W
+am__isrc
+INSTALL_DATA
+INSTALL_SCRIPT
+INSTALL_PROGRAM
+pdns_configure_args
+target_alias
+host_alias
+build_alias
+LIBS
+ECHO_T
+ECHO_N
+ECHO_C
+DEFS
+mandir
+localedir
+libdir
+psdir
+pdfdir
+dvidir
+htmldir
+infodir
+docdir
+oldincludedir
+includedir
+localstatedir
+sharedstatedir
+sysconfdir
+datadir
+datarootdir
+libexecdir
+sbindir
+bindir
+program_transform_name
+prefix
+exec_prefix
+PACKAGE_URL
+PACKAGE_BUGREPORT
+PACKAGE_STRING
+PACKAGE_VERSION
+PACKAGE_TARNAME
+PACKAGE_NAME
+PATH_SEPARATOR
+SHELL'
+ac_subst_files=''
+ac_user_opts='
+enable_option_checking
+enable_silent_rules
+enable_dependency_tracking
+with_luajit
+with_lua
+enable_hardening
+enable_static
+enable_shared
+with_pic
+enable_fast_install
+with_gnu_ld
+with_sysroot
+enable_libtool_lock
+enable_botan1_10
+enable_libsodium
+enable_libdecaf
+with_libcrypto
+with_boost
+enable_static_boost
+enable_unit_tests
+enable_backend_unit_tests
+enable_reproducible
+with_sqlite3
+enable_verbose_logging
+enable_experimental_pkcs11
+enable_experimental_gss_tsig
+with_socketdir
+with_modules
+with_dynmodules
+with_oracle_includes
+with_oracle_libs
+with_unixodbc
+with_odbc_config
+with_unixodbc_lib
+with_unixodbc_includes
+with_mysql
+with_mysql_config
+with_mysql_lib
+with_mysql_includes
+with_pgsql
+with_pgsql_lib
+with_pgsql_includes
+with_pgsql_config
+enable_remotebackend_zeromq
+enable_tools
+with_protobuf
+enable_systemd
+with_systemd
+enable_coverage
+enable_asan
+enable_msan
+enable_tsan
+enable_lsan
+enable_ubsan
+enable_malloc_trace
+'
+ ac_precious_vars='build_alias
+host_alias
+target_alias
+CC
+CFLAGS
+LDFLAGS
+LIBS
+CPPFLAGS
+YACC
+YFLAGS
+CXX
+CXXFLAGS
+CCC
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
+LUA_CFLAGS
+LUA_LIBS
+CXXCPP
+BOTAN110_CFLAGS
+BOTAN110_LIBS
+LIBSODIUM_CFLAGS
+LIBSODIUM_LIBS
+BOOST_ROOT
+P11KIT1_CFLAGS
+P11KIT1_LIBS
+GSS_CFLAGS
+GSS_LIBS
+LDAP_LIBS
+OPENDBX_CFLAGS
+OPENDBX_LIBS
+CDB_CFLAGS
+CDB_LIBS
+GEOIP_CFLAGS
+GEOIP_LIBS
+YAML_CFLAGS
+YAML_LIBS
+LIBZMQ_CFLAGS
+LIBZMQ_LIBS
+PROTOBUF_CFLAGS
+PROTOBUF_LIBS
+SQLITE3_CFLAGS
+SQLITE3_LIBS
+SYSTEMD_CFLAGS
+SYSTEMD_LIBS
+PACKAGEVERSION'
+
+
+# Initialize some variables set by options.
+ac_init_help=
+ac_init_version=false
+ac_unrecognized_opts=
+ac_unrecognized_sep=
+# The variables have the same names as the options, with
+# dashes changed to underlines.
+cache_file=/dev/null
+exec_prefix=NONE
+no_create=
+no_recursion=
+prefix=NONE
+program_prefix=NONE
+program_suffix=NONE
+program_transform_name=s,x,x,
+silent=
+site=
+srcdir=
+verbose=
+x_includes=NONE
+x_libraries=NONE
+
+# Installation directory options.
+# These are left unexpanded so users can "make install exec_prefix=/foo"
+# and all the variables that are supposed to be based on exec_prefix
+# by default will actually change.
+# Use braces instead of parens because sh, perl, etc. also accept them.
+# (The list follows the same order as the GNU Coding Standards.)
+bindir='${exec_prefix}/bin'
+sbindir='${exec_prefix}/sbin'
+libexecdir='${exec_prefix}/libexec'
+datarootdir='${prefix}/share'
+datadir='${datarootdir}'
+sysconfdir='${prefix}/etc'
+sharedstatedir='${prefix}/com'
+localstatedir='${prefix}/var'
+includedir='${prefix}/include'
+oldincludedir='/usr/include'
+docdir='${datarootdir}/doc/${PACKAGE_TARNAME}'
+infodir='${datarootdir}/info'
+htmldir='${docdir}'
+dvidir='${docdir}'
+pdfdir='${docdir}'
+psdir='${docdir}'
+libdir='${exec_prefix}/lib'
+localedir='${datarootdir}/locale'
+mandir='${datarootdir}/man'
+
+ac_prev=
+ac_dashdash=
+for ac_option
+do
+ # If the previous option needs an argument, assign it.
+ if test -n "$ac_prev"; then
+ eval $ac_prev=\$ac_option
+ ac_prev=
+ continue
+ fi
+
+ case $ac_option in
+ *=?*) ac_optarg=`expr "X$ac_option" : '[^=]*=\(.*\)'` ;;
+ *=) ac_optarg= ;;
+ *) ac_optarg=yes ;;
+ esac
+
+ # Accept the important Cygnus configure options, so we can diagnose typos.
+
+ case $ac_dashdash$ac_option in
+ --)
+ ac_dashdash=yes ;;
+
+ -bindir | --bindir | --bindi | --bind | --bin | --bi)
+ ac_prev=bindir ;;
+ -bindir=* | --bindir=* | --bindi=* | --bind=* | --bin=* | --bi=*)
+ bindir=$ac_optarg ;;
+
+ -build | --build | --buil | --bui | --bu)
+ ac_prev=build_alias ;;
+ -build=* | --build=* | --buil=* | --bui=* | --bu=*)
+ build_alias=$ac_optarg ;;
+
+ -cache-file | --cache-file | --cache-fil | --cache-fi \
+ | --cache-f | --cache- | --cache | --cach | --cac | --ca | --c)
+ ac_prev=cache_file ;;
+ -cache-file=* | --cache-file=* | --cache-fil=* | --cache-fi=* \
+ | --cache-f=* | --cache-=* | --cache=* | --cach=* | --cac=* | --ca=* | --c=*)
+ cache_file=$ac_optarg ;;
+
+ --config-cache | -C)
+ cache_file=config.cache ;;
+
+ -datadir | --datadir | --datadi | --datad)
+ ac_prev=datadir ;;
+ -datadir=* | --datadir=* | --datadi=* | --datad=*)
+ datadir=$ac_optarg ;;
+
+ -datarootdir | --datarootdir | --datarootdi | --datarootd | --dataroot \
+ | --dataroo | --dataro | --datar)
+ ac_prev=datarootdir ;;
+ -datarootdir=* | --datarootdir=* | --datarootdi=* | --datarootd=* \
+ | --dataroot=* | --dataroo=* | --dataro=* | --datar=*)
+ datarootdir=$ac_optarg ;;
+
+ -disable-* | --disable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*disable-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--disable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=no ;;
+
+ -docdir | --docdir | --docdi | --doc | --do)
+ ac_prev=docdir ;;
+ -docdir=* | --docdir=* | --docdi=* | --doc=* | --do=*)
+ docdir=$ac_optarg ;;
+
+ -dvidir | --dvidir | --dvidi | --dvid | --dvi | --dv)
+ ac_prev=dvidir ;;
+ -dvidir=* | --dvidir=* | --dvidi=* | --dvid=* | --dvi=* | --dv=*)
+ dvidir=$ac_optarg ;;
+
+ -enable-* | --enable-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*enable-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid feature name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"enable_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--enable-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval enable_$ac_useropt=\$ac_optarg ;;
+
+ -exec-prefix | --exec_prefix | --exec-prefix | --exec-prefi \
+ | --exec-pref | --exec-pre | --exec-pr | --exec-p | --exec- \
+ | --exec | --exe | --ex)
+ ac_prev=exec_prefix ;;
+ -exec-prefix=* | --exec_prefix=* | --exec-prefix=* | --exec-prefi=* \
+ | --exec-pref=* | --exec-pre=* | --exec-pr=* | --exec-p=* | --exec-=* \
+ | --exec=* | --exe=* | --ex=*)
+ exec_prefix=$ac_optarg ;;
+
+ -gas | --gas | --ga | --g)
+ # Obsolete; use --with-gas.
+ with_gas=yes ;;
+
+ -help | --help | --hel | --he | -h)
+ ac_init_help=long ;;
+ -help=r* | --help=r* | --hel=r* | --he=r* | -hr*)
+ ac_init_help=recursive ;;
+ -help=s* | --help=s* | --hel=s* | --he=s* | -hs*)
+ ac_init_help=short ;;
+
+ -host | --host | --hos | --ho)
+ ac_prev=host_alias ;;
+ -host=* | --host=* | --hos=* | --ho=*)
+ host_alias=$ac_optarg ;;
+
+ -htmldir | --htmldir | --htmldi | --htmld | --html | --htm | --ht)
+ ac_prev=htmldir ;;
+ -htmldir=* | --htmldir=* | --htmldi=* | --htmld=* | --html=* | --htm=* \
+ | --ht=*)
+ htmldir=$ac_optarg ;;
+
+ -includedir | --includedir | --includedi | --included | --include \
+ | --includ | --inclu | --incl | --inc)
+ ac_prev=includedir ;;
+ -includedir=* | --includedir=* | --includedi=* | --included=* | --include=* \
+ | --includ=* | --inclu=* | --incl=* | --inc=*)
+ includedir=$ac_optarg ;;
+
+ -infodir | --infodir | --infodi | --infod | --info | --inf)
+ ac_prev=infodir ;;
+ -infodir=* | --infodir=* | --infodi=* | --infod=* | --info=* | --inf=*)
+ infodir=$ac_optarg ;;
+
+ -libdir | --libdir | --libdi | --libd)
+ ac_prev=libdir ;;
+ -libdir=* | --libdir=* | --libdi=* | --libd=*)
+ libdir=$ac_optarg ;;
+
+ -libexecdir | --libexecdir | --libexecdi | --libexecd | --libexec \
+ | --libexe | --libex | --libe)
+ ac_prev=libexecdir ;;
+ -libexecdir=* | --libexecdir=* | --libexecdi=* | --libexecd=* | --libexec=* \
+ | --libexe=* | --libex=* | --libe=*)
+ libexecdir=$ac_optarg ;;
+
+ -localedir | --localedir | --localedi | --localed | --locale)
+ ac_prev=localedir ;;
+ -localedir=* | --localedir=* | --localedi=* | --localed=* | --locale=*)
+ localedir=$ac_optarg ;;
+
+ -localstatedir | --localstatedir | --localstatedi | --localstated \
+ | --localstate | --localstat | --localsta | --localst | --locals)
+ ac_prev=localstatedir ;;
+ -localstatedir=* | --localstatedir=* | --localstatedi=* | --localstated=* \
+ | --localstate=* | --localstat=* | --localsta=* | --localst=* | --locals=*)
+ localstatedir=$ac_optarg ;;
+
+ -mandir | --mandir | --mandi | --mand | --man | --ma | --m)
+ ac_prev=mandir ;;
+ -mandir=* | --mandir=* | --mandi=* | --mand=* | --man=* | --ma=* | --m=*)
+ mandir=$ac_optarg ;;
+
+ -nfp | --nfp | --nf)
+ # Obsolete; use --without-fp.
+ with_fp=no ;;
+
+ -no-create | --no-create | --no-creat | --no-crea | --no-cre \
+ | --no-cr | --no-c | -n)
+ no_create=yes ;;
+
+ -no-recursion | --no-recursion | --no-recursio | --no-recursi \
+ | --no-recurs | --no-recur | --no-recu | --no-rec | --no-re | --no-r)
+ no_recursion=yes ;;
+
+ -oldincludedir | --oldincludedir | --oldincludedi | --oldincluded \
+ | --oldinclude | --oldinclud | --oldinclu | --oldincl | --oldinc \
+ | --oldin | --oldi | --old | --ol | --o)
+ ac_prev=oldincludedir ;;
+ -oldincludedir=* | --oldincludedir=* | --oldincludedi=* | --oldincluded=* \
+ | --oldinclude=* | --oldinclud=* | --oldinclu=* | --oldincl=* | --oldinc=* \
+ | --oldin=* | --oldi=* | --old=* | --ol=* | --o=*)
+ oldincludedir=$ac_optarg ;;
+
+ -prefix | --prefix | --prefi | --pref | --pre | --pr | --p)
+ ac_prev=prefix ;;
+ -prefix=* | --prefix=* | --prefi=* | --pref=* | --pre=* | --pr=* | --p=*)
+ prefix=$ac_optarg ;;
+
+ -program-prefix | --program-prefix | --program-prefi | --program-pref \
+ | --program-pre | --program-pr | --program-p)
+ ac_prev=program_prefix ;;
+ -program-prefix=* | --program-prefix=* | --program-prefi=* \
+ | --program-pref=* | --program-pre=* | --program-pr=* | --program-p=*)
+ program_prefix=$ac_optarg ;;
+
+ -program-suffix | --program-suffix | --program-suffi | --program-suff \
+ | --program-suf | --program-su | --program-s)
+ ac_prev=program_suffix ;;
+ -program-suffix=* | --program-suffix=* | --program-suffi=* \
+ | --program-suff=* | --program-suf=* | --program-su=* | --program-s=*)
+ program_suffix=$ac_optarg ;;
+
+ -program-transform-name | --program-transform-name \
+ | --program-transform-nam | --program-transform-na \
+ | --program-transform-n | --program-transform- \
+ | --program-transform | --program-transfor \
+ | --program-transfo | --program-transf \
+ | --program-trans | --program-tran \
+ | --progr-tra | --program-tr | --program-t)
+ ac_prev=program_transform_name ;;
+ -program-transform-name=* | --program-transform-name=* \
+ | --program-transform-nam=* | --program-transform-na=* \
+ | --program-transform-n=* | --program-transform-=* \
+ | --program-transform=* | --program-transfor=* \
+ | --program-transfo=* | --program-transf=* \
+ | --program-trans=* | --program-tran=* \
+ | --progr-tra=* | --program-tr=* | --program-t=*)
+ program_transform_name=$ac_optarg ;;
+
+ -pdfdir | --pdfdir | --pdfdi | --pdfd | --pdf | --pd)
+ ac_prev=pdfdir ;;
+ -pdfdir=* | --pdfdir=* | --pdfdi=* | --pdfd=* | --pdf=* | --pd=*)
+ pdfdir=$ac_optarg ;;
+
+ -psdir | --psdir | --psdi | --psd | --ps)
+ ac_prev=psdir ;;
+ -psdir=* | --psdir=* | --psdi=* | --psd=* | --ps=*)
+ psdir=$ac_optarg ;;
+
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ silent=yes ;;
+
+ -sbindir | --sbindir | --sbindi | --sbind | --sbin | --sbi | --sb)
+ ac_prev=sbindir ;;
+ -sbindir=* | --sbindir=* | --sbindi=* | --sbind=* | --sbin=* \
+ | --sbi=* | --sb=*)
+ sbindir=$ac_optarg ;;
+
+ -sharedstatedir | --sharedstatedir | --sharedstatedi \
+ | --sharedstated | --sharedstate | --sharedstat | --sharedsta \
+ | --sharedst | --shareds | --shared | --share | --shar \
+ | --sha | --sh)
+ ac_prev=sharedstatedir ;;
+ -sharedstatedir=* | --sharedstatedir=* | --sharedstatedi=* \
+ | --sharedstated=* | --sharedstate=* | --sharedstat=* | --sharedsta=* \
+ | --sharedst=* | --shareds=* | --shared=* | --share=* | --shar=* \
+ | --sha=* | --sh=*)
+ sharedstatedir=$ac_optarg ;;
+
+ -site | --site | --sit)
+ ac_prev=site ;;
+ -site=* | --site=* | --sit=*)
+ site=$ac_optarg ;;
+
+ -srcdir | --srcdir | --srcdi | --srcd | --src | --sr)
+ ac_prev=srcdir ;;
+ -srcdir=* | --srcdir=* | --srcdi=* | --srcd=* | --src=* | --sr=*)
+ srcdir=$ac_optarg ;;
+
+ -sysconfdir | --sysconfdir | --sysconfdi | --sysconfd | --sysconf \
+ | --syscon | --sysco | --sysc | --sys | --sy)
+ ac_prev=sysconfdir ;;
+ -sysconfdir=* | --sysconfdir=* | --sysconfdi=* | --sysconfd=* | --sysconf=* \
+ | --syscon=* | --sysco=* | --sysc=* | --sys=* | --sy=*)
+ sysconfdir=$ac_optarg ;;
+
+ -target | --target | --targe | --targ | --tar | --ta | --t)
+ ac_prev=target_alias ;;
+ -target=* | --target=* | --targe=* | --targ=* | --tar=* | --ta=* | --t=*)
+ target_alias=$ac_optarg ;;
+
+ -v | -verbose | --verbose | --verbos | --verbo | --verb)
+ verbose=yes ;;
+
+ -version | --version | --versio | --versi | --vers | -V)
+ ac_init_version=: ;;
+
+ -with-* | --with-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*with-\([^=]*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--with-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=\$ac_optarg ;;
+
+ -without-* | --without-*)
+ ac_useropt=`expr "x$ac_option" : 'x-*without-\(.*\)'`
+ # Reject names that are not valid shell variable names.
+ expr "x$ac_useropt" : ".*[^-+._$as_cr_alnum]" >/dev/null &&
+ as_fn_error $? "invalid package name: $ac_useropt"
+ ac_useropt_orig=$ac_useropt
+ ac_useropt=`$as_echo "$ac_useropt" | sed 's/[-+.]/_/g'`
+ case $ac_user_opts in
+ *"
+"with_$ac_useropt"
+"*) ;;
+ *) ac_unrecognized_opts="$ac_unrecognized_opts$ac_unrecognized_sep--without-$ac_useropt_orig"
+ ac_unrecognized_sep=', ';;
+ esac
+ eval with_$ac_useropt=no ;;
+
+ --x)
+ # Obsolete; use --with-x.
+ with_x=yes ;;
+
+ -x-includes | --x-includes | --x-include | --x-includ | --x-inclu \
+ | --x-incl | --x-inc | --x-in | --x-i)
+ ac_prev=x_includes ;;
+ -x-includes=* | --x-includes=* | --x-include=* | --x-includ=* | --x-inclu=* \
+ | --x-incl=* | --x-inc=* | --x-in=* | --x-i=*)
+ x_includes=$ac_optarg ;;
+
+ -x-libraries | --x-libraries | --x-librarie | --x-librari \
+ | --x-librar | --x-libra | --x-libr | --x-lib | --x-li | --x-l)
+ ac_prev=x_libraries ;;
+ -x-libraries=* | --x-libraries=* | --x-librarie=* | --x-librari=* \
+ | --x-librar=* | --x-libra=* | --x-libr=* | --x-lib=* | --x-li=* | --x-l=*)
+ x_libraries=$ac_optarg ;;
+
+ -*) as_fn_error $? "unrecognized option: \`$ac_option'
+Try \`$0 --help' for more information"
+ ;;
+
+ *=*)
+ ac_envvar=`expr "x$ac_option" : 'x\([^=]*\)='`
+ # Reject names that are not valid shell variable names.
+ case $ac_envvar in #(
+ '' | [0-9]* | *[!_$as_cr_alnum]* )
+ as_fn_error $? "invalid variable name: \`$ac_envvar'" ;;
+ esac
+ eval $ac_envvar=\$ac_optarg
+ export $ac_envvar ;;
+
+ *)
+ # FIXME: should be removed in autoconf 3.0.
+ $as_echo "$as_me: WARNING: you should use --build, --host, --target" >&2
+ expr "x$ac_option" : ".*[^-._$as_cr_alnum]" >/dev/null &&
+ $as_echo "$as_me: WARNING: invalid host type: $ac_option" >&2
+ : "${build_alias=$ac_option} ${host_alias=$ac_option} ${target_alias=$ac_option}"
+ ;;
+
+ esac
+done
+
+if test -n "$ac_prev"; then
+ ac_option=--`echo $ac_prev | sed 's/_/-/g'`
+ as_fn_error $? "missing argument to $ac_option"
+fi
+
+if test -n "$ac_unrecognized_opts"; then
+ case $enable_option_checking in
+ no) ;;
+ fatal) as_fn_error $? "unrecognized options: $ac_unrecognized_opts" ;;
+ *) $as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2 ;;
+ esac
+fi
+
+# Check all directory arguments for consistency.
+for ac_var in exec_prefix prefix bindir sbindir libexecdir datarootdir \
+ datadir sysconfdir sharedstatedir localstatedir includedir \
+ oldincludedir docdir infodir htmldir dvidir pdfdir psdir \
+ libdir localedir mandir
+do
+ eval ac_val=\$$ac_var
+ # Remove trailing slashes.
+ case $ac_val in
+ */ )
+ ac_val=`expr "X$ac_val" : 'X\(.*[^/]\)' \| "X$ac_val" : 'X\(.*\)'`
+ eval $ac_var=\$ac_val;;
+ esac
+ # Be sure to have absolute directory names.
+ case $ac_val in
+ [\\/$]* | ?:[\\/]* ) continue;;
+ NONE | '' ) case $ac_var in *prefix ) continue;; esac;;
+ esac
+ as_fn_error $? "expected an absolute directory name for --$ac_var: $ac_val"
+done
+
+# There might be people who depend on the old broken behavior: `$host'
+# used to hold the argument of --host etc.
+# FIXME: To remove some day.
+build=$build_alias
+host=$host_alias
+target=$target_alias
+
+# FIXME: To remove some day.
+if test "x$host_alias" != x; then
+ if test "x$build_alias" = x; then
+ cross_compiling=maybe
+ elif test "x$build_alias" != "x$host_alias"; then
+ cross_compiling=yes
+ fi
+fi
+
+ac_tool_prefix=
+test -n "$host_alias" && ac_tool_prefix=$host_alias-
+
+test "$silent" = yes && exec 6>/dev/null
+
+
+ac_pwd=`pwd` && test -n "$ac_pwd" &&
+ac_ls_di=`ls -di .` &&
+ac_pwd_ls_di=`cd "$ac_pwd" && ls -di .` ||
+ as_fn_error $? "working directory cannot be determined"
+test "X$ac_ls_di" = "X$ac_pwd_ls_di" ||
+ as_fn_error $? "pwd does not report name of working directory"
+
+
+# Find the source files, if location was not specified.
+if test -z "$srcdir"; then
+ ac_srcdir_defaulted=yes
+ # Try the directory containing this script, then the parent directory.
+ ac_confdir=`$as_dirname -- "$as_myself" ||
+$as_expr X"$as_myself" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_myself" : 'X\(//\)[^/]' \| \
+ X"$as_myself" : 'X\(//\)$' \| \
+ X"$as_myself" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_myself" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ srcdir=$ac_confdir
+ if test ! -r "$srcdir/$ac_unique_file"; then
+ srcdir=..
+ fi
+else
+ ac_srcdir_defaulted=no
+fi
+if test ! -r "$srcdir/$ac_unique_file"; then
+ test "$ac_srcdir_defaulted" = yes && srcdir="$ac_confdir or .."
+ as_fn_error $? "cannot find sources ($ac_unique_file) in $srcdir"
+fi
+ac_msg="sources are in $srcdir, but \`cd $srcdir' does not work"
+ac_abs_confdir=`(
+ cd "$srcdir" && test -r "./$ac_unique_file" || as_fn_error $? "$ac_msg"
+ pwd)`
+# When building in place, set srcdir=.
+if test "$ac_abs_confdir" = "$ac_pwd"; then
+ srcdir=.
+fi
+# Remove unnecessary trailing slashes from srcdir.
+# Double slashes in file names in object file debugging info
+# mess up M-x gdb in Emacs.
+case $srcdir in
+*/) srcdir=`expr "X$srcdir" : 'X\(.*[^/]\)' \| "X$srcdir" : 'X\(.*\)'`;;
+esac
+for ac_var in $ac_precious_vars; do
+ eval ac_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_env_${ac_var}_value=\$${ac_var}
+ eval ac_cv_env_${ac_var}_set=\${${ac_var}+set}
+ eval ac_cv_env_${ac_var}_value=\$${ac_var}
+done
+
+#
+# Report the --help message.
+#
+if test "$ac_init_help" = "long"; then
+ # Omit some internal or obsolete options to make the list less imposing.
+ # This message is too long to be a string in the A/UX 3.1 sh.
+ cat <<_ACEOF
+\`configure' configures pdns 4.0.4 to adapt to many kinds of systems.
+
+Usage: $0 [OPTION]... [VAR=VALUE]...
+
+To assign environment variables (e.g., CC, CFLAGS...), specify them as
+VAR=VALUE. See below for descriptions of some of the useful variables.
+
+Defaults for the options are specified in brackets.
+
+Configuration:
+ -h, --help display this help and exit
+ --help=short display options specific to this package
+ --help=recursive display the short help of all the included packages
+ -V, --version display version information and exit
+ -q, --quiet, --silent do not print \`checking ...' messages
+ --cache-file=FILE cache test results in FILE [disabled]
+ -C, --config-cache alias for \`--cache-file=config.cache'
+ -n, --no-create do not create output files
+ --srcdir=DIR find the sources in DIR [configure dir or \`..']
+
+Installation directories:
+ --prefix=PREFIX install architecture-independent files in PREFIX
+ [$ac_default_prefix]
+ --exec-prefix=EPREFIX install architecture-dependent files in EPREFIX
+ [PREFIX]
+
+By default, \`make install' will install all the files in
+\`$ac_default_prefix/bin', \`$ac_default_prefix/lib' etc. You can specify
+an installation prefix other than \`$ac_default_prefix' using \`--prefix',
+for instance \`--prefix=\$HOME'.
+
+For better control, use the options below.
+
+Fine tuning of the installation directories:
+ --bindir=DIR user executables [EPREFIX/bin]
+ --sbindir=DIR system admin executables [EPREFIX/sbin]
+ --libexecdir=DIR program executables [EPREFIX/libexec]
+ --sysconfdir=DIR read-only single-machine data [PREFIX/etc]
+ --sharedstatedir=DIR modifiable architecture-independent data [PREFIX/com]
+ --localstatedir=DIR modifiable single-machine data [PREFIX/var]
+ --libdir=DIR object code libraries [EPREFIX/lib]
+ --includedir=DIR C header files [PREFIX/include]
+ --oldincludedir=DIR C header files for non-gcc [/usr/include]
+ --datarootdir=DIR read-only arch.-independent data root [PREFIX/share]
+ --datadir=DIR read-only architecture-independent data [DATAROOTDIR]
+ --infodir=DIR info documentation [DATAROOTDIR/info]
+ --localedir=DIR locale-dependent data [DATAROOTDIR/locale]
+ --mandir=DIR man documentation [DATAROOTDIR/man]
+ --docdir=DIR documentation root [DATAROOTDIR/doc/pdns]
+ --htmldir=DIR html documentation [DOCDIR]
+ --dvidir=DIR dvi documentation [DOCDIR]
+ --pdfdir=DIR pdf documentation [DOCDIR]
+ --psdir=DIR ps documentation [DOCDIR]
+_ACEOF
+
+ cat <<\_ACEOF
+
+Program names:
+ --program-prefix=PREFIX prepend PREFIX to installed program names
+ --program-suffix=SUFFIX append SUFFIX to installed program names
+ --program-transform-name=PROGRAM run sed PROGRAM on installed program names
+
+System types:
+ --build=BUILD configure for building on BUILD [guessed]
+ --host=HOST cross-compile to build programs to run on HOST [BUILD]
+_ACEOF
+fi
+
+if test -n "$ac_init_help"; then
+ case $ac_init_help in
+ short | recursive ) echo "Configuration of pdns 4.0.4:";;
+ esac
+ cat <<\_ACEOF
+
+Optional Features:
+ --disable-option-checking ignore unrecognized --enable/--with options
+ --disable-FEATURE do not include FEATURE (same as --enable-FEATURE=no)
+ --enable-FEATURE[=ARG] include FEATURE [ARG=yes]
+ --enable-silent-rules less verbose build output (undo: "make V=1")
+ --disable-silent-rules verbose build output (undo: "make V=0")
+ --enable-dependency-tracking
+ do not reject slow dependency extractors
+ --disable-dependency-tracking
+ speeds up one-time build
+ --disable-hardening disable compiler security checks [default=no]
+ --enable-static[=PKGS] build static libraries [default=no]
+ --enable-shared[=PKGS] build shared libraries [default=yes]
+ --enable-fast-install[=PKGS]
+ optimize for fast installation [default=yes]
+ --disable-libtool-lock avoid locking (might break parallel builds)
+ --enable-botan1.10 use Botan 1.10 [default=no]
+ --enable-libsodium use libsodium [default=no]
+ --enable-libdecaf use libdecaf [default=no]
+ --enable-static-boost Prefer the static boost libraries over the shared
+ ones [no]
+ --enable-unit-tests enable unit test building [default=no]
+ --enable-backend-unit-tests
+ enable backend unit test building [default=no]
+ --enable-reproducible Create reproducible builds. Use this only if you are
+ a distribution maintainer and need reproducible
+ builds. If you compile PowerDNS yourself, leave this
+ disabled, as it might make debugging harder.
+ [default=no]
+ --enable-verbose-logging
+ enable verbose logging [default=no]
+ --enable-experimental-pkcs11
+ enable experimental PKCS11 support [default=no]
+ --enable-experimental-gss-tsig
+ enable experimental GSS-TSIG support [default=no]
+ --enable-remotebackend-zeromq
+ enable ZeroMQ connector for remotebackend
+ [default=no]
+ --enable-tools if we should build and install the tools
+ [default=no]
+ --enable-systemd Enable systemd support (default is DISABLED)
+ --enable-coverage enable code coverage [default=no]
+ --enable-asan enable AddressSanitizer [default=no]
+ --enable-msan enable MemorySanitizer [default=no]
+ --enable-tsan enable ThreadSanitizer [default=no]
+ --enable-lsan enable LeakSanitizer [default=no]
+ --enable-ubsan enable Undefined Behaviour Sanitizer [default=no]
+ --enable-malloc-trace enable malloc-trace [default=no]
+
+Optional Packages:
+ --with-PACKAGE[=ARG] use PACKAGE [ARG=yes]
+ --without-PACKAGE do not use PACKAGE (same as --with-PACKAGE=no)
+ --with-luajit build LuaJIT bindings [default=auto]
+ --with-lua build Lua Bindings [default=auto]
+ --with-pic[=PKGS] try to use only PIC/non-PIC objects [default=use
+ both]
+ --with-gnu-ld assume the C compiler uses GNU ld [default=no]
+ --with-sysroot=DIR Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).
+ --with-libcrypto=DIR root of the OpenSSL directory
+ --with-boost=DIR prefix of Boost 1.35 [guess]
+ --with-sqlite3 include sqlite3 driver [default=no]
+ --with-socketdir where the controlsocket lives [default=/var/run]
+ --with-modules which backends to compile with [default=bind gmysql
+ random]
+ --with-dynmodules which backends to build for dynamic loading
+ [default=pipe]
+ --with-oracle-includes=<path>
+ instantclient sdk include dir
+ --with-oracle-libs=<path>
+ instantclient oracle library dir
+ --with-unixodbc=<path> root directory path of unixODBC installation
+ --with-odbc-config=<path>
+ file path to odbc_config
+ --with-unixodbc-lib=<path>
+ directory path of unixODBC library installation
+ --with-unixodbc-includes=<path>
+ directory path of unixODBC header installation
+ --with-mysql=<path> root directory path of MySQL installation
+ --with-mysql-config=<path>
+ file path to mysql_config
+ --with-mysql-lib=<path> directory path of MySQL library installation
+ --with-mysql-includes=<path>
+ directory path of MySQL header installation
+ --with-pgsql=<path> root directory path of PgSQL installation
+ --with-pgsql-lib=<path> directory path of PgSQL library installation
+ --with-pgsql-includes=<path>
+ directory path of PgSQL header installation
+ --with-pgsql-config=<path>
+ location of pg_config
+ --with-protobuf enable protobuf support [default=auto]
+ --with-systemd set directory for systemd service files
+ --with-systemd-modules-load set directory for systemd modules load files
+
+Some influential environment variables:
+ CC C compiler command
+ CFLAGS C compiler flags
+ LDFLAGS linker flags, e.g. -L<lib dir> if you have libraries in a
+ nonstandard directory <lib dir>
+ LIBS libraries to pass to the linker, e.g. -l<library>
+ CPPFLAGS (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
+ you have headers in a nonstandard directory <include dir>
+ YACC The `Yet Another Compiler Compiler' implementation to use.
+ Defaults to the first program found out of: `bison -y', `byacc',
+ `yacc'.
+ YFLAGS The list of arguments that will be passed by default to $YACC.
+ This script will default YFLAGS to the empty string to avoid a
+ default value of `-d' given by some make applications.
+ CXX C++ compiler command
+ CXXFLAGS C++ compiler flags
+ PKG_CONFIG path to pkg-config utility
+ PKG_CONFIG_PATH
+ directories to add to pkg-config's search path
+ PKG_CONFIG_LIBDIR
+ path overriding pkg-config's built-in search path
+ LUA_CFLAGS C compiler flags for LUA, overriding pkg-config
+ LUA_LIBS linker flags for LUA, overriding pkg-config
+ CXXCPP C++ preprocessor
+ BOTAN110_CFLAGS
+ C compiler flags for BOTAN110, overriding pkg-config
+ BOTAN110_LIBS
+ linker flags for BOTAN110, overriding pkg-config
+ LIBSODIUM_CFLAGS
+ C compiler flags for LIBSODIUM, overriding pkg-config
+ LIBSODIUM_LIBS
+ linker flags for LIBSODIUM, overriding pkg-config
+ BOOST_ROOT Location of Boost installation
+ P11KIT1_CFLAGS
+ C compiler flags for P11KIT1, overriding pkg-config
+ P11KIT1_LIBS
+ linker flags for P11KIT1, overriding pkg-config
+ GSS_CFLAGS C compiler flags for GSS, overriding pkg-config
+ GSS_LIBS linker flags for GSS, overriding pkg-config
+ LDAP_LIBS linker flags for openldap
+ OPENDBX_CFLAGS
+ C compiler flags for OPENDBX, overriding pkg-config
+ OPENDBX_LIBS
+ linker flags for OPENDBX, overriding pkg-config
+ CDB_CFLAGS C compiler flags for CDB, overriding pkg-config
+ CDB_LIBS linker flags for CDB, overriding pkg-config
+ GEOIP_CFLAGS
+ C compiler flags for GEOIP, overriding pkg-config
+ GEOIP_LIBS linker flags for GEOIP, overriding pkg-config
+ YAML_CFLAGS C compiler flags for YAML, overriding pkg-config
+ YAML_LIBS linker flags for YAML, overriding pkg-config
+ LIBZMQ_CFLAGS
+ C compiler flags for LIBZMQ, overriding pkg-config
+ LIBZMQ_LIBS linker flags for LIBZMQ, overriding pkg-config
+ PROTOBUF_CFLAGS
+ C compiler flags for PROTOBUF, overriding pkg-config
+ PROTOBUF_LIBS
+ linker flags for PROTOBUF, overriding pkg-config
+ SQLITE3_CFLAGS
+ C compiler flags for SQLITE3, overriding pkg-config
+ SQLITE3_LIBS
+ linker flags for SQLITE3, overriding pkg-config
+ SYSTEMD_CFLAGS
+ C compiler flags for SYSTEMD, overriding pkg-config
+ SYSTEMD_LIBS
+ linker flags for SYSTEMD, overriding pkg-config
+ PACKAGEVERSION
+ The version used in secpoll queries
+
+Use these variables to override the choices made by `configure' or to help
+it to find libraries and programs with nonstandard names/locations.
+
+Report bugs to the package provider.
+_ACEOF
+ac_status=$?
+fi
+
+if test "$ac_init_help" = "recursive"; then
+ # If there are subdirs, report their specific --help.
+ for ac_dir in : $ac_subdirs_all; do test "x$ac_dir" = x: && continue
+ test -d "$ac_dir" ||
+ { cd "$srcdir" && ac_pwd=`pwd` && srcdir=. && test -d "$ac_dir"; } ||
+ continue
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+ cd "$ac_dir" || { ac_status=$?; continue; }
+ # Check for guested configure.
+ if test -f "$ac_srcdir/configure.gnu"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure.gnu" --help=recursive
+ elif test -f "$ac_srcdir/configure"; then
+ echo &&
+ $SHELL "$ac_srcdir/configure" --help=recursive
+ else
+ $as_echo "$as_me: WARNING: no configuration information is in $ac_dir" >&2
+ fi || ac_status=$?
+ cd "$ac_pwd" || { ac_status=$?; break; }
+ done
+fi
+
+test -n "$ac_init_help" && exit $ac_status
+if $ac_init_version; then
+ cat <<\_ACEOF
+pdns configure 4.0.4
+generated by GNU Autoconf 2.69
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This configure script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it.
+_ACEOF
+ exit
+fi
+
+## ------------------------ ##
+## Autoconf initialization. ##
+## ------------------------ ##
+
+# ac_fn_c_try_compile LINENO
+# --------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_compile
+
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_c_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_cxx_try_compile LINENO
+# ----------------------------
+# Try to compile conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext
+ if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest.$ac_objext; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_compile
+
+# ac_fn_cxx_try_link LINENO
+# -------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_link ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ rm -f conftest.$ac_objext conftest$ac_exeext
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ test -x conftest$ac_exeext
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+ # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+ # interfere with the next link command; also delete a directory that is
+ # left behind by Apple's compiler. We do this before executing the actions.
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_link
+
+# ac_fn_cxx_try_cpp LINENO
+# ------------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_cxx_try_cpp ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_cpp conftest.$ac_ext"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } > conftest.i && {
+ test -z "$ac_cxx_preproc_warn_flag$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=1
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_cpp
+
+# ac_fn_cxx_check_header_mongrel LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_cxx_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if eval \${$3+:} false; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_cxx_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_mongrel
+
+# ac_fn_cxx_try_run LINENO
+# ------------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded. Assumes
+# that executables *can* be run.
+ac_fn_cxx_try_run ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && { ac_try='./conftest$ac_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then :
+ ac_retval=0
+else
+ $as_echo "$as_me: program exited with status $ac_status" >&5
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ ac_retval=$ac_status
+fi
+ rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+ as_fn_set_status $ac_retval
+
+} # ac_fn_cxx_try_run
+
+# ac_fn_cxx_check_header_compile LINENO HEADER VAR INCLUDES
+# ---------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_cxx_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_header_compile
+
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_header_compile
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_c_check_func
+
+# ac_fn_cxx_check_func LINENO FUNC VAR
+# ------------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_cxx_check_func ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+ For example, HP-UX 11i <limits.h> declares gettimeofday. */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+ which can conflict with char $2 (); below.
+ Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ <limits.h> exists even on freestanding compilers. */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+
+#undef $2
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char $2 ();
+/* The GNU C library defines this for functions which it implements
+ to always fail with ENOSYS. Some functions are actually named
+ something starting with __ and the normal name is an alias. */
+#if defined __stub_$2 || defined __stub___$2
+choke me
+#endif
+
+int
+main ()
+{
+return $2 ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_func
+
+# ac_fn_cxx_check_decl LINENO SYMBOL VAR INCLUDES
+# -----------------------------------------------
+# Tests whether SYMBOL is declared in INCLUDES, setting cache variable VAR
+# accordingly.
+ac_fn_cxx_check_decl ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ as_decl_name=`echo $2|sed 's/ *(.*//'`
+ as_decl_use=`echo $2|sed -e 's/(/((/' -e 's/)/) 0&/' -e 's/,/) 0& (/g'`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $as_decl_name is declared" >&5
+$as_echo_n "checking whether $as_decl_name is declared... " >&6; }
+if eval \${$3+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+int
+main ()
+{
+#ifndef $as_decl_name
+#ifdef __cplusplus
+ (void) $as_decl_use;
+#else
+ (void) $as_decl_name;
+#endif
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval "$3=yes"
+else
+ eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+
+} # ac_fn_cxx_check_decl
+cat >config.log <<_ACEOF
+This file contains any messages produced by compilers while
+running configure, to aid debugging if configure makes a mistake.
+
+It was created by pdns $as_me 4.0.4, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ $ $0 $@
+
+_ACEOF
+exec 5>>config.log
+{
+cat <<_ASUNAME
+## --------- ##
+## Platform. ##
+## --------- ##
+
+hostname = `(hostname || uname -n) 2>/dev/null | sed 1q`
+uname -m = `(uname -m) 2>/dev/null || echo unknown`
+uname -r = `(uname -r) 2>/dev/null || echo unknown`
+uname -s = `(uname -s) 2>/dev/null || echo unknown`
+uname -v = `(uname -v) 2>/dev/null || echo unknown`
+
+/usr/bin/uname -p = `(/usr/bin/uname -p) 2>/dev/null || echo unknown`
+/bin/uname -X = `(/bin/uname -X) 2>/dev/null || echo unknown`
+
+/bin/arch = `(/bin/arch) 2>/dev/null || echo unknown`
+/usr/bin/arch -k = `(/usr/bin/arch -k) 2>/dev/null || echo unknown`
+/usr/convex/getsysinfo = `(/usr/convex/getsysinfo) 2>/dev/null || echo unknown`
+/usr/bin/hostinfo = `(/usr/bin/hostinfo) 2>/dev/null || echo unknown`
+/bin/machine = `(/bin/machine) 2>/dev/null || echo unknown`
+/usr/bin/oslevel = `(/usr/bin/oslevel) 2>/dev/null || echo unknown`
+/bin/universe = `(/bin/universe) 2>/dev/null || echo unknown`
+
+_ASUNAME
+
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ $as_echo "PATH: $as_dir"
+ done
+IFS=$as_save_IFS
+
+} >&5
+
+cat >&5 <<_ACEOF
+
+
+## ----------- ##
+## Core tests. ##
+## ----------- ##
+
+_ACEOF
+
+
+# Keep a trace of the command line.
+# Strip out --no-create and --no-recursion so they do not pile up.
+# Strip out --silent because we don't want to record it for future runs.
+# Also quote any args containing shell meta-characters.
+# Make two passes to allow for proper duplicate-argument suppression.
+ac_configure_args=
+ac_configure_args0=
+ac_configure_args1=
+ac_must_keep_next=false
+for ac_pass in 1 2
+do
+ for ac_arg
+ do
+ case $ac_arg in
+ -no-create | --no-c* | -n | -no-recursion | --no-r*) continue ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil)
+ continue ;;
+ *\'*)
+ ac_arg=`$as_echo "$ac_arg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ case $ac_pass in
+ 1) as_fn_append ac_configure_args0 " '$ac_arg'" ;;
+ 2)
+ as_fn_append ac_configure_args1 " '$ac_arg'"
+ if test $ac_must_keep_next = true; then
+ ac_must_keep_next=false # Got value, back to normal.
+ else
+ case $ac_arg in
+ *=* | --config-cache | -C | -disable-* | --disable-* \
+ | -enable-* | --enable-* | -gas | --g* | -nfp | --nf* \
+ | -q | -quiet | --q* | -silent | --sil* | -v | -verb* \
+ | -with-* | --with-* | -without-* | --without-* | --x)
+ case "$ac_configure_args0 " in
+ "$ac_configure_args1"*" '$ac_arg' "* ) continue ;;
+ esac
+ ;;
+ -* ) ac_must_keep_next=true ;;
+ esac
+ fi
+ as_fn_append ac_configure_args " '$ac_arg'"
+ ;;
+ esac
+ done
+done
+{ ac_configure_args0=; unset ac_configure_args0;}
+{ ac_configure_args1=; unset ac_configure_args1;}
+
+# When interrupted or exit'd, cleanup temporary files, and complete
+# config.log. We remove comments because anyway the quotes in there
+# would cause problems or look ugly.
+# WARNING: Use '\'' to represent an apostrophe within the trap.
+# WARNING: Do not start the trap code with a newline, due to a FreeBSD 4.0 bug.
+trap 'exit_status=$?
+ # Save into config.log some information that might help in debugging.
+ {
+ echo
+
+ $as_echo "## ---------------- ##
+## Cache variables. ##
+## ---------------- ##"
+ echo
+ # The following way of writing the cache mishandles newlines in values,
+(
+ for ac_var in `(set) 2>&1 | sed -n '\''s/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'\''`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+ (set) 2>&1 |
+ case $as_nl`(ac_space='\'' '\''; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ sed -n \
+ "s/'\''/'\''\\\\'\'''\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\''\\2'\''/p"
+ ;; #(
+ *)
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+)
+ echo
+
+ $as_echo "## ----------------- ##
+## Output variables. ##
+## ----------------- ##"
+ echo
+ for ac_var in $ac_subst_vars
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+
+ if test -n "$ac_subst_files"; then
+ $as_echo "## ------------------- ##
+## File substitutions. ##
+## ------------------- ##"
+ echo
+ for ac_var in $ac_subst_files
+ do
+ eval ac_val=\$$ac_var
+ case $ac_val in
+ *\'\''*) ac_val=`$as_echo "$ac_val" | sed "s/'\''/'\''\\\\\\\\'\'''\''/g"`;;
+ esac
+ $as_echo "$ac_var='\''$ac_val'\''"
+ done | sort
+ echo
+ fi
+
+ if test -s confdefs.h; then
+ $as_echo "## ----------- ##
+## confdefs.h. ##
+## ----------- ##"
+ echo
+ cat confdefs.h
+ echo
+ fi
+ test "$ac_signal" != 0 &&
+ $as_echo "$as_me: caught signal $ac_signal"
+ $as_echo "$as_me: exit $exit_status"
+ } >&5
+ rm -f core *.core core.conftest.* &&
+ rm -f -r conftest* confdefs* conf$$* $ac_clean_files &&
+ exit $exit_status
+' 0
+for ac_signal in 1 2 13 15; do
+ trap 'ac_signal='$ac_signal'; as_fn_exit 1' $ac_signal
+done
+ac_signal=0
+
+# confdefs.h avoids OS command line length limits that DEFS can exceed.
+rm -f -r conftest* confdefs.h
+
+$as_echo "/* confdefs.h */" > confdefs.h
+
+# Predefined preprocessor variables.
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_NAME "$PACKAGE_NAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_TARNAME "$PACKAGE_TARNAME"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_VERSION "$PACKAGE_VERSION"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_STRING "$PACKAGE_STRING"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_BUGREPORT "$PACKAGE_BUGREPORT"
+_ACEOF
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE_URL "$PACKAGE_URL"
+_ACEOF
+
+
+# Let the site file select an alternate cache file if it wants to.
+# Prefer an explicitly selected file to automatically selected ones.
+ac_site_file1=NONE
+ac_site_file2=NONE
+if test -n "$CONFIG_SITE"; then
+ # We do not want a PATH search for config.site.
+ case $CONFIG_SITE in #((
+ -*) ac_site_file1=./$CONFIG_SITE;;
+ */*) ac_site_file1=$CONFIG_SITE;;
+ *) ac_site_file1=./$CONFIG_SITE;;
+ esac
+elif test "x$prefix" != xNONE; then
+ ac_site_file1=$prefix/share/config.site
+ ac_site_file2=$prefix/etc/config.site
+else
+ ac_site_file1=$ac_default_prefix/share/config.site
+ ac_site_file2=$ac_default_prefix/etc/config.site
+fi
+for ac_site_file in "$ac_site_file1" "$ac_site_file2"
+do
+ test "x$ac_site_file" = xNONE && continue
+ if test /dev/null != "$ac_site_file" && test -r "$ac_site_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading site script $ac_site_file" >&5
+$as_echo "$as_me: loading site script $ac_site_file" >&6;}
+ sed 's/^/| /' "$ac_site_file" >&5
+ . "$ac_site_file" \
+ || { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "failed to load site script $ac_site_file
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+done
+
+if test -r "$cache_file"; then
+ # Some versions of bash will fail to source /dev/null (special files
+ # actually), so we avoid doing that. DJGPP emulates it as a regular file.
+ if test /dev/null != "$cache_file" && test -f "$cache_file"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: loading cache $cache_file" >&5
+$as_echo "$as_me: loading cache $cache_file" >&6;}
+ case $cache_file in
+ [\\/]* | ?:[\\/]* ) . "$cache_file";;
+ *) . "./$cache_file";;
+ esac
+ fi
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating cache $cache_file" >&5
+$as_echo "$as_me: creating cache $cache_file" >&6;}
+ >$cache_file
+fi
+
+as_fn_append ac_func_list " strcasestr"
+as_fn_append ac_func_list " localtime_r"
+as_fn_append ac_func_list " recvmmsg"
+# Check that the precious variables saved in the cache have kept the same
+# value.
+ac_cache_corrupted=false
+for ac_var in $ac_precious_vars; do
+ eval ac_old_set=\$ac_cv_env_${ac_var}_set
+ eval ac_new_set=\$ac_env_${ac_var}_set
+ eval ac_old_val=\$ac_cv_env_${ac_var}_value
+ eval ac_new_val=\$ac_env_${ac_var}_value
+ case $ac_old_set,$ac_new_set in
+ set,)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was set to \`$ac_old_val' in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,set)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' was not set in the previous run" >&5
+$as_echo "$as_me: error: \`$ac_var' was not set in the previous run" >&2;}
+ ac_cache_corrupted=: ;;
+ ,);;
+ *)
+ if test "x$ac_old_val" != "x$ac_new_val"; then
+ # differences in whitespace do not lead to failure.
+ ac_old_val_w=`echo x $ac_old_val`
+ ac_new_val_w=`echo x $ac_new_val`
+ if test "$ac_old_val_w" != "$ac_new_val_w"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: \`$ac_var' has changed since the previous run:" >&5
+$as_echo "$as_me: error: \`$ac_var' has changed since the previous run:" >&2;}
+ ac_cache_corrupted=:
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&5
+$as_echo "$as_me: warning: ignoring whitespace changes in \`$ac_var' since the previous run:" >&2;}
+ eval $ac_var=\$ac_old_val
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: former value: \`$ac_old_val'" >&5
+$as_echo "$as_me: former value: \`$ac_old_val'" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: current value: \`$ac_new_val'" >&5
+$as_echo "$as_me: current value: \`$ac_new_val'" >&2;}
+ fi;;
+ esac
+ # Pass precious variables to config.status.
+ if test "$ac_new_set" = set; then
+ case $ac_new_val in
+ *\'*) ac_arg=$ac_var=`$as_echo "$ac_new_val" | sed "s/'/'\\\\\\\\''/g"` ;;
+ *) ac_arg=$ac_var=$ac_new_val ;;
+ esac
+ case " $ac_configure_args " in
+ *" '$ac_arg' "*) ;; # Avoid dups. Use of quotes ensures accuracy.
+ *) as_fn_append ac_configure_args " '$ac_arg'" ;;
+ esac
+ fi
+done
+if $ac_cache_corrupted; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: error: changes in the environment can compromise the build" >&5
+$as_echo "$as_me: error: changes in the environment can compromise the build" >&2;}
+ as_fn_error $? "run \`make distclean' and/or \`rm $cache_file' and start over" "$LINENO" 5
+fi
+## -------------------- ##
+## Main body of script. ##
+## -------------------- ##
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+
+
+
+ac_config_headers="$ac_config_headers config.h"
+
+ac_aux_dir=
+for ac_dir in build-aux "$srcdir"/build-aux; do
+ if test -f "$ac_dir/install-sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install-sh -c"
+ break
+ elif test -f "$ac_dir/install.sh"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/install.sh -c"
+ break
+ elif test -f "$ac_dir/shtool"; then
+ ac_aux_dir=$ac_dir
+ ac_install_sh="$ac_aux_dir/shtool install -c"
+ break
+ fi
+done
+if test -z "$ac_aux_dir"; then
+ as_fn_error $? "cannot find install-sh, install.sh, or shtool in build-aux \"$srcdir\"/build-aux" "$LINENO" 5
+fi
+
+# These three variables are undocumented and unsupported,
+# and are intended to be withdrawn in a future Autoconf release.
+# They can cause serious problems if a builder's source tree is in a directory
+# whose full name contains unusual characters.
+ac_config_guess="$SHELL $ac_aux_dir/config.guess" # Please don't use this var.
+ac_config_sub="$SHELL $ac_aux_dir/config.sub" # Please don't use this var.
+ac_configure="$SHELL $ac_aux_dir/configure" # Please don't use this var.
+
+
+
+pdns_configure_args="$ac_configure_args"
+
+
+cat >>confdefs.h <<_ACEOF
+#define PDNS_CONFIG_ARGS "$pdns_configure_args"
+_ACEOF
+
+
+am__api_version='1.14'
+
+# Find a good install program. We prefer a C program (faster),
+# so one script is as good as another. But avoid the broken or
+# incompatible versions:
+# SysV /etc/install, /usr/sbin/install
+# SunOS /usr/etc/install
+# IRIX /sbin/install
+# AIX /bin/install
+# AmigaOS /C/install, which installs bootblocks on floppy discs
+# AIX 4 /usr/bin/installbsd, which doesn't work without a -g flag
+# AFS /usr/afsws/bin/install, which mishandles nonexistent args
+# SVR4 /usr/ucb/install, which tries to use the nonexistent group "staff"
+# OS/2's system install, which has a completely different semantic
+# ./install, which can be erroneously created by make from ./install.sh.
+# Reject install programs that cannot install multiple files.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a BSD-compatible install" >&5
+$as_echo_n "checking for a BSD-compatible install... " >&6; }
+if test -z "$INSTALL"; then
+if ${ac_cv_path_install+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ # Account for people who put trailing slashes in PATH elements.
+case $as_dir/ in #((
+ ./ | .// | /[cC]/* | \
+ /etc/* | /usr/sbin/* | /usr/etc/* | /sbin/* | /usr/afsws/bin/* | \
+ ?:[\\/]os2[\\/]install[\\/]* | ?:[\\/]OS2[\\/]INSTALL[\\/]* | \
+ /usr/ucb/* ) ;;
+ *)
+ # OSF1 and SCO ODT 3.0 have their own names for install.
+ # Don't use installbsd from OSF since it installs stuff as root
+ # by default.
+ for ac_prog in ginstall scoinst install; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext"; then
+ if test $ac_prog = install &&
+ grep dspmsg "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # AIX install. It has an incompatible calling convention.
+ :
+ elif test $ac_prog = install &&
+ grep pwplus "$as_dir/$ac_prog$ac_exec_ext" >/dev/null 2>&1; then
+ # program-specific install script used by HP pwplus--don't use.
+ :
+ else
+ rm -rf conftest.one conftest.two conftest.dir
+ echo one > conftest.one
+ echo two > conftest.two
+ mkdir conftest.dir
+ if "$as_dir/$ac_prog$ac_exec_ext" -c conftest.one conftest.two "`pwd`/conftest.dir" &&
+ test -s conftest.one && test -s conftest.two &&
+ test -s conftest.dir/conftest.one &&
+ test -s conftest.dir/conftest.two
+ then
+ ac_cv_path_install="$as_dir/$ac_prog$ac_exec_ext -c"
+ break 3
+ fi
+ fi
+ fi
+ done
+ done
+ ;;
+esac
+
+ done
+IFS=$as_save_IFS
+
+rm -rf conftest.one conftest.two conftest.dir
+
+fi
+ if test "${ac_cv_path_install+set}" = set; then
+ INSTALL=$ac_cv_path_install
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for INSTALL within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ INSTALL=$ac_install_sh
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $INSTALL" >&5
+$as_echo "$INSTALL" >&6; }
+
+# Use test -z because SunOS4 sh mishandles braces in ${var-val}.
+# It thinks the first close brace ends the variable substitution.
+test -z "$INSTALL_PROGRAM" && INSTALL_PROGRAM='${INSTALL}'
+
+test -z "$INSTALL_SCRIPT" && INSTALL_SCRIPT='${INSTALL}'
+
+test -z "$INSTALL_DATA" && INSTALL_DATA='${INSTALL} -m 644'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether build environment is sane" >&5
+$as_echo_n "checking whether build environment is sane... " >&6; }
+# Reject unsafe characters in $srcdir or the absolute working directory
+# name. Accept space and tab only in the latter.
+am_lf='
+'
+case `pwd` in
+ *[\\\"\#\$\&\'\`$am_lf]*)
+ as_fn_error $? "unsafe absolute working directory name" "$LINENO" 5;;
+esac
+case $srcdir in
+ *[\\\"\#\$\&\'\`$am_lf\ \ ]*)
+ as_fn_error $? "unsafe srcdir value: '$srcdir'" "$LINENO" 5;;
+esac
+
+# Do 'set' in a subshell so we don't clobber the current shell's
+# arguments. Must try -L first in case configure is actually a
+# symlink; some systems play weird games with the mod time of symlinks
+# (eg FreeBSD returns the mod time of the symlink's containing
+# directory).
+if (
+ am_has_slept=no
+ for am_try in 1 2; do
+ echo "timestamp, slept: $am_has_slept" > conftest.file
+ set X `ls -Lt "$srcdir/configure" conftest.file 2> /dev/null`
+ if test "$*" = "X"; then
+ # -L didn't work.
+ set X `ls -t "$srcdir/configure" conftest.file`
+ fi
+ if test "$*" != "X $srcdir/configure conftest.file" \
+ && test "$*" != "X conftest.file $srcdir/configure"; then
+
+ # If neither matched, then we have a broken ls. This can happen
+ # if, for instance, CONFIG_SHELL is bash and it inherits a
+ # broken ls alias from the environment. This has actually
+ # happened. Such a system could not be considered "sane".
+ as_fn_error $? "ls -t appears to fail. Make sure there is not a broken
+ alias in your environment" "$LINENO" 5
+ fi
+ if test "$2" = conftest.file || test $am_try -eq 2; then
+ break
+ fi
+ # Just in case.
+ sleep 1
+ am_has_slept=yes
+ done
+ test "$2" = conftest.file
+ )
+then
+ # Ok.
+ :
+else
+ as_fn_error $? "newly created file is older than distributed files!
+Check your system clock" "$LINENO" 5
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+# If we didn't sleep, we still need to ensure time stamps of config.status and
+# generated files are strictly newer.
+am_sleep_pid=
+if grep 'slept: no' conftest.file >/dev/null 2>&1; then
+ ( sleep 1 ) &
+ am_sleep_pid=$!
+fi
+
+rm -f conftest.file
+
+test "$program_prefix" != NONE &&
+ program_transform_name="s&^&$program_prefix&;$program_transform_name"
+# Use a double $ so make ignores it.
+test "$program_suffix" != NONE &&
+ program_transform_name="s&\$&$program_suffix&;$program_transform_name"
+# Double any \ or $.
+# By default was `s,x,x', remove it if useless.
+ac_script='s/[\\$]/&&/g;s/;s,x,x,$//'
+program_transform_name=`$as_echo "$program_transform_name" | sed "$ac_script"`
+
+# Expand $ac_aux_dir to an absolute path.
+am_aux_dir=`cd "$ac_aux_dir" && pwd`
+
+if test x"${MISSING+set}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ MISSING="\${SHELL} \"$am_aux_dir/missing\"" ;;
+ *)
+ MISSING="\${SHELL} $am_aux_dir/missing" ;;
+ esac
+fi
+# Use eval to expand $SHELL
+if eval "$MISSING --is-lightweight"; then
+ am_missing_run="$MISSING "
+else
+ am_missing_run=
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: 'missing' script is too old or missing" >&5
+$as_echo "$as_me: WARNING: 'missing' script is too old or missing" >&2;}
+fi
+
+if test x"${install_sh}" != xset; then
+ case $am_aux_dir in
+ *\ * | *\ *)
+ install_sh="\${SHELL} '$am_aux_dir/install-sh'" ;;
+ *)
+ install_sh="\${SHELL} $am_aux_dir/install-sh"
+ esac
+fi
+
+# Installed binaries are usually stripped using 'strip' when the user
+# run "make install-strip". However 'strip' might not be the right
+# tool to use in cross-compilation environments, therefore Automake
+# will honor the 'STRIP' environment variable to overrule this program.
+if test "$cross_compiling" != no; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+fi
+INSTALL_STRIP_PROGRAM="\$(install_sh) -c -s"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a thread-safe mkdir -p" >&5
+$as_echo_n "checking for a thread-safe mkdir -p... " >&6; }
+if test -z "$MKDIR_P"; then
+ if ${ac_cv_path_mkdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/opt/sfw/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in mkdir gmkdir; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ as_fn_executable_p "$as_dir/$ac_prog$ac_exec_ext" || continue
+ case `"$as_dir/$ac_prog$ac_exec_ext" --version 2>&1` in #(
+ 'mkdir (GNU coreutils) '* | \
+ 'mkdir (coreutils) '* | \
+ 'mkdir (fileutils) '4.1*)
+ ac_cv_path_mkdir=$as_dir/$ac_prog$ac_exec_ext
+ break 3;;
+ esac
+ done
+ done
+ done
+IFS=$as_save_IFS
+
+fi
+
+ test -d ./--version && rmdir ./--version
+ if test "${ac_cv_path_mkdir+set}" = set; then
+ MKDIR_P="$ac_cv_path_mkdir -p"
+ else
+ # As a last resort, use the slow shell script. Don't cache a
+ # value for MKDIR_P within a source directory, because that will
+ # break other packages using the cache if that directory is
+ # removed, or if the value is a relative name.
+ MKDIR_P="$ac_install_sh -d"
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $MKDIR_P" >&5
+$as_echo "$MKDIR_P" >&6; }
+
+for ac_prog in gawk mawk nawk awk
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AWK+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AWK"; then
+ ac_cv_prog_AWK="$AWK" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AWK="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AWK=$ac_cv_prog_AWK
+if test -n "$AWK"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AWK" >&5
+$as_echo "$AWK" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AWK" && break
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+rm -rf .tst 2>/dev/null
+mkdir .tst 2>/dev/null
+if test -d .tst; then
+ am__leading_dot=.
+else
+ am__leading_dot=_
+fi
+rmdir .tst 2>/dev/null
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+if test "`cd $srcdir && pwd`" != "`pwd`"; then
+ # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
+ # is not polluted with repeated "-I."
+ am__isrc=' -I$(srcdir)'
+ # test to see if srcdir already configured
+ if test -f $srcdir/config.status; then
+ as_fn_error $? "source directory already configured; run \"make distclean\" there first" "$LINENO" 5
+ fi
+fi
+
+# test whether we have cygpath
+if test -z "$CYGPATH_W"; then
+ if (cygpath --version) >/dev/null 2>/dev/null; then
+ CYGPATH_W='cygpath -w'
+ else
+ CYGPATH_W=echo
+ fi
+fi
+
+
+# Define the identity of the package.
+ PACKAGE='pdns'
+ VERSION='4.0.4'
+
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGE "$PACKAGE"
+_ACEOF
+
+
+cat >>confdefs.h <<_ACEOF
+#define VERSION "$VERSION"
+_ACEOF
+
+# Some tools Automake needs.
+
+ACLOCAL=${ACLOCAL-"${am_missing_run}aclocal-${am__api_version}"}
+
+
+AUTOCONF=${AUTOCONF-"${am_missing_run}autoconf"}
+
+
+AUTOMAKE=${AUTOMAKE-"${am_missing_run}automake-${am__api_version}"}
+
+
+AUTOHEADER=${AUTOHEADER-"${am_missing_run}autoheader"}
+
+
+MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
+
+# For better backward compatibility. To be removed once Automake 1.9.x
+# dies out for good. For more background, see:
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00001.html>
+# <http://lists.gnu.org/archive/html/automake/2012-07/msg00014.html>
+mkdir_p='$(MKDIR_P)'
+
+# We need awk for the "check" target. The system "awk" is bad on
+# some platforms.
+# Always define AMTAR for backward compatibility. Yes, it's still used
+# in the wild :-( We should find a proper way to deprecate it ...
+AMTAR='$${TAR-tar}'
+
+
+# We'll loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar plaintar pax cpio none'
+
+# The POSIX 1988 'ustar' format is defined with fixed-size fields.
+ # There is notably a 21 bits limit for the UID and the GID. In fact,
+ # the 'pax' utility can hang on bigger UID/GID (see automake bug#8343
+ # and bug#13588).
+ am_max_uid=2097151 # 2^21 - 1
+ am_max_gid=$am_max_uid
+ # The $UID and $GID variables are not portable, so we need to resort
+ # to the POSIX-mandated id(1) utility. Errors in the 'id' calls
+ # below are definitely unexpected, so allow the users to see them
+ # (that is, avoid stderr redirection).
+ am_uid=`id -u || echo unknown`
+ am_gid=`id -g || echo unknown`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether UID '$am_uid' is supported by ustar format" >&5
+$as_echo_n "checking whether UID '$am_uid' is supported by ustar format... " >&6; }
+ if test $am_uid -le $am_max_uid; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ _am_tools=none
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether GID '$am_gid' is supported by ustar format" >&5
+$as_echo_n "checking whether GID '$am_gid' is supported by ustar format... " >&6; }
+ if test $am_gid -le $am_max_gid; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ _am_tools=none
+ fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a ustar tar archive" >&5
+$as_echo_n "checking how to create a ustar tar archive... " >&6; }
+
+ # Go ahead even if we have the value already cached. We do so because we
+ # need to set the values for the 'am__tar' and 'am__untar' variables.
+ _am_tools=${am_cv_prog_tar_ustar-$_am_tools}
+
+ for _am_tool in $_am_tools; do
+ case $_am_tool in
+ gnutar)
+ for _am_tar in tar gnutar gtar; do
+ { echo "$as_me:$LINENO: $_am_tar --version" >&5
+ ($_am_tar --version) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } && break
+ done
+ am__tar="$_am_tar --format=ustar -chf - "'"$$tardir"'
+ am__tar_="$_am_tar --format=ustar -chf - "'"$tardir"'
+ am__untar="$_am_tar -xf -"
+ ;;
+ plaintar)
+ # Must skip GNU tar: if it does not support --format= it doesn't create
+ # ustar tarball either.
+ (tar --version) >/dev/null 2>&1 && continue
+ am__tar='tar chf - "$$tardir"'
+ am__tar_='tar chf - "$tardir"'
+ am__untar='tar xf -'
+ ;;
+ pax)
+ am__tar='pax -L -x ustar -w "$$tardir"'
+ am__tar_='pax -L -x ustar -w "$tardir"'
+ am__untar='pax -r'
+ ;;
+ cpio)
+ am__tar='find "$$tardir" -print | cpio -o -H ustar -L'
+ am__tar_='find "$tardir" -print | cpio -o -H ustar -L'
+ am__untar='cpio -i -H ustar -d'
+ ;;
+ none)
+ am__tar=false
+ am__tar_=false
+ am__untar=false
+ ;;
+ esac
+
+ # If the value was cached, stop now. We just wanted to have am__tar
+ # and am__untar set.
+ test -n "${am_cv_prog_tar_ustar}" && break
+
+ # tar/untar a dummy directory, and stop if the command works.
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ echo GrepMe > conftest.dir/file
+ { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5
+ (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ rm -rf conftest.dir
+ if test -s conftest.tar; then
+ { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5
+ ($am__untar <conftest.tar) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ { echo "$as_me:$LINENO: cat conftest.dir/file" >&5
+ (cat conftest.dir/file) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); }
+ grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+ fi
+ done
+ rm -rf conftest.dir
+
+ if ${am_cv_prog_tar_ustar+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ am_cv_prog_tar_ustar=$_am_tool
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_ustar" >&5
+$as_echo "$am_cv_prog_tar_ustar" >&6; }
+
+
+
+
+
+
+# POSIX will say in a future version that running "rm -f" with no argument
+# is OK; and we want to be able to make that assumption in our Makefile
+# recipes. So use an aggressive probe to check that the usage we want is
+# actually supported "in the wild" to an acceptable degree.
+# See automake bug#10828.
+# To make any issue more visible, cause the running configure to be aborted
+# by default if the 'rm' program in use doesn't match our expectations; the
+# user can still override this though.
+if rm -f && rm -fr && rm -rf; then : OK; else
+ cat >&2 <<'END'
+Oops!
+
+Your 'rm' program seems unable to run without file operands specified
+on the command line, even when the '-f' option is present. This is contrary
+to the behaviour of most rm programs out there, and not conforming with
+the upcoming POSIX standard: <http://austingroupbugs.net/view.php?id=542>
+
+Please tell bug-automake@gnu.org about your system, including the value
+of your $PATH and any error possibly output before this message. This
+can help us improve future automake versions.
+
+END
+ if test x"$ACCEPT_INFERIOR_RM_PROGRAM" = x"yes"; then
+ echo 'Configuration will proceed anyway, since you have set the' >&2
+ echo 'ACCEPT_INFERIOR_RM_PROGRAM variable to "yes"' >&2
+ echo >&2
+ else
+ cat >&2 <<'END'
+Aborting the configuration process, to ensure you take notice of the issue.
+
+You can download and install GNU coreutils to get an 'rm' implementation
+that behaves properly: <http://www.gnu.org/software/coreutils/>.
+
+If you want to complete the configuration process using your problematic
+'rm' anyway, export the environment variable ACCEPT_INFERIOR_RM_PROGRAM
+to "yes", and re-run configure.
+
+END
+ as_fn_error $? "Your 'rm' program is bad, sorry." "$LINENO" 5
+ fi
+fi
+
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+ enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in # (((
+ yes) AM_DEFAULT_VERBOSITY=0;;
+ no) AM_DEFAULT_VERBOSITY=1;;
+ *) AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+ @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+ am_cv_make_support_nested_variables=yes
+else
+ am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+ AM_V='$(V)'
+ AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+ AM_V=$AM_DEFAULT_VERBOSITY
+ AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+ as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+ ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+ as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "x$host_alias" = x; then
+ ac_cv_host=$ac_cv_build
+else
+ ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+ as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+: ${CFLAGS="-Wall -g -O2"}
+: ${CXXFLAGS="-Wall -g -O2"}
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_CC"; then
+ ac_ct_CC=$CC
+ # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="gcc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+else
+ CC="$ac_cv_prog_CC"
+fi
+
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="${ac_tool_prefix}cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ fi
+fi
+if test -z "$CC"; then
+ # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+ ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+ ac_prog_rejected=yes
+ continue
+ fi
+ ac_cv_prog_CC="cc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+ # We found a bogon in the path, so make sure we never use it.
+ set dummy $ac_cv_prog_CC
+ shift
+ if test $# != 0; then
+ # We chose a different compiler from the bogus one.
+ # However, it has the same basename, so the bogon will be chosen
+ # first if we set CC to just the basename; use the full file name.
+ shift
+ ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+ fi
+fi
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$CC"; then
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in cl.exe
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CC"; then
+ ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CC" && break
+ done
+fi
+if test -z "$CC"; then
+ ac_ct_CC=$CC
+ for ac_prog in cl.exe
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CC"; then
+ ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CC" && break
+done
+
+ if test "x$ac_ct_CC" = x; then
+ CC=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CC=$ac_ct_CC
+ fi
+fi
+
+fi
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files a.out a.out.dSYM a.exe b.out"
+# Try to create an executable without -o first, disregard a.out.
+# It will help us diagnose broken compilers, and finding out an intuition
+# of exeext.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler works" >&5
+$as_echo_n "checking whether the C compiler works... " >&6; }
+ac_link_default=`$as_echo "$ac_link" | sed 's/ -o *conftest[^ ]*//'`
+
+# The possible output files:
+ac_files="a.out conftest.exe conftest a.exe a_out.exe b.out conftest.*"
+
+ac_rmfiles=
+for ac_file in $ac_files
+do
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ * ) ac_rmfiles="$ac_rmfiles $ac_file";;
+ esac
+done
+rm -f $ac_rmfiles
+
+if { { ac_try="$ac_link_default"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link_default") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # Autoconf-2.13 could set the ac_cv_exeext variable to `no'.
+# So ignore a value of `no', otherwise this would lead to `EXEEXT = no'
+# in a Makefile. We should not override ac_cv_exeext if it was cached,
+# so that the user can short-circuit this test for compilers unknown to
+# Autoconf.
+for ac_file in $ac_files ''
+do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj )
+ ;;
+ [ab].out )
+ # We found the default executable, but exeext='' is most
+ # certainly right.
+ break;;
+ *.* )
+ if test "${ac_cv_exeext+set}" = set && test "$ac_cv_exeext" != no;
+ then :; else
+ ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ fi
+ # We set ac_cv_exeext here because the later test for it is not
+ # safe: cross compilers may not add the suffix if given an `-o'
+ # argument, so we may need to know it at that point already.
+ # Even if this section looks crufty: it has the advantage of
+ # actually working.
+ break;;
+ * )
+ break;;
+ esac
+done
+test "$ac_cv_exeext" = no && ac_cv_exeext=
+
+else
+ ac_file=''
+fi
+if test -z "$ac_file"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+$as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error 77 "C compiler cannot create executables
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler default output file name" >&5
+$as_echo_n "checking for C compiler default output file name... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_file" >&5
+$as_echo "$ac_file" >&6; }
+ac_exeext=$ac_cv_exeext
+
+rm -f -r a.out a.out.dSYM a.exe conftest$ac_cv_exeext b.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of executables" >&5
+$as_echo_n "checking for suffix of executables... " >&6; }
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ # If both `conftest.exe' and `conftest' are `present' (well, observable)
+# catch `conftest.exe'. For instance with Cygwin, `ls conftest' will
+# work properly (i.e., refer to `conftest.exe'), while it won't with
+# `rm'.
+for ac_file in conftest.exe conftest conftest.*; do
+ test -f "$ac_file" || continue
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM | *.o | *.obj ) ;;
+ *.* ) ac_cv_exeext=`expr "$ac_file" : '[^.]*\(\..*\)'`
+ break;;
+ * ) break;;
+ esac
+done
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of executables: cannot compile and link
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest conftest$ac_cv_exeext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_exeext" >&5
+$as_echo "$ac_cv_exeext" >&6; }
+
+rm -f conftest.$ac_ext
+EXEEXT=$ac_cv_exeext
+ac_exeext=$EXEEXT
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+FILE *f = fopen ("conftest.out", "w");
+ return ferror (f) || fclose (f) != 0;
+
+ ;
+ return 0;
+}
+_ACEOF
+ac_clean_files="$ac_clean_files conftest.out"
+# Check that the compiler produces executables we can run. If not, either
+# the compiler is broken, or we cross compile.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are cross compiling" >&5
+$as_echo_n "checking whether we are cross compiling... " >&6; }
+if test "$cross_compiling" != yes; then
+ { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if { ac_try='./conftest$ac_cv_exeext'
+ { { case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_try") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; }; then
+ cross_compiling=no
+ else
+ if test "$cross_compiling" = maybe; then
+ cross_compiling=yes
+ else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot run C compiled programs.
+If you meant to cross compile, use \`--host'.
+See \`config.log' for more details" "$LINENO" 5; }
+ fi
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $cross_compiling" >&5
+$as_echo "$cross_compiling" >&6; }
+
+rm -f conftest.$ac_ext conftest$ac_cv_exeext conftest.out
+ac_clean_files=$ac_clean_files_save
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for suffix of object files" >&5
+$as_echo_n "checking for suffix of object files... " >&6; }
+if ${ac_cv_objext+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+rm -f conftest.o conftest.obj
+if { { ac_try="$ac_compile"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compile") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then :
+ for ac_file in conftest.o conftest.obj conftest.*; do
+ test -f "$ac_file" || continue;
+ case $ac_file in
+ *.$ac_ext | *.xcoff | *.tds | *.d | *.pdb | *.xSYM | *.bb | *.bbg | *.map | *.inf | *.dSYM ) ;;
+ *) ac_cv_objext=`expr "$ac_file" : '.*\.\(.*\)'`
+ break;;
+ esac
+done
+else
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+{ { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "cannot compute suffix of object files: cannot compile
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+rm -f conftest.$ac_cv_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_objext" >&5
+$as_echo "$ac_cv_objext" >&6; }
+OBJEXT=$ac_cv_objext
+ac_objext=$OBJEXT
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GCC=yes
+else
+ GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_c_werror_flag=$ac_c_werror_flag
+ ac_c_werror_flag=yes
+ ac_cv_prog_cc_g=no
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+else
+ CFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+ ac_c_werror_flag=$ac_save_c_werror_flag
+ CFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+ CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+ if test "$GCC" = yes; then
+ CFLAGS="-g -O2"
+ else
+ CFLAGS="-g"
+ fi
+else
+ if test "$GCC" = yes; then
+ CFLAGS="-O2"
+ else
+ CFLAGS=
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh. */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+ char **p;
+ int i;
+{
+ return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+ char *s;
+ va_list v;
+ va_start (v,p);
+ s = g (p, va_arg (v,int));
+ va_end (v);
+ return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default. It has
+ function prototypes and stuff, but not '\xHH' hex character constants.
+ These don't provoke an error unfortunately, instead are silently treated
+ as 'x'. The following induces an error, until -std is added to get
+ proper ANSI mode. Curiously '\x00'!='x' always comes out true, for an
+ array size at least. It's necessary to write '\x00'==0 to get something
+ that's true only with -std. */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+ inside strings and character constants. */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0] || f (e, argv, 1) != argv[1];
+ ;
+ return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+ -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+ CC="$ac_save_CC $ac_arg"
+ if ac_fn_c_try_compile "$LINENO"; then :
+ ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+ test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+ x)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+ xno)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+ *)
+ CC="$CC $ac_cv_prog_cc_c89"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -c and -o together" >&5
+$as_echo_n "checking whether $CC understands -c and -o together... " >&6; }
+if ${am_cv_prog_cc_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # Make sure it works both with $CC and with simple cc.
+ # Following AC_PROG_CC_C_O, we do the test twice because some
+ # compilers refuse to overwrite an existing .o file with -o,
+ # though they will create one.
+ am_cv_prog_cc_c_o=yes
+ for am_i in 1 2; do
+ if { echo "$as_me:$LINENO: $CC -c conftest.$ac_ext -o conftest2.$ac_objext" >&5
+ ($CC -c conftest.$ac_ext -o conftest2.$ac_objext) >&5 2>&5
+ ac_status=$?
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ (exit $ac_status); } \
+ && test -f conftest2.$ac_objext; then
+ : OK
+ else
+ am_cv_prog_cc_c_o=no
+ break
+ fi
+ done
+ rm -f core conftest*
+ unset am_i
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_cc_c_o" >&5
+$as_echo "$am_cv_prog_cc_c_o" >&6; }
+if test "$am_cv_prog_cc_c_o" != yes; then
+ # Losing compiler, so override with the script.
+ # FIXME: It is wrong to rewrite CC.
+ # But if we don't then we get into trouble of one sort or another.
+ # A longer-term fix would be to have automake use am__CC in this case,
+ # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+ CC="$am_aux_dir/compile $CC"
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
+
+
+am_make=${MAKE-make}
+cat > confinc << 'END'
+am__doit:
+ @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from 'make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+ am__include=include
+ am__quote=
+ _am_result=GNU
+ ;;
+esac
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+ echo '.include "confinc"' > confmf
+ case `$am_make -s -f confmf 2> /dev/null` in #(
+ *the\ am__doit\ target*)
+ am__include=.include
+ am__quote="\""
+ _am_result=BSD
+ ;;
+ esac
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
+
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+ enableval=$enable_dependency_tracking;
+fi
+
+if test "x$enable_dependency_tracking" != xno; then
+ am_depcomp="$ac_aux_dir/depcomp"
+ AMDEPBACKSLASH='\'
+ am__nodep='_no'
+fi
+ if test "x$enable_dependency_tracking" != xno; then
+ AMDEP_TRUE=
+ AMDEP_FALSE='#'
+else
+ AMDEP_TRUE='#'
+ AMDEP_FALSE=
+fi
+
+
+
+depcc="$CC" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CC_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CC_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+ am__fastdepCC_TRUE=
+ am__fastdepCC_FALSE='#'
+else
+ am__fastdepCC_TRUE='#'
+ am__fastdepCC_FALSE=
+fi
+
+
+
+for ac_prog in 'bison -y' byacc
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_YACC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$YACC"; then
+ ac_cv_prog_YACC="$YACC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_YACC="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+YACC=$ac_cv_prog_YACC
+if test -n "$YACC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
+$as_echo "$YACC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$YACC" && break
+done
+test -n "$YACC" || YACC="yacc"
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$GREP"; then
+ ac_path_GREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in grep ggrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+ # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'GREP' >> "conftest.nl"
+ "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_GREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_GREP="$ac_path_GREP"
+ ac_path_GREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_GREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_GREP"; then
+ as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_GREP=$GREP
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+ then ac_cv_path_EGREP="$GREP -E"
+ else
+ if test -z "$EGREP"; then
+ ac_path_EGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in egrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+ # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'EGREP' >> "conftest.nl"
+ "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_EGREP="$ac_path_EGREP"
+ ac_path_EGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_EGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_EGREP"; then
+ as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_EGREP=$EGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if bison is the parser generator" >&5
+$as_echo_n "checking if bison is the parser generator... " >&6; }
+if ${pdns_cv_prog_bison+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if $YACC --version 2>/dev/null | $EGREP -q '^bison '; then :
+ pdns_cv_prog_bison=yes
+else
+ pdns_cv_prog_bison=no
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pdns_cv_prog_bison" >&5
+$as_echo "$pdns_cv_prog_bison" >&6; }
+
+ if test "x$pdns_cv_prog_bison" = "xno"; then :
+
+ if test ! -f "${srcdir}/pdns/bindparser.cc"; then :
+ as_fn_error $? "bison is missing and you don't have ${srcdir}/pdns/bindparser.cc. Please install bison" "$LINENO" 5
+
+fi
+
+fi
+
+
+for ac_prog in flex lex
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LEX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LEX"; then
+ ac_cv_prog_LEX="$LEX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LEX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LEX=$ac_cv_prog_LEX
+if test -n "$LEX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
+$as_echo "$LEX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$LEX" && break
+done
+test -n "$LEX" || LEX=":"
+
+if test "x$LEX" != "x:"; then
+ cat >conftest.l <<_ACEOF
+%%
+a { ECHO; }
+b { REJECT; }
+c { yymore (); }
+d { yyless (1); }
+e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument. */
+ yyless ((input () != 0)); }
+f { unput (yytext[0]); }
+. { BEGIN INITIAL; }
+%%
+#ifdef YYTEXT_POINTER
+extern char *yytext;
+#endif
+int
+main (void)
+{
+ return ! yylex () + ! yywrap ();
+}
+_ACEOF
+{ { ac_try="$LEX conftest.l"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$LEX conftest.l") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
+$as_echo_n "checking lex output file root... " >&6; }
+if ${ac_cv_prog_lex_root+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+if test -f lex.yy.c; then
+ ac_cv_prog_lex_root=lex.yy
+elif test -f lexyy.c; then
+ ac_cv_prog_lex_root=lexyy
+else
+ as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
+$as_echo "$ac_cv_prog_lex_root" >&6; }
+LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+
+if test -z "${LEXLIB+set}"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
+$as_echo_n "checking lex library... " >&6; }
+if ${ac_cv_lib_lex+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ac_save_LIBS=$LIBS
+ ac_cv_lib_lex='none needed'
+ for ac_lib in '' -lfl -ll; do
+ LIBS="$ac_lib $ac_save_LIBS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_lex=$ac_lib
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ test "$ac_cv_lib_lex" != 'none needed' && break
+ done
+ LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
+$as_echo "$ac_cv_lib_lex" >&6; }
+ test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
+$as_echo_n "checking whether yytext is a pointer... " >&6; }
+if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # POSIX says lex can declare yytext either as a pointer or an array; the
+# default is implementation-dependent. Figure out which it is, since
+# not all implementations provide the %pointer and %array declarations.
+ac_cv_prog_lex_yytext_pointer=no
+ac_save_LIBS=$LIBS
+LIBS="$LEXLIB $ac_save_LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ #define YYTEXT_POINTER 1
+`cat $LEX_OUTPUT_ROOT.c`
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_prog_lex_yytext_pointer=yes
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_save_LIBS
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
+$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
+if test $ac_cv_prog_lex_yytext_pointer = yes; then
+
+$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+
+fi
+rm -f conftest.l $LEX_OUTPUT_ROOT.c
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if the lexer is flex" >&5
+$as_echo_n "checking if the lexer is flex... " >&6; }
+if ${pdns_cv_prog_flex+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ if $LEX --version 2>/dev/null | $EGREP -q '^flex '; then :
+ pdns_cv_prog_flex=yes
+else
+ pdns_cv_prog_flex=no
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $pdns_cv_prog_flex" >&5
+$as_echo "$pdns_cv_prog_flex" >&6; }
+
+ if test "x$pdns_cv_prog_flex" = "xno"; then :
+
+ if test ! -f "${srcdir}/pdns/bindlexer.c"; then :
+ as_fn_error $? "flex is missing and you don't have ${srcdir}/pdns/bindlexer.c. Please install flex" "$LINENO" 5
+
+fi
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${MAKE-make} sets \$(MAKE)" >&5
+$as_echo_n "checking whether ${MAKE-make} sets \$(MAKE)... " >&6; }
+set x ${MAKE-make}
+ac_make=`$as_echo "$2" | sed 's/+/p/g; s/[^a-zA-Z0-9_]/_/g'`
+if eval \${ac_cv_prog_make_${ac_make}_set+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat >conftest.make <<\_ACEOF
+SHELL = /bin/sh
+all:
+ @echo '@@@%%%=$(MAKE)=@@@%%%'
+_ACEOF
+# GNU make sometimes prints "make[1]: Entering ...", which would confuse us.
+case `${MAKE-make} -f conftest.make 2>/dev/null` in
+ *@@@%%%=?*=@@@%%%*)
+ eval ac_cv_prog_make_${ac_make}_set=yes;;
+ *)
+ eval ac_cv_prog_make_${ac_make}_set=no;;
+esac
+rm -f conftest.make
+fi
+if eval test \$ac_cv_prog_make_${ac_make}_set = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ SET_MAKE=
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ SET_MAKE="MAKE=${MAKE-make}"
+fi
+
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test -z "$CXX"; then
+ if test -n "$CCC"; then
+ CXX=$CCC
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CXX"; then
+ ac_cv_prog_CXX="$CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CXX="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+CXX=$ac_cv_prog_CXX
+if test -n "$CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXX" >&5
+$as_echo "$CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$CXX" && break
+ done
+fi
+if test -z "$CXX"; then
+ ac_ct_CXX=$CXX
+ for ac_prog in g++ c++ gpp aCC CC cxx cc++ cl.exe FCC KCC RCC xlC_r xlC
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_CXX"; then
+ ac_cv_prog_ac_ct_CXX="$ac_ct_CXX" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_CXX="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_CXX=$ac_cv_prog_ac_ct_CXX
+if test -n "$ac_ct_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CXX" >&5
+$as_echo "$ac_ct_CXX" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_CXX" && break
+done
+
+ if test "x$ac_ct_CXX" = x; then
+ CXX="g++"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ CXX=$ac_ct_CXX
+ fi
+fi
+
+ fi
+fi
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C++ compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+ { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ sed '10a\
+... rest of stderr output deleted ...
+ 10q' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ fi
+ rm -f conftest.er1 conftest.err
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C++ compiler" >&5
+$as_echo_n "checking whether we are using the GNU C++ compiler... " >&6; }
+if ${ac_cv_cxx_compiler_gnu+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+#ifndef __GNUC__
+ choke me
+#endif
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_compiler_gnu=yes
+else
+ ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_cxx_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_cxx_compiler_gnu" >&5
+$as_echo "$ac_cv_cxx_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+ GXX=yes
+else
+ GXX=
+fi
+ac_test_CXXFLAGS=${CXXFLAGS+set}
+ac_save_CXXFLAGS=$CXXFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX accepts -g" >&5
+$as_echo_n "checking whether $CXX accepts -g... " >&6; }
+if ${ac_cv_prog_cxx_g+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_cxx_werror_flag=$ac_cxx_werror_flag
+ ac_cxx_werror_flag=yes
+ ac_cv_prog_cxx_g=no
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+else
+ CXXFLAGS=""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+
+else
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+ CXXFLAGS="-g"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_prog_cxx_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ ac_cxx_werror_flag=$ac_save_cxx_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cxx_g" >&5
+$as_echo "$ac_cv_prog_cxx_g" >&6; }
+if test "$ac_test_CXXFLAGS" = set; then
+ CXXFLAGS=$ac_save_CXXFLAGS
+elif test $ac_cv_prog_cxx_g = yes; then
+ if test "$GXX" = yes; then
+ CXXFLAGS="-g -O2"
+ else
+ CXXFLAGS="-g"
+ fi
+else
+ if test "$GXX" = yes; then
+ CXXFLAGS="-O2"
+ else
+ CXXFLAGS=
+ fi
+fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CXX" am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CXX_dependencies_compiler_type+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+ # We make a subdir and do the tests there. Otherwise we can end up
+ # making bogus files that we don't know about and never remove. For
+ # instance it was reported that on HP-UX the gcc test will end up
+ # making a dummy file named 'D' -- because '-MD' means "put the output
+ # in D".
+ rm -rf conftest.dir
+ mkdir conftest.dir
+ # Copy depcomp to subdir because otherwise we won't find it if we're
+ # using a relative directory.
+ cp "$am_depcomp" conftest.dir
+ cd conftest.dir
+ # We will build objects and dependencies in a subdirectory because
+ # it helps to detect inapplicable dependency modes. For instance
+ # both Tru64's cc and ICC support -MD to output dependencies as a
+ # side effect of compilation, but ICC will put the dependencies in
+ # the current directory while Tru64 will put them in the object
+ # directory.
+ mkdir sub
+
+ am_cv_CXX_dependencies_compiler_type=none
+ if test "$am_compiler_list" = ""; then
+ am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+ fi
+ am__universal=false
+ case " $depcc " in #(
+ *\ -arch\ *\ -arch\ *) am__universal=true ;;
+ esac
+
+ for depmode in $am_compiler_list; do
+ # Setup a source with many dependencies, because some compilers
+ # like to wrap large dependency lists on column 80 (with \), and
+ # we should not choose a depcomp mode which is confused by this.
+ #
+ # We need to recreate these files for each test, as the compiler may
+ # overwrite some of them when testing with obscure command lines.
+ # This happens at least with the AIX C compiler.
+ : > sub/conftest.c
+ for i in 1 2 3 4 5 6; do
+ echo '#include "conftst'$i'.h"' >> sub/conftest.c
+ # Using ": > sub/conftst$i.h" creates only sub/conftst1.h with
+ # Solaris 10 /bin/sh.
+ echo '/* dummy */' > sub/conftst$i.h
+ done
+ echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+ # We check with '-c' and '-o' for the sake of the "dashmstdout"
+ # mode. It turns out that the SunPro C++ compiler does not properly
+ # handle '-M -o', and we need to detect this. Also, some Intel
+ # versions had trouble with output in subdirs.
+ am__obj=sub/conftest.${OBJEXT-o}
+ am__minus_obj="-o $am__obj"
+ case $depmode in
+ gcc)
+ # This depmode causes a compiler race in universal mode.
+ test "$am__universal" = false || continue
+ ;;
+ nosideeffect)
+ # After this tag, mechanisms are not by side-effect, so they'll
+ # only be used when explicitly requested.
+ if test "x$enable_dependency_tracking" = xyes; then
+ continue
+ else
+ break
+ fi
+ ;;
+ msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+ # This compiler won't grok '-c -o', but also, the minuso test has
+ # not run yet. These depmodes are late enough in the game, and
+ # so weak that their functioning should not be impacted.
+ am__obj=conftest.${OBJEXT-o}
+ am__minus_obj=
+ ;;
+ none) break ;;
+ esac
+ if depmode=$depmode \
+ source=sub/conftest.c object=$am__obj \
+ depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+ $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+ >/dev/null 2>conftest.err &&
+ grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+ grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+ ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+ # icc doesn't choke on unknown options, it will just issue warnings
+ # or remarks (even with -Werror). So we grep stderr for any message
+ # that says an option was ignored or not supported.
+ # When given -MP, icc 7.0 and 7.1 complain thusly:
+ # icc: Command line warning: ignoring option '-M'; no argument required
+ # The diagnosis changed in icc 8.0:
+ # icc: Command line remark: option '-MP' not supported
+ if (grep 'ignoring option' conftest.err ||
+ grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+ am_cv_CXX_dependencies_compiler_type=$depmode
+ break
+ fi
+ fi
+ done
+
+ cd ..
+ rm -rf conftest.dir
+else
+ am_cv_CXX_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CXX_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CXX_dependencies_compiler_type" >&6; }
+CXXDEPMODE=depmode=$am_cv_CXX_dependencies_compiler_type
+
+ if
+ test "x$enable_dependency_tracking" != xno \
+ && test "$am_cv_CXX_dependencies_compiler_type" = gcc3; then
+ am__fastdepCXX_TRUE=
+ am__fastdepCXX_FALSE='#'
+else
+ am__fastdepCXX_TRUE='#'
+ am__fastdepCXX_FALSE=
+fi
+
+
+if test "x$CXX" = "xno" || test "x$CXX:x$GXX" = "xg++:x"; then :
+ as_fn_error $? "no C++ compiler found" "$LINENO" 5
+
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+$as_echo "#define _GNU_SOURCE 1" >>confdefs.h
+
+
+# Warn when pkg.m4 is missing
+
+
+
+
+ THREADFLAGS=""
+
+ case "$host_os" in
+ solaris2.1*)
+ LIBS="-lposix4 -lpthread $LIBS"
+ CXXFLAGS="-D_REENTRANT $CXXFLAGS"
+ have_solaris="yes"
+ ;;
+ solaris2.8 | solaris2.9 )
+
+$as_echo "#define NEED_POSIX_TYPEDEF /**/" >>confdefs.h
+
+
+$as_echo "#define NEED_INET_NTOP_PROTO /**/" >>confdefs.h
+
+ LIBS="-lposix4 -lpthread $LIBS"
+ CXXFLAGS="-D_REENTRANT $CXXFLAGS"
+ have_solaris="yes"
+ ;;
+ linux*)
+ THREADFLAGS="-pthread"
+ have_linux="yes"
+ ;;
+ darwin*)
+ CXXFLAGS="-D__APPLE_USE_RFC_3542 -D_XOPEN_SOURCE $CXXFLAGS"
+ ;;
+ freebsd*)
+ THREADFLAGS="-pthread"
+ have_freebsd="yes"
+ ;;
+ *)
+ LDFLAGS="-pthread $LDFLAGS"
+ CXXFLAGS="-pthread $CXXFLAGS"
+ ;;
+ esac
+
+ if test "x$have_freebsd" = "xyes"; then
+ HAVE_FREEBSD_TRUE=
+ HAVE_FREEBSD_FALSE='#'
+else
+ HAVE_FREEBSD_TRUE='#'
+ HAVE_FREEBSD_FALSE=
+fi
+
+ if test "x$have_linux" = "xyes"; then
+ HAVE_LINUX_TRUE=
+ HAVE_LINUX_FALSE='#'
+else
+ HAVE_LINUX_TRUE='#'
+ HAVE_LINUX_FALSE=
+fi
+
+ if test "x$have_solaris" = "xyes"; then
+ HAVE_SOLARIS_TRUE=
+ HAVE_SOLARIS_FALSE='#'
+else
+ HAVE_SOLARIS_TRUE='#'
+ HAVE_SOLARIS_FALSE=
+fi
+
+
+ case "$host" in
+ mips* | powerpc* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the linker accepts -latomic" >&5
+$as_echo_n "checking whether the linker accepts -latomic... " >&6; }
+if ${ax_cv_check_ldflags___latomic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS -latomic"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ax_cv_check_ldflags___latomic=yes
+else
+ ax_cv_check_ldflags___latomic=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$ax_check_save_flags
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_check_ldflags___latomic" >&5
+$as_echo "$ax_cv_check_ldflags___latomic" >&6; }
+if test "x$ax_cv_check_ldflags___latomic" = xyes; then :
+ :
+else
+ as_fn_error $? "Unable to link against libatomic, cannot continue" "$LINENO" 5
+
+fi
+
+ LDFLAGS="-latomic $LDFLAGS"
+ ;;
+ esac
+
+
+ DYNLINKFLAGS=-export-dynamic
+
+
+
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in LuaJIT" >&5
+$as_echo_n "checking whether we will be linking in LuaJIT... " >&6; }
+
+# Check whether --with-luajit was given.
+if test "${with_luajit+set}" = set; then :
+ withval=$with_luajit; with_luajit=$withval
+else
+ with_luajit=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_luajit" >&5
+$as_echo "$with_luajit" >&6; }
+
+ if test "x$with_luajit" = "xyes"; then :
+
+ LUAJITPC="$with_luajit"
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
+$as_echo_n "checking for LUA... " >&6; }
+
+if test -n "$LUA_CFLAGS"; then
+ pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "luajit") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "luajit" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LUA_LIBS"; then
+ pkg_cv_LUA_LIBS="$LUA_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"luajit\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "luajit") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "luajit" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "luajit" 2>&1`
+ else
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "luajit" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
+
+ LUAJITPC=""
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ LUAJITPC=""
+
+else
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_LUA 1" >>confdefs.h
+
+fi
+ if test "x$LUAJITPC" = "x"; then :
+
+ as_fn_error $? "LuaJIT not found" "$LINENO" 5
+
+fi
+
+fi
+
+ if test "x$with_luajit" = "xyes"; then
+ LUA_TRUE=
+ LUA_FALSE='#'
+else
+ LUA_TRUE='#'
+ LUA_FALSE=
+fi
+
+
+if test "x$with_luajit" = "xno"; then :
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in Lua" >&5
+$as_echo_n "checking whether we will be linking in Lua... " >&6; }
+
+# Check whether --with-lua was given.
+if test "${with_lua+set}" = set; then :
+ withval=$with_lua; with_lua=$withval
+else
+ with_lua=auto
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_lua" >&5
+$as_echo "$with_lua" >&6; }
+
+ if test "x$with_lua" != "xno"; then :
+
+ if test "x$with_lua" = "xyes" -o "x$with_lua" = "xauto"; then :
+ for LUAPC in lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua; do
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
+$as_echo_n "checking for LUA... " >&6; }
+
+if test -n "$LUA_CFLAGS"; then
+ pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$LUAPC >= 5.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LUA_LIBS"; then
+ pkg_cv_LUA_LIBS="$LUA_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$LUAPC >= 5.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1`
+ else
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
+
+ LUAPC=""
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ LUAPC=""
+else
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_LUA 1" >>confdefs.h
+
+ with_lua=yes
+
+fi # otherwise pkg_check will fail
+ if test "x$LUA_LIBS" != "x"; then break; fi
+ done
+
+else
+ LUAPC="$with_lua"
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LUA" >&5
+$as_echo_n "checking for LUA... " >&6; }
+
+if test -n "$LUA_CFLAGS"; then
+ pkg_cv_LUA_CFLAGS="$LUA_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_CFLAGS=`$PKG_CONFIG --cflags "$LUAPC >= 5.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LUA_LIBS"; then
+ pkg_cv_LUA_LIBS="$LUA_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$LUAPC >= 5.1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$LUAPC >= 5.1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LUA_LIBS=`$PKG_CONFIG --libs "$LUAPC >= 5.1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LUA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1`
+ else
+ LUA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$LUAPC >= 5.1" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LUA_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements ($LUAPC >= 5.1) were not met:
+
+$LUA_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables LUA_CFLAGS
+and LUA_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables LUA_CFLAGS
+and LUA_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ LUA_CFLAGS=$pkg_cv_LUA_CFLAGS
+ LUA_LIBS=$pkg_cv_LUA_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_LUA 1" >>confdefs.h
+
+ with_lua=yes
+
+fi
+
+fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for chosen LUA" >&5
+$as_echo_n "checking for chosen LUA... " >&6; }
+ if test "x$LUAPC" = "x"; then :
+
+ if test "x$with_lua" = "xyes"; then :
+ as_fn_error $? "cannot find lua" "$LINENO" 5
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: not found" >&5
+$as_echo "not found" >&6; }
+
+fi
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LUAPC" >&5
+$as_echo "$LUAPC" >&6; }
+
+fi
+
+fi
+ if test "x$with_lua" = "xyes"; then
+ LUA_TRUE=
+ LUA_FALSE='#'
+else
+ LUA_TRUE='#'
+ LUA_FALSE=
+fi
+
+
+
+fi
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+ if ${ac_cv_prog_CXXCPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_header_stdc=yes
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+if test $ac_cv_header_stdc = yes; then
+ # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <string.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "memchr" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdlib.h>
+
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ $EGREP "free" >/dev/null 2>&1; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f conftest*
+
+fi
+
+if test $ac_cv_header_stdc = yes; then
+ # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+ if test "$cross_compiling" = yes; then :
+ :
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+ (('a' <= (c) && (c) <= 'i') \
+ || ('j' <= (c) && (c) <= 'r') \
+ || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ if (XOR (islower (i), ISLOWER (i))
+ || toupper (i) != TOUPPER (i))
+ return 2;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_run "$LINENO"; then :
+
+else
+ ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+ conftest.$ac_objext conftest.beam conftest.$ac_ext
+fi
+
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
+
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
+
+fi
+
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+ inttypes.h stdint.h unistd.h
+do :
+ as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_cxx_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+
+done
+
+
+
+
+
+ if test "x$LUAPC" != "x" -o "x$LUAJITPC" != "x" ; then :
+
+ ac_fn_cxx_check_header_mongrel "$LINENO" "lua.hpp" "ac_cv_header_lua_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_lua_hpp" = xyes; then :
+ have_lua_hpp=y
+fi
+
+
+
+fi
+ if test x"$have_lua_hpp" = "xy" ; then
+ HAVE_LUA_HPP_TRUE=
+ HAVE_LUA_HPP_FALSE='#'
+else
+ HAVE_LUA_HPP_TRUE='#'
+ HAVE_LUA_HPP_FALSE=
+fi
+
+
+
+ ax_cxx_compile_cxx11_required=true
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+ ac_success=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features by default" >&5
+$as_echo_n "checking whether $CXX supports C++11 features by default... " >&6; }
+if ${ax_cv_cxx_compile_cxx11+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ struct Base {
+ virtual void f() {}
+ };
+ struct Child : public Base {
+ virtual void f() override {}
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+
+ auto d = a;
+ auto l = [](){};
+ // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
+ struct use_l { use_l() { l(); } };
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
+ namespace test_template_alias_sfinae {
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() {
+ func<foo>(0);
+ }
+ }
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ax_cv_cxx_compile_cxx11=yes
+else
+ ax_cv_cxx_compile_cxx11=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ax_cv_cxx_compile_cxx11" >&5
+$as_echo "$ax_cv_cxx_compile_cxx11" >&6; }
+ if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+ ac_success=yes
+ fi
+
+ if test x$ac_success = xno; then
+ for switch in -std=gnu++11 -std=gnu++0x; do
+ cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ struct Base {
+ virtual void f() {}
+ };
+ struct Child : public Base {
+ virtual void f() override {}
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+
+ auto d = a;
+ auto l = [](){};
+ // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
+ struct use_l { use_l() { l(); } };
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
+ namespace test_template_alias_sfinae {
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() {
+ func<foo>(0);
+ }
+ }
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval $cachevar=yes
+else
+ eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CXXFLAGS="$ac_save_CXXFLAGS"
+fi
+eval ac_res=\$$cachevar
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi
+
+ if test x$ac_success = xno; then
+ for switch in -std=c++11 -std=c++0x; do
+ cachevar=`$as_echo "ax_cv_cxx_compile_cxx11_$switch" | $as_tr_sh`
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CXX supports C++11 features with $switch" >&5
+$as_echo_n "checking whether $CXX supports C++11 features with $switch... " >&6; }
+if eval \${$cachevar+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ struct Base {
+ virtual void f() {}
+ };
+ struct Child : public Base {
+ virtual void f() override {}
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+
+ auto d = a;
+ auto l = [](){};
+ // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
+ struct use_l { use_l() { l(); } };
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
+ namespace test_template_alias_sfinae {
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() {
+ func<foo>(0);
+ }
+ }
+
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ eval $cachevar=yes
+else
+ eval $cachevar=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ CXXFLAGS="$ac_save_CXXFLAGS"
+fi
+eval ac_res=\$$cachevar
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+ if test x$ax_cxx_compile_cxx11_required = xtrue; then
+ if test x$ac_success = xno; then
+ as_fn_error $? "*** A compiler with support for C++11 language features is required." "$LINENO" 5
+ fi
+ else
+ if test x$ac_success = xno; then
+ HAVE_CXX11=0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: No compiler with C++11 support was found" >&5
+$as_echo "$as_me: No compiler with C++11 support was found" >&6;}
+ else
+ HAVE_CXX11=1
+
+$as_echo "#define HAVE_CXX11 1" >>confdefs.h
+
+ fi
+
+
+ fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will enable compiler security checks" >&5
+$as_echo_n "checking whether we will enable compiler security checks... " >&6; }
+# Check whether --enable-hardening was given.
+if test "${enable_hardening+set}" = set; then :
+ enableval=$enable_hardening; enable_hardening=$enableval
+else
+ enable_hardening=yes
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_hardening" >&5
+$as_echo "$enable_hardening" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Werror -Wunknown-warning-option" >&5
+$as_echo_n "checking whether C++ compiler handles -Werror -Wunknown-warning-option... " >&6; }
+if ${gl_cv_warn_cxx__Werror__Wunknown_warning_option+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Werror -Wunknown-warning-option"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__Werror__Wunknown_warning_option=yes
+else
+ gl_cv_warn_cxx__Werror__Wunknown_warning_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&5
+$as_echo "$gl_cv_warn_cxx__Werror__Wunknown_warning_option" >&6; }
+if test "x$gl_cv_warn_cxx__Werror__Wunknown_warning_option" = xyes; then :
+ gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror'
+else
+ gl_unknown_warnings_are_errors=
+fi
+
+if test "x$enable_hardening" != "xno"; then :
+
+
+
+ PIE_CFLAGS=
+ PIE_LDFLAGS=
+ OLD_CXXFLAGS=$CXXFLAGS
+ case "$host" in
+ *-*-mingw* | *-*-msvc* | *-*-cygwin* )
+ ;; *)
+ CXXFLAGS="-fPIE -DPIE"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -pie" >&5
+$as_echo_n "checking whether C++ compiler handles -pie... " >&6; }
+if ${gl_cv_warn_cxx__pie+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -pie"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <pthread.h>
+__thread unsigned int t_id;
+
+int
+main ()
+{
+t_id = 1;
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__pie=yes
+else
+ gl_cv_warn_cxx__pie=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__pie" >&5
+$as_echo "$gl_cv_warn_cxx__pie" >&6; }
+if test "x$gl_cv_warn_cxx__pie" = xyes; then :
+
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-pie"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -Wl,-pie" >&5
+$as_echo_n "checking whether C++ compiler handles -Wl,-pie... " >&6; }
+if ${gl_cv_warn_cxx__Wl__pie+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -Wl,-pie"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#include <pthread.h>
+__thread unsigned int t_id;
+
+int
+main ()
+{
+t_id = 1;
+ ;
+ return 0;
+}
+
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__Wl__pie=yes
+else
+ gl_cv_warn_cxx__Wl__pie=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__Wl__pie" >&5
+$as_echo "$gl_cv_warn_cxx__Wl__pie" >&6; }
+if test "x$gl_cv_warn_cxx__Wl__pie" = xyes; then :
+
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-Wl,-pie"
+
+fi
+
+
+fi
+
+ esac
+ CXXFLAGS=$OLD_CXXFLAGS
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fstack-protector" >&5
+$as_echo_n "checking whether C++ compiler handles -fstack-protector... " >&6; }
+if ${gl_cv_warn_cxx__fstack_protector+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fstack-protector"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fstack_protector=yes
+else
+ gl_cv_warn_cxx__fstack_protector=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fstack_protector" >&5
+$as_echo "$gl_cv_warn_cxx__fstack_protector" >&6; }
+if test "x$gl_cv_warn_cxx__fstack_protector" = xyes; then :
+
+ CFLAGS="-fstack-protector $CFLAGS"
+ CXXFLAGS="-fstack-protector $CXXFLAGS"
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles --param ssp-buffer-size=4" >&5
+$as_echo_n "checking whether C++ compiler handles --param ssp-buffer-size=4... " >&6; }
+if ${gl_cv_warn_cxx___param_ssp_buffer_size_4+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors --param ssp-buffer-size=4"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx___param_ssp_buffer_size_4=yes
+else
+ gl_cv_warn_cxx___param_ssp_buffer_size_4=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx___param_ssp_buffer_size_4" >&5
+$as_echo "$gl_cv_warn_cxx___param_ssp_buffer_size_4" >&6; }
+if test "x$gl_cv_warn_cxx___param_ssp_buffer_size_4" = xyes; then :
+
+ CFLAGS="--param ssp-buffer-size=4 $CFLAGS"
+ CXXFLAGS="--param ssp-buffer-size=4 $CXXFLAGS"
+
+fi
+
+
+
+ OLD_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="-Wall -W -Werror $CXXFLAGS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -D_FORTIFY_SOURCE=2" >&5
+$as_echo_n "checking whether C++ compiler handles -D_FORTIFY_SOURCE=2... " >&6; }
+if ${gl_cv_warn_cxx__D_FORTIFY_SOURCE_2+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -D_FORTIFY_SOURCE=2"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <stdio.h>
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=yes
+else
+ gl_cv_warn_cxx__D_FORTIFY_SOURCE_2=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&5
+$as_echo "$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" >&6; }
+if test "x$gl_cv_warn_cxx__D_FORTIFY_SOURCE_2" = xyes; then :
+
+ CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
+ CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $OLD_CXXFLAGS"
+
+else
+ CXXFLAGS="$OLD_CXXFLAGS"
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for how to force completely read-only GOT table" >&5
+$as_echo_n "checking for how to force completely read-only GOT table... " >&6; }
+
+ RELRO_LDFLAGS=
+ ld_help=`$CXX -Wl,-help 2>&1`
+ case $ld_help in
+ *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;;
+ esac
+ case $ld_help in
+ *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;;
+ esac
+
+ if test "x$RELRO_LDFLAGS" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RELRO_LDFLAGS" >&5
+$as_echo "$RELRO_LDFLAGS" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: unknown" >&5
+$as_echo "unknown" >&6; }
+
+fi
+
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing inet_aton" >&5
+$as_echo_n "checking for library containing inet_aton... " >&6; }
+if ${ac_cv_search_inet_aton+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char inet_aton ();
+int
+main ()
+{
+return inet_aton ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' resolv; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_inet_aton=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_inet_aton+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_inet_aton+:} false; then :
+
+else
+ ac_cv_search_inet_aton=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_inet_aton" >&5
+$as_echo "$ac_cv_search_inet_aton" >&6; }
+ac_res=$ac_cv_search_inet_aton
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostbyname" >&5
+$as_echo_n "checking for library containing gethostbyname... " >&6; }
+if ${ac_cv_search_gethostbyname+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostbyname ();
+int
+main ()
+{
+return gethostbyname ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' nsl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_gethostbyname=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_gethostbyname+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_gethostbyname+:} false; then :
+
+else
+ ac_cv_search_gethostbyname=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostbyname" >&5
+$as_echo "$ac_cv_search_gethostbyname" >&6; }
+ac_res=$ac_cv_search_gethostbyname
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing socket" >&5
+$as_echo_n "checking for library containing socket... " >&6; }
+if ${ac_cv_search_socket+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char socket ();
+int
+main ()
+{
+return socket ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' socket; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_socket=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_socket+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_socket+:} false; then :
+
+else
+ ac_cv_search_socket=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_socket" >&5
+$as_echo "$ac_cv_search_socket" >&6; }
+ac_res=$ac_cv_search_socket
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing gethostent" >&5
+$as_echo_n "checking for library containing gethostent... " >&6; }
+if ${ac_cv_search_gethostent+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char gethostent ();
+int
+main ()
+{
+return gethostent ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' nsl; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_gethostent=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_gethostent+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_gethostent+:} false; then :
+
+else
+ ac_cv_search_gethostent=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_gethostent" >&5
+$as_echo "$ac_cv_search_gethostent" >&6; }
+ac_res=$ac_cv_search_gethostent
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+fi
+
+
+
+
+case `pwd` in
+ *\ * | *\ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO ""
+}
+
+case "$ECHO" in
+ printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+ print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+ *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+ for ac_i in 1 2 3 4 5 6 7; do
+ ac_script="$ac_script$as_nl$ac_script"
+ done
+ echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+ { ac_script=; unset ac_script;}
+ if test -z "$SED"; then
+ ac_path_SED_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+ # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+ ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo '' >> "conftest.nl"
+ "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_SED_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_SED="$ac_path_SED"
+ ac_path_SED_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_SED_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_SED"; then
+ as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+ fi
+else
+ ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+ rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+ then ac_cv_path_FGREP="$GREP -F"
+ else
+ if test -z "$FGREP"; then
+ ac_path_FGREP_found=false
+ # Loop through the user's path and test for each of PROGNAME-LIST
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_prog in fgrep; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+ as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+ # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+ ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+ ac_count=0
+ $as_echo_n 0123456789 >"conftest.in"
+ while :
+ do
+ cat "conftest.in" "conftest.in" >"conftest.tmp"
+ mv "conftest.tmp" "conftest.in"
+ cp "conftest.in" "conftest.nl"
+ $as_echo 'FGREP' >> "conftest.nl"
+ "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+ diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+ as_fn_arith $ac_count + 1 && ac_count=$as_val
+ if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+ # Best one so far, save it but keep looking for a better one
+ ac_cv_path_FGREP="$ac_path_FGREP"
+ ac_path_FGREP_max=$ac_count
+ fi
+ # 10*(2^10) chars as input seems more than enough
+ test $ac_count -gt 10 && break
+ done
+ rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+ $ac_path_FGREP_found && break 3
+ done
+ done
+ done
+IFS=$as_save_IFS
+ if test -z "$ac_cv_path_FGREP"; then
+ as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+ fi
+else
+ ac_cv_path_FGREP=$FGREP
+fi
+
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ if test -n "$ac_tool_prefix"; then
+ for ac_prog in dumpbin "link -dump"
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DUMPBIN"; then
+ ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$DUMPBIN" && break
+ done
+fi
+if test -z "$DUMPBIN"; then
+ ac_ct_DUMPBIN=$DUMPBIN
+ for ac_prog in dumpbin "link -dump"
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DUMPBIN"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_DUMPBIN" && break
+done
+
+ if test "x$ac_ct_DUMPBIN" = x; then
+ DUMPBIN=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DUMPBIN=$ac_ct_DUMPBIN
+ fi
+fi
+
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the name lister ($NM) interface" >&5
+$as_echo_n "checking the name lister ($NM) interface... " >&6; }
+if ${lt_cv_nm_interface+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&5)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&5)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&5
+ (eval echo "\"\$as_me:$LINENO: output\"" >&5)
+ cat conftest.out >&5
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_nm_interface" >&5
+$as_echo "$lt_cv_nm_interface" >&6; }
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ln -s works" >&5
+$as_echo_n "checking whether ln -s works... " >&6; }
+LN_S=$as_ln_s
+if test "$LN_S" = "ln -s"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no, using $LN_S" >&5
+$as_echo "no, using $LN_S" >&6; }
+fi
+
+# find the maximum length of command line arguments
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking the maximum length of command line arguments" >&5
+$as_echo_n "checking the maximum length of command line arguments... " >&6; }
+if ${lt_cv_sys_max_cmd_len+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[ ]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+
+fi
+
+if test -n $lt_cv_sys_max_cmd_len ; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sys_max_cmd_len" >&5
+$as_echo "$lt_cv_sys_max_cmd_len" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: none" >&5
+$as_echo "none" >&6; }
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+
+
+
+
+
+
+: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands some XSI constructs" >&5
+$as_echo_n "checking whether the shell understands some XSI constructs... " >&6; }
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $xsi_shell" >&5
+$as_echo "$xsi_shell" >&6; }
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the shell understands \"+=\"" >&5
+$as_echo_n "checking whether the shell understands \"+=\"... " >&6; }
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$1+=\$2" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_shell_append" >&5
+$as_echo "$lt_shell_append" >&6; }
+
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+
+
+
+
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to $host format" >&5
+$as_echo_n "checking how to convert $build file names to $host format... " >&6; }
+if ${lt_cv_to_host_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+
+fi
+
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_host_file_cmd" >&5
+$as_echo "$lt_cv_to_host_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to convert $build file names to toolchain format" >&5
+$as_echo_n "checking how to convert $build file names to toolchain format... " >&6; }
+if ${lt_cv_to_tool_file_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ #assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+
+fi
+
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_to_tool_file_cmd" >&5
+$as_echo "$lt_cv_to_tool_file_cmd" >&6; }
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $LD option to reload object files" >&5
+$as_echo_n "checking for $LD option to reload object files... " >&6; }
+if ${lt_cv_ld_reload_flag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_reload_flag='-r'
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_reload_flag" >&5
+$as_echo "$lt_cv_ld_reload_flag" >&6; }
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}objdump", so it can be a program name with args.
+set dummy ${ac_tool_prefix}objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OBJDUMP"; then
+ ac_cv_prog_OBJDUMP="$OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OBJDUMP="${ac_tool_prefix}objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OBJDUMP=$ac_cv_prog_OBJDUMP
+if test -n "$OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OBJDUMP" >&5
+$as_echo "$OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OBJDUMP"; then
+ ac_ct_OBJDUMP=$OBJDUMP
+ # Extract the first word of "objdump", so it can be a program name with args.
+set dummy objdump; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OBJDUMP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OBJDUMP"; then
+ ac_cv_prog_ac_ct_OBJDUMP="$ac_ct_OBJDUMP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OBJDUMP="objdump"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OBJDUMP=$ac_cv_prog_ac_ct_OBJDUMP
+if test -n "$ac_ct_OBJDUMP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OBJDUMP" >&5
+$as_echo "$ac_ct_OBJDUMP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OBJDUMP" = x; then
+ OBJDUMP="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OBJDUMP=$ac_ct_OBJDUMP
+ fi
+else
+ OBJDUMP="$ac_cv_prog_OBJDUMP"
+fi
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to recognize dependent libraries" >&5
+$as_echo_n "checking how to recognize dependent libraries... " >&6; }
+if ${lt_cv_deplibs_check_method+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[4-9]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[45]*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[3-9]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF-[0-9][0-9]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]'
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|PA-RISC[0-9]\.[0-9]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[3-9]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[^/]+(\.so\.[0-9]+\.[0-9]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [ML]SB (shared object|dynamic lib) M[0-9][0-9]* Version [0-9]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [0-9][0-9]*-bit [LM]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [0-9][0-9]*-bit [LM]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_deplibs_check_method" >&5
+$as_echo "$lt_cv_deplibs_check_method" >&6; }
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[\1]\/[\1]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dlltool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DLLTOOL"; then
+ ac_cv_prog_DLLTOOL="$DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DLLTOOL="${ac_tool_prefix}dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DLLTOOL=$ac_cv_prog_DLLTOOL
+if test -n "$DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DLLTOOL" >&5
+$as_echo "$DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DLLTOOL"; then
+ ac_ct_DLLTOOL=$DLLTOOL
+ # Extract the first word of "dlltool", so it can be a program name with args.
+set dummy dlltool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DLLTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DLLTOOL"; then
+ ac_cv_prog_ac_ct_DLLTOOL="$ac_ct_DLLTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DLLTOOL="dlltool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DLLTOOL=$ac_cv_prog_ac_ct_DLLTOOL
+if test -n "$ac_ct_DLLTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DLLTOOL" >&5
+$as_echo "$ac_ct_DLLTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DLLTOOL" = x; then
+ DLLTOOL="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DLLTOOL=$ac_ct_DLLTOOL
+ fi
+else
+ DLLTOOL="$ac_cv_prog_DLLTOOL"
+fi
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to associate runtime and link libraries" >&5
+$as_echo_n "checking how to associate runtime and link libraries... " >&6; }
+if ${lt_cv_sharedlib_from_linklib_cmd+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_sharedlib_from_linklib_cmd" >&5
+$as_echo "$lt_cv_sharedlib_from_linklib_cmd" >&6; }
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ for ac_prog in ar
+ do
+ # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$AR"; then
+ ac_cv_prog_AR="$AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_AR="$ac_tool_prefix$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+AR=$ac_cv_prog_AR
+if test -n "$AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $AR" >&5
+$as_echo "$AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$AR" && break
+ done
+fi
+if test -z "$AR"; then
+ ac_ct_AR=$AR
+ for ac_prog in ar
+do
+ # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_AR+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_AR"; then
+ ac_cv_prog_ac_ct_AR="$ac_ct_AR" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_AR="$ac_prog"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_AR=$ac_cv_prog_ac_ct_AR
+if test -n "$ac_ct_AR"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_AR" >&5
+$as_echo "$ac_ct_AR" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ test -n "$ac_ct_AR" && break
+done
+
+ if test "x$ac_ct_AR" = x; then
+ AR="false"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ AR=$ac_ct_AR
+ fi
+fi
+
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for archiver @FILE support" >&5
+$as_echo_n "checking for archiver @FILE support... " >&6; }
+if ${lt_cv_ar_at_file+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ar_at_file=no
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&5'
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$lt_ar_try\""; } >&5
+ (eval $lt_ar_try) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ar_at_file" >&5
+$as_echo "$lt_cv_ar_at_file" >&6; }
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}strip", so it can be a program name with args.
+set dummy ${ac_tool_prefix}strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$STRIP"; then
+ ac_cv_prog_STRIP="$STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_STRIP="${ac_tool_prefix}strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+STRIP=$ac_cv_prog_STRIP
+if test -n "$STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $STRIP" >&5
+$as_echo "$STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_STRIP"; then
+ ac_ct_STRIP=$STRIP
+ # Extract the first word of "strip", so it can be a program name with args.
+set dummy strip; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_STRIP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_STRIP"; then
+ ac_cv_prog_ac_ct_STRIP="$ac_ct_STRIP" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_STRIP="strip"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_STRIP=$ac_cv_prog_ac_ct_STRIP
+if test -n "$ac_ct_STRIP"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_STRIP" >&5
+$as_echo "$ac_ct_STRIP" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_STRIP" = x; then
+ STRIP=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ STRIP=$ac_ct_STRIP
+ fi
+else
+ STRIP="$ac_cv_prog_STRIP"
+fi
+
+test -z "$STRIP" && STRIP=:
+
+
+
+
+
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}ranlib", so it can be a program name with args.
+set dummy ${ac_tool_prefix}ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RANLIB"; then
+ ac_cv_prog_RANLIB="$RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RANLIB="${ac_tool_prefix}ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RANLIB=$ac_cv_prog_RANLIB
+if test -n "$RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RANLIB" >&5
+$as_echo "$RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_RANLIB"; then
+ ac_ct_RANLIB=$RANLIB
+ # Extract the first word of "ranlib", so it can be a program name with args.
+set dummy ranlib; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_RANLIB+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_RANLIB"; then
+ ac_cv_prog_ac_ct_RANLIB="$ac_ct_RANLIB" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_RANLIB="ranlib"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_RANLIB=$ac_cv_prog_ac_ct_RANLIB
+if test -n "$ac_ct_RANLIB"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_RANLIB" >&5
+$as_echo "$ac_ct_RANLIB" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_RANLIB" = x; then
+ RANLIB=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ RANLIB=$ac_ct_RANLIB
+ fi
+else
+ RANLIB="$ac_cv_prog_RANLIB"
+fi
+
+test -z "$RANLIB" && RANLIB=:
+
+
+
+
+
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking command to parse $NM output from $compiler object" >&5
+$as_echo_n "checking command to parse $NM output from $compiler object... " >&6; }
+if ${lt_cv_sys_global_symbol_pipe+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[BCDEGRST]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([_A-Za-z][_A-Za-z0-9]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[BCDT]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[ABCDGISTW]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[ABCDEGRST]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[BCDEGRST]'
+ ;;
+osf*)
+ symcode='[BCDEGQRST]'
+ ;;
+solaris*)
+ symcode='[BDRT]'
+ ;;
+sco3.2v5*)
+ symcode='[DT]'
+ ;;
+sysv4.2uw2*)
+ symcode='[DT]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[ABDT]'
+ ;;
+sysv4)
+ symcode='[DFNSTU]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[ABCDGIRSTW]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([^ ]*\)[ ]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([^ ]*\) \(lib[^ ]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([^ ]*\) \([^ ]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK '"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[ ]\($symcode$symcode*\)[ ][ ]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist\""; } >&5
+ (eval $NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT_DLSYM_CONST
+#else
+# define LT_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$lt_prog_compiler_no_builtin_flag"
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&5
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&5
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&5
+ fi
+ else
+ echo "$progname: failed program was:" >&5
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+
+fi
+
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: failed" >&5
+$as_echo "failed" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ok" >&5
+$as_echo "ok" >&6; }
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[@]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sysroot" >&5
+$as_echo_n "checking for sysroot... " >&6; }
+
+# Check whether --with-sysroot was given.
+if test "${with_sysroot+set}" = set; then :
+ withval=$with_sysroot;
+else
+ with_sysroot=no
+fi
+
+
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${with_sysroot}" >&5
+$as_echo "${with_sysroot}" >&6; }
+ as_fn_error $? "The sysroot must be an absolute path." "$LINENO" 5
+ ;;
+esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${lt_sysroot:-no}" >&5
+$as_echo "${lt_sysroot:-no}" >&6; }
+
+
+
+
+
+# Check whether --enable-libtool-lock was given.
+if test "${enable_libtool_lock+set}" = set; then :
+ enableval=$enable_libtool_lock;
+fi
+
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '#line '$LINENO' "configure"' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the C compiler needs -belf" >&5
+$as_echo_n "checking whether the C compiler needs -belf... " >&6; }
+if ${lt_cv_cc_needs_belf+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_cc_needs_belf=yes
+else
+ lt_cv_cc_needs_belf=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_cc_needs_belf" >&5
+$as_echo "$lt_cv_cc_needs_belf" >&6; }
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+
+if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}mt", so it can be a program name with args.
+set dummy ${ac_tool_prefix}mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$MANIFEST_TOOL"; then
+ ac_cv_prog_MANIFEST_TOOL="$MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_MANIFEST_TOOL="${ac_tool_prefix}mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+MANIFEST_TOOL=$ac_cv_prog_MANIFEST_TOOL
+if test -n "$MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MANIFEST_TOOL" >&5
+$as_echo "$MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_MANIFEST_TOOL"; then
+ ac_ct_MANIFEST_TOOL=$MANIFEST_TOOL
+ # Extract the first word of "mt", so it can be a program name with args.
+set dummy mt; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_MANIFEST_TOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_MANIFEST_TOOL"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="$ac_ct_MANIFEST_TOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_MANIFEST_TOOL="mt"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_MANIFEST_TOOL=$ac_cv_prog_ac_ct_MANIFEST_TOOL
+if test -n "$ac_ct_MANIFEST_TOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_MANIFEST_TOOL" >&5
+$as_echo "$ac_ct_MANIFEST_TOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_MANIFEST_TOOL" = x; then
+ MANIFEST_TOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ MANIFEST_TOOL=$ac_ct_MANIFEST_TOOL
+ fi
+else
+ MANIFEST_TOOL="$ac_cv_prog_MANIFEST_TOOL"
+fi
+
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $MANIFEST_TOOL is a manifest tool" >&5
+$as_echo_n "checking if $MANIFEST_TOOL is a manifest tool... " >&6; }
+if ${lt_cv_path_mainfest_tool+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&5
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&5
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_mainfest_tool" >&5
+$as_echo "$lt_cv_path_mainfest_tool" >&6; }
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+
+
+
+
+
+
+ case $host_os in
+ rhapsody* | darwin*)
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$DSYMUTIL"; then
+ ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+ ac_ct_DSYMUTIL=$DSYMUTIL
+ # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_DSYMUTIL"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_DSYMUTIL" = x; then
+ DSYMUTIL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ DSYMUTIL=$ac_ct_DSYMUTIL
+ fi
+else
+ DSYMUTIL="$ac_cv_prog_DSYMUTIL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$NMEDIT"; then
+ ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_NMEDIT"; then
+ ac_ct_NMEDIT=$NMEDIT
+ # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_NMEDIT"; then
+ ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_NMEDIT="nmedit"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_NMEDIT" = x; then
+ NMEDIT=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ NMEDIT=$ac_ct_NMEDIT
+ fi
+else
+ NMEDIT="$ac_cv_prog_NMEDIT"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$LIPO"; then
+ ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_LIPO"; then
+ ac_ct_LIPO=$LIPO
+ # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_LIPO"; then
+ ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_LIPO="lipo"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_LIPO" = x; then
+ LIPO=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ LIPO=$ac_ct_LIPO
+ fi
+else
+ LIPO="$ac_cv_prog_LIPO"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL"; then
+ ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL"; then
+ ac_ct_OTOOL=$OTOOL
+ # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL"; then
+ ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL="otool"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL" = x; then
+ OTOOL=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL=$ac_ct_OTOOL
+ fi
+else
+ OTOOL="$ac_cv_prog_OTOOL"
+fi
+
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$OTOOL64"; then
+ ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_OTOOL64"; then
+ ac_ct_OTOOL64=$OTOOL64
+ # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_OTOOL64"; then
+ ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_OTOOL64="otool64"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_OTOOL64" = x; then
+ OTOOL64=":"
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ OTOOL64=$ac_ct_OTOOL64
+ fi
+else
+ OTOOL64="$ac_cv_prog_OTOOL64"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&5
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_ld_exported_symbols_list=yes
+else
+ lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+ echo "$AR cru libconftest.a conftest.o" >&5
+ $AR cru libconftest.a conftest.o 2>&5
+ echo "$RANLIB libconftest.a" >&5
+ $RANLIB libconftest.a 2>&5
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&5
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&5
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+ case $host_os in
+ rhapsody* | darwin1.[012])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[012]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+
+for ac_header in dlfcn.h
+do :
+ ac_fn_c_check_header_compile "$LINENO" "dlfcn.h" "ac_cv_header_dlfcn_h" "$ac_includes_default
+"
+if test "x$ac_cv_header_dlfcn_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_DLFCN_H 1
+_ACEOF
+
+fi
+
+done
+
+
+
+func_stripname_cnf ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname_cnf
+
+
+
+
+
+# Set options
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+ enableval=$enable_static; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_static=no
+fi
+
+
+
+
+
+
+
+enable_dlopen=yes
+
+
+
+
+ enable_win32_dll=no
+
+
+ # Check whether --enable-shared was given.
+if test "${enable_shared+set}" = set; then :
+ enableval=$enable_shared; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_shared=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-pic was given.
+if test "${with_pic+set}" = set; then :
+ withval=$with_pic; lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ pic_mode=default
+fi
+
+
+test -z "$pic_mode" && pic_mode=default
+
+
+
+
+
+
+
+ # Check whether --enable-fast-install was given.
+if test "${enable_fast_install+set}" = set; then :
+ enableval=$enable_fast_install; p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac
+else
+ enable_fast_install=yes
+fi
+
+
+
+
+
+
+
+
+
+
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+test -z "$LN_S" && LN_S="ln -s"
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for objdir" >&5
+$as_echo_n "checking for objdir... " >&6; }
+if ${lt_cv_objdir+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_objdir" >&5
+$as_echo "$lt_cv_objdir" >&6; }
+objdir=$lt_cv_objdir
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define LT_OBJDIR "$lt_cv_objdir/"
+_ACEOF
+
+
+
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ${ac_tool_prefix}file" >&5
+$as_echo_n "checking for ${ac_tool_prefix}file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/${ac_tool_prefix}file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/${ac_tool_prefix}file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+
+
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for file" >&5
+$as_echo_n "checking for file... " >&6; }
+if ${lt_cv_path_MAGIC_CMD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MAGIC_CMD in
+[\\/*] | ?:[\\/]*)
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ ac_dummy="/usr/bin$PATH_SEPARATOR$PATH"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/file; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/file"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac
+fi
+
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MAGIC_CMD" >&5
+$as_echo "$MAGIC_CMD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ MAGIC_CMD=:
+ fi
+fi
+
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+
+lt_save_CC="$CC"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+objext=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+
+lt_prog_compiler_no_builtin_flag=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ lt_prog_compiler_no_builtin_flag=' -Xcompiler -fno-builtin' ;;
+ *)
+ lt_prog_compiler_no_builtin_flag=' -fno-builtin' ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -fno-rtti -fno-exceptions" >&5
+$as_echo_n "checking if $compiler supports -fno-rtti -fno-exceptions... " >&6; }
+if ${lt_cv_prog_compiler_rtti_exceptions+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_rtti_exceptions=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="-fno-rtti -fno-exceptions"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_rtti_exceptions=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_rtti_exceptions" >&5
+$as_echo "$lt_cv_prog_compiler_rtti_exceptions" >&6; }
+
+if test x"$lt_cv_prog_compiler_rtti_exceptions" = xyes; then
+ lt_prog_compiler_no_builtin_flag="$lt_prog_compiler_no_builtin_flag -fno-rtti -fno-exceptions"
+else
+ :
+fi
+
+fi
+
+
+
+
+
+
+ lt_prog_compiler_wl=
+lt_prog_compiler_pic=
+lt_prog_compiler_static=
+
+
+ if test "$GCC" = yes; then
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_static='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ lt_prog_compiler_can_build_shared=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ lt_prog_compiler_pic='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ lt_prog_compiler_wl='-Xlinker '
+ if test -n "$lt_prog_compiler_pic"; then
+ lt_prog_compiler_pic="-Xcompiler $lt_prog_compiler_pic"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ lt_prog_compiler_wl='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static='-Bstatic'
+ else
+ lt_prog_compiler_static='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic='-DDLL_EXPORT'
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ lt_prog_compiler_static='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ lt_prog_compiler_wl='-Wl,'
+ # PIC (with -KPIC) is the default.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='--shared'
+ lt_prog_compiler_static='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ lt_prog_compiler_wl='-Wl,-Wl,,'
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ ccc*)
+ lt_prog_compiler_wl='-Wl,'
+ # All Alpha code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-qpic'
+ lt_prog_compiler_static='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [1-7].* | *Sun*Fortran*\ 8.[0-3]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ lt_prog_compiler_wl='-Wl,'
+ ;;
+ *Intel*\ [CF]*Compiler*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fPIC'
+ lt_prog_compiler_static='-static'
+ ;;
+ *Portland\ Group*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-fpic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ lt_prog_compiler_wl='-Wl,'
+ # All OSF/1 code is PIC.
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ rdos*)
+ lt_prog_compiler_static='-non_shared'
+ ;;
+
+ solaris*)
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ lt_prog_compiler_wl='-Qoption ld ';;
+ *)
+ lt_prog_compiler_wl='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ lt_prog_compiler_wl='-Qoption ld '
+ lt_prog_compiler_pic='-PIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ lt_prog_compiler_pic='-Kconform_pic'
+ lt_prog_compiler_static='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_pic='-KPIC'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ unicos*)
+ lt_prog_compiler_wl='-Wl,'
+ lt_prog_compiler_can_build_shared=no
+ ;;
+
+ uts4*)
+ lt_prog_compiler_pic='-pic'
+ lt_prog_compiler_static='-Bstatic'
+ ;;
+
+ *)
+ lt_prog_compiler_can_build_shared=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic=
+ ;;
+ *)
+ lt_prog_compiler_pic="$lt_prog_compiler_pic -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic=$lt_prog_compiler_pic
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic" >&5
+$as_echo "$lt_cv_prog_compiler_pic" >&6; }
+lt_prog_compiler_pic=$lt_cv_prog_compiler_pic
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works" = xyes; then
+ case $lt_prog_compiler_pic in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic=" $lt_prog_compiler_pic" ;;
+ esac
+else
+ lt_prog_compiler_pic=
+ lt_prog_compiler_can_build_shared=no
+fi
+
+fi
+
+
+
+
+
+
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl eval lt_tmp_static_flag=\"$lt_prog_compiler_static\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works" >&5
+$as_echo "$lt_cv_prog_compiler_static_works" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works" = xyes; then
+ :
+else
+ lt_prog_compiler_static=
+fi
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o" >&5
+$as_echo "$lt_cv_prog_compiler_c_o" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ runpath_var=
+ allow_undefined_flag=
+ always_export_symbols=no
+ archive_cmds=
+ archive_expsym_cmds=
+ compiler_needs_object=no
+ enable_shared_with_static_runtimes=no
+ export_dynamic_flag_spec=
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ hardcode_automatic=no
+ hardcode_direct=no
+ hardcode_direct_absolute=no
+ hardcode_libdir_flag_spec=
+ hardcode_libdir_separator=
+ hardcode_minus_L=no
+ hardcode_shlibpath_var=unsupported
+ inherit_rpath=no
+ link_all_deplibs=unknown
+ module_cmds=
+ module_expsym_cmds=
+ old_archive_from_new_cmds=
+ old_archive_from_expsyms_cmds=
+ thread_safe_flag_spec=
+ whole_archive_flag_spec=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ include_expsyms=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ exclude_expsyms='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ link_all_deplibs=no
+ ;;
+ esac
+
+ ld_shlibs=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[2-9]*) ;;
+ *\ \(GNU\ Binutils\)\ [3-9]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[3-9]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, ) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec='-L$libdir'
+ export_dynamic_flag_spec='${wl}--export-all-symbols'
+ allow_undefined_flag=unsupported
+ always_export_symbols=no
+ enable_shared_with_static_runtimes=yes
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ haiku*)
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs=yes
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ whole_archive_flag_spec=
+ tmp_sharedflag='--shared' ;;
+ xl[cC]* | bgxl[cC]* | mpixl[cC]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ whole_archive_flag_spec='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ whole_archive_flag_spec='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ archive_cmds='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ whole_archive_flag_spec='--whole-archive$convenience --no-whole-archive'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [01].* | *\ 2.[0-9].* | *\ 2.1[0-5].*)
+ ld_shlibs=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ archive_cmds='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ ld_shlibs=no
+ fi
+ ;;
+ esac
+
+ if test "$ld_shlibs" = no; then
+ runpath_var=
+ hardcode_libdir_flag_spec=
+ export_dynamic_flag_spec=
+ whole_archive_flag_spec=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ archive_expsym_cmds='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ hardcode_minus_L=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ hardcode_direct=unsupported
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds=''
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ file_list_spec='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L=yes
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_libdir_separator=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ link_all_deplibs=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ always_export_symbols=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ archive_expsym_cmds='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag="-z nodefs"
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath_+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath_=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath_"; then
+ lt_cv_aix_libpath_="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath_
+fi
+
+ hardcode_libdir_flag_spec='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag=' ${wl}-bernotok'
+ allow_undefined_flag=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec='$convenience'
+ fi
+ archive_cmds_need_lc=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ archive_expsym_cmds="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds=''
+ ;;
+ m68k)
+ archive_cmds='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[45]*)
+ export_dynamic_flag_spec=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ always_export_symbols=yes
+ file_list_spec='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ archive_expsym_cmds='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, )='true'
+ enable_shared_with_static_runtimes=yes
+ exclude_expsyms='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ export_symbols_cmds='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1,DATA/'\'' | $SED -e '\''/^[AITW][ ]/s/.*[ ]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ old_postinstall_cmds='chmod 644 $oldlib'
+ postlink_cmds='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ hardcode_libdir_flag_spec=' '
+ allow_undefined_flag=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ old_archive_from_new_cmds='true'
+ # FIXME: Should let the user specify the lib program.
+ old_archive_cmds='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ enable_shared_with_static_runtimes=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc=no
+ hardcode_direct=no
+ hardcode_automatic=yes
+ hardcode_shlibpath_var=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec=''
+ fi
+ link_all_deplibs=yes
+ allow_undefined_flag="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+
+ else
+ ld_shlibs=no
+ fi
+
+ ;;
+
+ dgux*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ archive_cmds='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ archive_cmds='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ export_dynamic_flag_spec='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $CC understands -b" >&5
+$as_echo_n "checking if $CC understands -b... " >&6; }
+if ${lt_cv_prog_compiler__b+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler__b=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -b"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler__b=yes
+ fi
+ else
+ lt_cv_prog_compiler__b=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler__b" >&5
+$as_echo "$lt_cv_prog_compiler__b" >&6; }
+
+if test x"$lt_cv_prog_compiler__b" = xyes; then
+ archive_cmds='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+else
+ archive_cmds='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+fi
+
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ hardcode_libdir_flag_spec='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct=no
+ hardcode_shlibpath_var=no
+ ;;
+ *)
+ hardcode_direct=yes
+ hardcode_direct_absolute=yes
+ export_dynamic_flag_spec='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ hardcode_minus_L=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $host_os linker accepts -exported_symbol" >&5
+$as_echo_n "checking whether the $host_os linker accepts -exported_symbol... " >&6; }
+if ${lt_cv_irix_exported_symbol+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+int foo (void) { return 0; }
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ lt_cv_irix_exported_symbol=yes
+else
+ lt_cv_irix_exported_symbol=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS="$save_LDFLAGS"
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_irix_exported_symbol" >&5
+$as_echo "$lt_cv_irix_exported_symbol" >&6; }
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ archive_expsym_cmds='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ archive_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ inherit_rpath=yes
+ link_all_deplibs=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ archive_cmds='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ newsos6)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ hardcode_shlibpath_var=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct=yes
+ hardcode_shlibpath_var=no
+ hardcode_direct_absolute=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec='${wl}-E'
+ else
+ case $host_os in
+ openbsd[01].* | openbsd2.[0-7] | openbsd2.[0-7].*)
+ archive_cmds='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-R$libdir'
+ ;;
+ *)
+ archive_cmds='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ hardcode_libdir_flag_spec='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ ld_shlibs=no
+ fi
+ ;;
+
+ os2*)
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_minus_L=yes
+ allow_undefined_flag=unsupported
+ archive_cmds='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ old_archive_from_new_cmds='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ allow_undefined_flag=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec='${wl}-rpath ${wl}$libdir'
+ else
+ allow_undefined_flag=' -expect_unresolved \*'
+ archive_cmds='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ hardcode_libdir_flag_spec='-rpath $libdir'
+ fi
+ archive_cmds_need_lc='no'
+ hardcode_libdir_separator=:
+ ;;
+
+ solaris*)
+ no_undefined_flag=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ archive_cmds='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ archive_cmds='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ archive_cmds='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ hardcode_libdir_flag_spec='-R$libdir'
+ hardcode_shlibpath_var=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ whole_archive_flag_spec='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ whole_archive_flag_spec='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ link_all_deplibs=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ archive_cmds='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_direct=yes
+ hardcode_minus_L=yes
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ archive_cmds='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ reload_cmds='$CC -r -o $output$reload_objs'
+ hardcode_direct=no
+ ;;
+ motorola)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_direct=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ hardcode_shlibpath_var=no
+ ;;
+
+ sysv4.3*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ export_dynamic_flag_spec='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_shlibpath_var=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ ld_shlibs=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag='${wl}-z,text'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag='${wl}-z,text'
+ allow_undefined_flag='${wl}-z,nodefs'
+ archive_cmds_need_lc=no
+ hardcode_shlibpath_var=no
+ hardcode_libdir_flag_spec='${wl}-R,$libdir'
+ hardcode_libdir_separator=':'
+ link_all_deplibs=yes
+ export_dynamic_flag_spec='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ archive_cmds='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ archive_cmds='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ archive_cmds='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ hardcode_libdir_flag_spec='-L$libdir'
+ hardcode_shlibpath_var=no
+ ;;
+
+ *)
+ ld_shlibs=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ export_dynamic_flag_spec='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs" >&5
+$as_echo "$ld_shlibs" >&6; }
+test "$ld_shlibs" = no && can_build_shared=no
+
+with_gnu_ld=$with_gnu_ld
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl
+ pic_flag=$lt_prog_compiler_pic
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag
+ allow_undefined_flag=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc=no
+ else
+ lt_cv_archive_cmds_need_lc=yes
+ fi
+ allow_undefined_flag=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc" >&6; }
+ archive_cmds_need_lc=$lt_cv_archive_cmds_need_lc
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([A-Za-z]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[lt_foo]++; }
+ if (lt_freq[lt_foo] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([A-Za-z]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action=
+if test -n "$hardcode_libdir_flag_spec" ||
+ test -n "$runpath_var" ||
+ test "X$hardcode_automatic" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, )" != no &&
+ test "$hardcode_minus_L" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action" >&5
+$as_echo "$hardcode_action" >&6; }
+
+if test "$hardcode_action" = relink ||
+ test "$inherit_rpath" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+ if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+
+fi
+
+ ;;
+
+ *)
+ ac_fn_c_check_func "$LINENO" "shl_load" "ac_cv_func_shl_load"
+if test "x$ac_cv_func_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for shl_load in -ldld" >&5
+$as_echo_n "checking for shl_load in -ldld... " >&6; }
+if ${ac_cv_lib_dld_shl_load+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char shl_load ();
+int
+main ()
+{
+return shl_load ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_shl_load=yes
+else
+ ac_cv_lib_dld_shl_load=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_shl_load" >&5
+$as_echo "$ac_cv_lib_dld_shl_load" >&6; }
+if test "x$ac_cv_lib_dld_shl_load" = xyes; then :
+ lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"
+else
+ ac_fn_c_check_func "$LINENO" "dlopen" "ac_cv_func_dlopen"
+if test "x$ac_cv_func_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldl $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dl_dlopen=yes
+else
+ ac_cv_lib_dl_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -lsvld" >&5
+$as_echo_n "checking for dlopen in -lsvld... " >&6; }
+if ${ac_cv_lib_svld_dlopen+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lsvld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dlopen ();
+int
+main ()
+{
+return dlopen ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_svld_dlopen=yes
+else
+ ac_cv_lib_svld_dlopen=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_svld_dlopen" >&5
+$as_echo "$ac_cv_lib_svld_dlopen" >&6; }
+if test "x$ac_cv_lib_svld_dlopen" = xyes; then :
+ lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for dld_link in -ldld" >&5
+$as_echo_n "checking for dld_link in -ldld... " >&6; }
+if ${ac_cv_lib_dld_dld_link+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-ldld $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char dld_link ();
+int
+main ()
+{
+return dld_link ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+ ac_cv_lib_dld_dld_link=yes
+else
+ ac_cv_lib_dld_dld_link=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dld_dld_link" >&5
+$as_echo "$ac_cv_lib_dld_dld_link" >&6; }
+if test "x$ac_cv_lib_dld_dld_link" = xyes; then :
+ lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+
+fi
+
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a program can dlopen itself" >&5
+$as_echo_n "checking whether a program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self" >&5
+$as_echo "$lt_cv_dlopen_self" >&6; }
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether a statically linked program can dlopen itself" >&5
+$as_echo_n "checking whether a statically linked program can dlopen itself... " >&6; }
+if ${lt_cv_dlopen_self_static+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test "$cross_compiling" = yes; then :
+ lt_cv_dlopen_self_static=cross
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}
+_LT_EOF
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_link\""; } >&5
+ (eval $ac_link) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&5 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlneed_uscore) lt_cv_dlopen_self_static=yes ;;
+ x$lt_dlunknown|x*) lt_cv_dlopen_self_static=no ;;
+ esac
+ else :
+ # compilation failed
+ lt_cv_dlopen_self_static=no
+ fi
+fi
+rm -fr conftest*
+
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_dlopen_self_static" >&5
+$as_echo "$lt_cv_dlopen_self_static" >&6; }
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+striplib=
+old_striplib=
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether stripping libraries is possible" >&5
+$as_echo_n "checking whether stripping libraries is possible... " >&6; }
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ ;;
+ *)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ ;;
+ esac
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+ # Report which library types will actually be built
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if libtool supports shared libraries" >&5
+$as_echo_n "checking if libtool supports shared libraries... " >&6; }
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $can_build_shared" >&5
+$as_echo "$can_build_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build shared libraries" >&5
+$as_echo_n "checking whether to build shared libraries... " >&6; }
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[4-9]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_shared" >&5
+$as_echo "$enable_shared" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to build static libraries" >&5
+$as_echo_n "checking whether to build static libraries... " >&6; }
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_static" >&5
+$as_echo "$enable_static" >&6; }
+
+
+
+
+fi
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+CC="$lt_save_CC"
+
+ if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C++ preprocessor" >&5
+$as_echo_n "checking how to run the C++ preprocessor... " >&6; }
+if test -z "$CXXCPP"; then
+ if ${ac_cv_prog_CXXCPP+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # Double quotes because CXXCPP needs to be expanded
+ for CXXCPP in "$CXX -E" "/lib/cpp"
+ do
+ ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+ break
+fi
+
+ done
+ ac_cv_prog_CXXCPP=$CXXCPP
+
+fi
+ CXXCPP=$ac_cv_prog_CXXCPP
+else
+ ac_cv_prog_CXXCPP=$CXXCPP
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CXXCPP" >&5
+$as_echo "$CXXCPP" >&6; }
+ac_preproc_ok=false
+for ac_cxx_preproc_warn_flag in '' yes
+do
+ # Use a header file that comes with gcc, so configuring glibc
+ # with a fresh cross-compiler works.
+ # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+ # <limits.h> exists even on freestanding compilers.
+ # On the NeXT, cc -E runs the code through the compiler's parser,
+ # not just through cpp. "Syntax error" is here to catch this case.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+ Syntax error
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+
+else
+ # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+ # OK, works on sane cases. Now check whether nonexistent headers
+ # can be detected and how.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_cxx_try_cpp "$LINENO"; then :
+ # Broken: success on invalid input.
+continue
+else
+ # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+
+else
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C++ preprocessor \"$CXXCPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+else
+ _lt_caught_CXX_error=yes
+fi
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+archive_cmds_need_lc_CXX=no
+allow_undefined_flag_CXX=
+always_export_symbols_CXX=no
+archive_expsym_cmds_CXX=
+compiler_needs_object_CXX=no
+export_dynamic_flag_spec_CXX=
+hardcode_direct_CXX=no
+hardcode_direct_absolute_CXX=no
+hardcode_libdir_flag_spec_CXX=
+hardcode_libdir_separator_CXX=
+hardcode_minus_L_CXX=no
+hardcode_shlibpath_var_CXX=unsupported
+hardcode_automatic_CXX=no
+inherit_rpath_CXX=no
+module_cmds_CXX=
+module_expsym_cmds_CXX=
+link_all_deplibs_CXX=unknown
+old_archive_cmds_CXX=$old_archive_cmds
+reload_flag_CXX=$reload_flag
+reload_cmds_CXX=$reload_cmds
+no_undefined_flag_CXX=
+whole_archive_flag_spec_CXX=
+enable_shared_with_static_runtimes_CXX=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+objext_CXX=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+
+
+
+
+
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+
+
+ # save warnings/boilerplate of simple test code
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+
+ ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ compiler_CXX=$CC
+ for cc_temp in $compiler""; do
+ case $cc_temp in
+ compile | *[\\/]compile | ccache | *[\\/]ccache ) ;;
+ distcc | *[\\/]distcc | purify | *[\\/]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ lt_prog_compiler_no_builtin_flag_CXX=' -fno-builtin'
+ else
+ lt_prog_compiler_no_builtin_flag_CXX=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+ withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+ with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [\\/]* | ?:[\\/]*)
+ re_direlt='/[^/][^/]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ archive_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ whole_archive_flag_spec_CXX=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+ ld_shlibs_CXX=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aix[4-9]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[23]|aix4.[23].*|aix[5-9]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ archive_cmds_CXX=''
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ file_list_spec_CXX='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[012]|aix4.[012].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ hardcode_direct_CXX=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ hardcode_minus_L_CXX=yes
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ hardcode_libdir_separator_CXX=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ export_dynamic_flag_spec_CXX='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ always_export_symbols_CXX=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ allow_undefined_flag_CXX='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath__CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath__CXX"; then
+ lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath__CXX"; then
+ lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ archive_expsym_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ hardcode_libdir_flag_spec_CXX='${wl}-R $libdir:/usr/lib:/lib'
+ allow_undefined_flag_CXX="-z nodefs"
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ if ${lt_cv_aix_libpath__CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+ lt_aix_libpath_sed='
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }'
+ lt_cv_aix_libpath__CXX=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$lt_cv_aix_libpath__CXX"; then
+ lt_cv_aix_libpath__CXX=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ if test -z "$lt_cv_aix_libpath__CXX"; then
+ lt_cv_aix_libpath__CXX="/usr/lib:/lib"
+ fi
+
+fi
+
+ aix_libpath=$lt_cv_aix_libpath__CXX
+fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ no_undefined_flag_CXX=' ${wl}-bernotok'
+ allow_undefined_flag_CXX=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ whole_archive_flag_spec_CXX='$convenience'
+ fi
+ archive_cmds_need_lc_CXX=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ archive_expsym_cmds_CXX="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ allow_undefined_flag_CXX=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ archive_cmds_CXX='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX=' '
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=yes
+ file_list_spec_CXX='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ archive_cmds_CXX='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, CXX)='true'
+ enable_shared_with_static_runtimes_CXX=yes
+ # Don't use ranlib
+ old_postinstall_cmds_CXX='chmod 644 $oldlib'
+ postlink_cmds_CXX='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, CXX) is actually meaningless,
+ # as there is no search path for DLLs.
+ hardcode_libdir_flag_spec_CXX='-L$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-all-symbols'
+ allow_undefined_flag_CXX=unsupported
+ always_export_symbols_CXX=no
+ enable_shared_with_static_runtimes_CXX=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ archive_cmds_CXX='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ archive_expsym_cmds_CXX='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+
+
+ archive_cmds_need_lc_CXX=no
+ hardcode_direct_CXX=no
+ hardcode_automatic_CXX=yes
+ hardcode_shlibpath_var_CXX=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ whole_archive_flag_spec_CXX='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+
+ else
+ whole_archive_flag_spec_CXX=''
+ fi
+ link_all_deplibs_CXX=yes
+ allow_undefined_flag_CXX="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ archive_cmds_CXX="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ module_cmds_CXX="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ module_expsym_cmds_CXX="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ archive_cmds_CXX="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ archive_expsym_cmds_CXX="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+
+ else
+ ld_shlibs_CXX=no
+ fi
+
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ ld_shlibs_CXX=no
+ ;;
+
+ freebsd-elf*)
+ archive_cmds_need_lc_CXX=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ ld_shlibs_CXX=yes
+ ;;
+
+ haiku*)
+ archive_cmds_CXX='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ link_all_deplibs_CXX=yes
+ ;;
+
+ hpux9*)
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ hardcode_direct_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ archive_cmds_CXX='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ hardcode_libdir_flag_spec_CXX='${wl}+b ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ ;;
+ *)
+ hardcode_direct_CXX=yes
+ hardcode_direct_absolute_CXX=yes
+ hardcode_minus_L_CXX=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ archive_cmds_CXX='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[3-9]*)
+ hardcode_direct_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ archive_cmds_CXX='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ archive_expsym_cmds_CXX='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ archive_cmds_CXX='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ link_all_deplibs_CXX=yes
+ ;;
+ esac
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+ inherit_rpath_CXX=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ archive_expsym_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ archive_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ archive_cmds_need_lc_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [1-5].* | *pgcpp\ [1-5].*)
+ prelink_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ old_archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ archive_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}--rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ export_dynamic_flag_spec_CXX='${wl}--export-dynamic'
+ archive_cmds_CXX='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ archive_expsym_cmds_CXX='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ whole_archive_flag_spec_CXX='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ compiler_needs_object_CXX=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ archive_cmds_CXX='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ ld_shlibs_CXX=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ ld_shlibs_CXX=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ hardcode_direct_CXX=yes
+ hardcode_shlibpath_var_CXX=no
+ hardcode_direct_absolute_CXX=yes
+ archive_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ archive_expsym_cmds_CXX='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ export_dynamic_flag_spec_CXX='${wl}-E'
+ whole_archive_flag_spec_CXX="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ ld_shlibs_CXX=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ archive_cmds_CXX='tempext=`echo $shared_ext | $SED -e '\''s/\([^()0-9A-Za-z{}]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath,$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) old_archive_cmds_CXX='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) old_archive_cmds_CXX='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ allow_undefined_flag_CXX=' -expect_unresolved \*'
+ archive_cmds_CXX='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ archive_expsym_cmds_CXX='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ hardcode_libdir_flag_spec_CXX='-rpath $libdir'
+ ;;
+ esac
+
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ allow_undefined_flag_CXX=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ archive_cmds_CXX='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ hardcode_libdir_flag_spec_CXX='${wl}-rpath ${wl}$libdir'
+ hardcode_libdir_separator_CXX=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ archive_cmds_need_lc_CXX=yes
+ no_undefined_flag_CXX=' -zdefs'
+ archive_cmds_CXX='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ hardcode_libdir_flag_spec_CXX='-R$libdir'
+ hardcode_shlibpath_var_CXX=no
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ whole_archive_flag_spec_CXX='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ link_all_deplibs_CXX=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ old_archive_cmds_CXX='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ archive_cmds_CXX='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ old_archive_cmds_CXX='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ no_undefined_flag_CXX=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ archive_cmds_CXX='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ archive_cmds_CXX='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ archive_expsym_cmds_CXX='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ hardcode_libdir_flag_spec_CXX='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[0-5] | solaris2.[0-5].*) ;;
+ *)
+ whole_archive_flag_spec_CXX='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[01].[10]* | unixware7* | sco3.2v5.0.[024]*)
+ no_undefined_flag_CXX='${wl}-z,text'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ no_undefined_flag_CXX='${wl}-z,text'
+ allow_undefined_flag_CXX='${wl}-z,nodefs'
+ archive_cmds_need_lc_CXX=no
+ hardcode_shlibpath_var_CXX=no
+ hardcode_libdir_flag_spec_CXX='${wl}-R,$libdir'
+ hardcode_libdir_separator_CXX=':'
+ link_all_deplibs_CXX=yes
+ export_dynamic_flag_spec_CXX='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ archive_cmds_CXX='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ old_archive_cmds_CXX='$CC -Tprelink_objects $oldobjs~
+ '"$old_archive_cmds_CXX"
+ reload_cmds_CXX='$CC -Tprelink_objects $reload_objs~
+ '"$reload_cmds_CXX"
+ ;;
+ *)
+ archive_cmds_CXX='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ archive_expsym_cmds_CXX='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ ld_shlibs_CXX=no
+ ;;
+ esac
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+ test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+ GCC_CXX="$GXX"
+ LD_CXX="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ # Dependencies to place before and after the object being linked:
+predep_objects_CXX=
+postdep_objects_CXX=
+predeps_CXX=
+postdeps_CXX=
+compiler_lib_search_path_CXX=
+
+cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case ${prev}${p} in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test "$pre_test_object_deps_done" = no; then
+ case ${prev} in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$compiler_lib_search_path_CXX"; then
+ compiler_lib_search_path_CXX="${prev}${p}"
+ else
+ compiler_lib_search_path_CXX="${compiler_lib_search_path_CXX} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$postdeps_CXX"; then
+ postdeps_CXX="${prev}${p}"
+ else
+ postdeps_CXX="${postdeps_CXX} ${prev}${p}"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$predep_objects_CXX"; then
+ predep_objects_CXX="$p"
+ else
+ predep_objects_CXX="$predep_objects_CXX $p"
+ fi
+ else
+ if test -z "$postdep_objects_CXX"; then
+ postdep_objects_CXX="$p"
+ else
+ postdep_objects_CXX="$postdep_objects_CXX $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling CXX test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+case $host_os in
+interix[3-9]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ predep_objects_CXX=
+ postdep_objects_CXX=
+ postdeps_CXX=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ postdeps_CXX='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+
+
+case " $postdeps_CXX " in
+*" -lc "*) archive_cmds_need_lc_CXX=no ;;
+esac
+ compiler_lib_search_dirs_CXX=
+if test -n "${compiler_lib_search_path_CXX}"; then
+ compiler_lib_search_dirs_CXX=`echo " ${compiler_lib_search_path_CXX}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ lt_prog_compiler_wl_CXX=
+lt_prog_compiler_pic_CXX=
+lt_prog_compiler_static_CXX=
+
+
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ lt_prog_compiler_pic_CXX='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ lt_prog_compiler_pic_CXX='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ lt_prog_compiler_pic_CXX=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ lt_prog_compiler_static_CXX=
+ ;;
+ interix[3-9]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ lt_prog_compiler_pic_CXX=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[4-9]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ lt_prog_compiler_static_CXX='-Bstatic'
+ else
+ lt_prog_compiler_static_CXX='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, CXX)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ lt_prog_compiler_pic_CXX='-DDLL_EXPORT'
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ lt_prog_compiler_pic_CXX='+Z'
+ fi
+ ;;
+ aCC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_static_CXX='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fPIC'
+ lt_prog_compiler_static_CXX='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-fpic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[cC]* | mpixl[cC]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-qpic'
+ lt_prog_compiler_static_CXX='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ lt_prog_compiler_pic_CXX='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ lt_prog_compiler_pic_CXX='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ lt_prog_compiler_wl_CXX='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ lt_prog_compiler_wl_CXX='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_static_CXX='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ lt_prog_compiler_wl_CXX='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ lt_prog_compiler_pic_CXX='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ lt_prog_compiler_pic_CXX='-pic'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ lt_prog_compiler_pic_CXX='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ lt_prog_compiler_wl_CXX='-Wl,'
+ lt_prog_compiler_pic_CXX='-KPIC'
+ lt_prog_compiler_static_CXX='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ lt_prog_compiler_pic_CXX='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ lt_prog_compiler_can_build_shared_CXX=no
+ ;;
+ esac
+ fi
+
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ lt_prog_compiler_pic_CXX=
+ ;;
+ *)
+ lt_prog_compiler_pic_CXX="$lt_prog_compiler_pic_CXX -DPIC"
+ ;;
+esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $compiler option to produce PIC" >&5
+$as_echo_n "checking for $compiler option to produce PIC... " >&6; }
+if ${lt_cv_prog_compiler_pic_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_CXX=$lt_prog_compiler_pic_CXX
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_CXX" >&6; }
+lt_prog_compiler_pic_CXX=$lt_cv_prog_compiler_pic_CXX
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$lt_prog_compiler_pic_CXX"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works" >&5
+$as_echo_n "checking if $compiler PIC flag $lt_prog_compiler_pic_CXX works... " >&6; }
+if ${lt_cv_prog_compiler_pic_works_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_pic_works_CXX=no
+ ac_outfile=conftest.$ac_objext
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$lt_prog_compiler_pic_CXX -DPIC"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_pic_works_CXX=yes
+ fi
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_pic_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_pic_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_pic_works_CXX" = xyes; then
+ case $lt_prog_compiler_pic_CXX in
+ "" | " "*) ;;
+ *) lt_prog_compiler_pic_CXX=" $lt_prog_compiler_pic_CXX" ;;
+ esac
+else
+ lt_prog_compiler_pic_CXX=
+ lt_prog_compiler_can_build_shared_CXX=no
+fi
+
+fi
+
+
+
+
+
+#
+# Check to make sure the static flag actually works.
+#
+wl=$lt_prog_compiler_wl_CXX eval lt_tmp_static_flag=\"$lt_prog_compiler_static_CXX\"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler static flag $lt_tmp_static_flag works" >&5
+$as_echo_n "checking if $compiler static flag $lt_tmp_static_flag works... " >&6; }
+if ${lt_cv_prog_compiler_static_works_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_static_works_CXX=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $lt_tmp_static_flag"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&5
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ else
+ lt_cv_prog_compiler_static_works_CXX=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_static_works_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_static_works_CXX" >&6; }
+
+if test x"$lt_cv_prog_compiler_static_works_CXX" = xyes; then
+ :
+else
+ lt_prog_compiler_static_CXX=
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if $compiler supports -c -o file.$ac_objext" >&5
+$as_echo_n "checking if $compiler supports -c -o file.$ac_objext... " >&6; }
+if ${lt_cv_prog_compiler_c_o_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_prog_compiler_c_o_CXX=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [^ ]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&5)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&5
+ echo "$as_me:$LINENO: \$? = $ac_status" >&5
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ lt_cv_prog_compiler_c_o_CXX=yes
+ fi
+ fi
+ chmod u+w . 2>&5
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_compiler_c_o_CXX" >&5
+$as_echo "$lt_cv_prog_compiler_c_o_CXX" >&6; }
+
+
+
+
+hard_links="nottested"
+if test "$lt_cv_prog_compiler_c_o_CXX" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we can lock with hard links" >&5
+$as_echo_n "checking if we can lock with hard links... " >&6; }
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $hard_links" >&5
+$as_echo "$hard_links" >&6; }
+ if test "$hard_links" = no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&5
+$as_echo "$as_me: WARNING: \`$CC' does not support \`-c -o', so \`make -j' may be unsafe" >&2;}
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether the $compiler linker ($LD) supports shared libraries" >&5
+$as_echo_n "checking whether the $compiler linker ($LD) supports shared libraries... " >&6; }
+
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms_CXX='_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*'
+ case $host_os in
+ aix[4-9]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ export_symbols_cmds_CXX='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ export_symbols_cmds_CXX='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && (substr(\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ export_symbols_cmds_CXX="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ exclude_expsyms_CXX='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[BCDGRS][ ]/s/.*[ ]\([^ ]*\)/\1 DATA/;s/^.*[ ]__nm__\([^ ]*\)[ ][^ ]*/\1 DATA/;/^I[ ]/d;/^[AITW][ ]/s/.* //'\'' | sort | uniq > $export_symbols'
+ exclude_expsyms_CXX='[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname'
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ link_all_deplibs_CXX=no
+ ;;
+ *)
+ export_symbols_cmds_CXX='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ld_shlibs_CXX" >&5
+$as_echo "$ld_shlibs_CXX" >&6; }
+test "$ld_shlibs_CXX" = no && can_build_shared=no
+
+with_gnu_ld_CXX=$with_gnu_ld
+
+
+
+
+
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$archive_cmds_need_lc_CXX" in
+x|xyes)
+ # Assume -lc should be added
+ archive_cmds_need_lc_CXX=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $archive_cmds_CXX in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether -lc should be explicitly linked in" >&5
+$as_echo_n "checking whether -lc should be explicitly linked in... " >&6; }
+if ${lt_cv_archive_cmds_need_lc_CXX+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ $RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_compile\""; } >&5
+ (eval $ac_compile) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$lt_prog_compiler_wl_CXX
+ pic_flag=$lt_prog_compiler_pic_CXX
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$allow_undefined_flag_CXX
+ allow_undefined_flag_CXX=
+ if { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1\""; } >&5
+ (eval $archive_cmds_CXX 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1) 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }
+ then
+ lt_cv_archive_cmds_need_lc_CXX=no
+ else
+ lt_cv_archive_cmds_need_lc_CXX=yes
+ fi
+ allow_undefined_flag_CXX=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_archive_cmds_need_lc_CXX" >&5
+$as_echo "$lt_cv_archive_cmds_need_lc_CXX" >&6; }
+ archive_cmds_need_lc_CXX=$lt_cv_archive_cmds_need_lc_CXX
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking dynamic linker characteristics" >&5
+$as_echo_n "checking dynamic linker characteristics... " >&6; }
+
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[4-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[01] | aix4.[01].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([^/]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[45]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([a-zA-Z]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | $GREP ';[c-zC-Z]:/' >/dev/null; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[.]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[23].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[01]* | freebsdelf3.[01]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[2-9]* | freebsdelf3.[2-9]* | \
+ freebsd4.[0-5] | freebsdelf4.[0-5] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[3-9]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ if ${lt_cv_shlibpath_overrides_runpath+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$lt_prog_compiler_wl_CXX\"; \
+ LDFLAGS=\"\$LDFLAGS $hardcode_libdir_flag_spec_CXX\""
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ if ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null; then :
+ lt_cv_shlibpath_overrides_runpath=yes
+fi
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+
+fi
+
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \$2)); skip = 1; } { if (!skip) print \$0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[89] | openbsd2.[89].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $dynamic_linker" >&5
+$as_echo "$dynamic_linker" >&6; }
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking how to hardcode library paths into programs" >&5
+$as_echo_n "checking how to hardcode library paths into programs... " >&6; }
+hardcode_action_CXX=
+if test -n "$hardcode_libdir_flag_spec_CXX" ||
+ test -n "$runpath_var_CXX" ||
+ test "X$hardcode_automatic_CXX" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$hardcode_direct_CXX" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, CXX)" != no &&
+ test "$hardcode_minus_L_CXX" != no; then
+ # Linking always hardcodes the temporary library directory.
+ hardcode_action_CXX=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ hardcode_action_CXX=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ hardcode_action_CXX=unsupported
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $hardcode_action_CXX" >&5
+$as_echo "$hardcode_action_CXX" >&6; }
+
+if test "$hardcode_action_CXX" = relink ||
+ test "$inherit_rpath_CXX" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+
+
+
+
+
+
+
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether struct tm is in sys/time.h or time.h" >&5
+$as_echo_n "checking whether struct tm is in sys/time.h or time.h... " >&6; }
+if ${ac_cv_struct_tm+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <time.h>
+
+int
+main ()
+{
+struct tm tm;
+ int *p = &tm.tm_sec;
+ return !p;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_struct_tm=time.h
+else
+ ac_cv_struct_tm=sys/time.h
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm" >&5
+$as_echo "$ac_cv_struct_tm" >&6; }
+if test $ac_cv_struct_tm = sys/time.h; then
+
+$as_echo "#define TM_IN_SYS_TIME 1" >>confdefs.h
+
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for tm_gmtoff in struct tm" >&5
+$as_echo_n "checking for tm_gmtoff in struct tm... " >&6; }
+if ${ac_cv_struct_tm_gmtoff+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <sys/types.h>
+#include <$ac_cv_struct_tm>
+int
+main ()
+{
+struct tm tm; tm.tm_gmtoff;
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_cv_struct_tm_gmtoff=yes
+else
+ ac_cv_struct_tm_gmtoff=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_struct_tm_gmtoff" >&5
+$as_echo "$ac_cv_struct_tm_gmtoff" >&6; }
+if test "$ac_cv_struct_tm_gmtoff" = yes; then
+
+$as_echo "#define HAVE_TM_GMTOFF 1" >>confdefs.h
+
+fi
+
+
+# Define full_libdir to be the fully expanded (${exec_prefix}, etc.)
+# "system" library path.
+# We use this to search for other libraries.
+eval full_libdir="\"$libdir\""
+
+# detect pkg-config explicitly
+
+
+
+
+
+
+
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+ ac_pt_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $ac_pt_PKG_CONFIG in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_pt_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_pt_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+fi
+
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=0.9.0
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ PKG_CONFIG=""
+ fi
+fi
+
+for ac_header in sys/mman.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "sys/mman.h" "ac_cv_header_sys_mman_h" "$ac_includes_default"
+if test "x$ac_cv_header_sys_mman_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_SYS_MMAN_H 1
+_ACEOF
+ ac_fn_cxx_check_func "$LINENO" "mmap" "ac_cv_func_mmap"
+if test "x$ac_cv_func_mmap" = xyes; then :
+
+$as_echo "#define HAVE_MMAP 1" >>confdefs.h
+
+else
+ have_mmap=no
+
+fi
+
+else
+ have_mmap=no
+
+fi
+
+done
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in Botan 1.10" >&5
+$as_echo_n "checking whether we will be linking in Botan 1.10... " >&6; }
+ # Check whether --enable-botan1.10 was given.
+if test "${enable_botan1_10+set}" = set; then :
+ enableval=$enable_botan1_10; enable_botan110=$enableval
+else
+ enable_botan110=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_botan110" >&5
+$as_echo "$enable_botan110" >&6; }
+ if test "x$enable_botan110" != "xno"; then
+ BOTAN110_TRUE=
+ BOTAN110_FALSE='#'
+else
+ BOTAN110_TRUE='#'
+ BOTAN110_FALSE=
+fi
+
+
+
+ if test "x$enable_botan110" != "xno"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BOTAN110" >&5
+$as_echo_n "checking for BOTAN110... " >&6; }
+
+if test -n "$BOTAN110_CFLAGS"; then
+ pkg_cv_BOTAN110_CFLAGS="$BOTAN110_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"botan-1.10\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "botan-1.10") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_BOTAN110_CFLAGS=`$PKG_CONFIG --cflags "botan-1.10" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$BOTAN110_LIBS"; then
+ pkg_cv_BOTAN110_LIBS="$BOTAN110_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"botan-1.10\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "botan-1.10") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_BOTAN110_LIBS=`$PKG_CONFIG --libs "botan-1.10" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ BOTAN110_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "botan-1.10" 2>&1`
+ else
+ BOTAN110_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "botan-1.10" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$BOTAN110_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find botan 1.10" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find botan 1.10" "$LINENO" 5
+
+else
+ BOTAN110_CFLAGS=$pkg_cv_BOTAN110_CFLAGS
+ BOTAN110_LIBS=$pkg_cv_BOTAN110_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_BOTAN110 1" >>confdefs.h
+
+fi
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libsodium" >&5
+$as_echo_n "checking whether we will be linking in libsodium... " >&6; }
+ # Check whether --enable-libsodium was given.
+if test "${enable_libsodium+set}" = set; then :
+ enableval=$enable_libsodium; enable_libsodium=$enableval
+else
+ enable_libsodium=no
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libsodium" >&5
+$as_echo "$enable_libsodium" >&6; }
+
+ if test "x$enable_libsodium" != "xno"; then
+ LIBSODIUM_TRUE=
+ LIBSODIUM_FALSE='#'
+else
+ LIBSODIUM_TRUE='#'
+ LIBSODIUM_FALSE=
+fi
+
+
+ if test -z "$LIBSODIUM_TRUE"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBSODIUM" >&5
+$as_echo_n "checking for LIBSODIUM... " >&6; }
+
+if test -n "$LIBSODIUM_CFLAGS"; then
+ pkg_cv_LIBSODIUM_CFLAGS="$LIBSODIUM_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libsodium") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBSODIUM_CFLAGS=`$PKG_CONFIG --cflags "libsodium" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LIBSODIUM_LIBS"; then
+ pkg_cv_LIBSODIUM_LIBS="$LIBSODIUM_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libsodium\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libsodium") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBSODIUM_LIBS=`$PKG_CONFIG --libs "libsodium" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libsodium" 2>&1`
+ else
+ LIBSODIUM_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libsodium" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBSODIUM_PKG_ERRORS" >&5
+
+
+ as_fn_error $? "libsodium requested but not available" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ as_fn_error $? "libsodium requested but not available" "$LINENO" 5
+
+else
+ LIBSODIUM_CFLAGS=$pkg_cv_LIBSODIUM_CFLAGS
+ LIBSODIUM_LIBS=$pkg_cv_LIBSODIUM_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_LIBSODIUM 1" >>confdefs.h
+
+
+fi
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be linking in libdecaf" >&5
+$as_echo_n "checking whether we will be linking in libdecaf... " >&6; }
+ # Check whether --enable-libdecaf was given.
+if test "${enable_libdecaf+set}" = set; then :
+ enableval=$enable_libdecaf; enable_libdecaf=$enableval
+else
+ enable_libdecaf=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_libdecaf" >&5
+$as_echo "$enable_libdecaf" >&6; }
+
+ if test "x$enable_libdecaf" != "xno"; then
+ LIBDECAF_TRUE=
+ LIBDECAF_FALSE='#'
+else
+ LIBDECAF_TRUE='#'
+ LIBDECAF_FALSE=
+fi
+
+
+ if test "x$enable_libdecaf" != "xno"; then :
+
+ save_LIBS=$LIBS
+ LIBS=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing decaf_ed25519_sign" >&5
+$as_echo_n "checking for library containing decaf_ed25519_sign... " >&6; }
+if ${ac_cv_search_decaf_ed25519_sign+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char decaf_ed25519_sign ();
+int
+main ()
+{
+return decaf_ed25519_sign ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' decaf; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_decaf_ed25519_sign=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_decaf_ed25519_sign+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_decaf_ed25519_sign+:} false; then :
+
+else
+ ac_cv_search_decaf_ed25519_sign=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_decaf_ed25519_sign" >&5
+$as_echo "$ac_cv_search_decaf_ed25519_sign" >&6; }
+ac_res=$ac_cv_search_decaf_ed25519_sign
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+
+$as_echo "#define HAVE_LIBDECAF 1" >>confdefs.h
+
+ LIBDECAF_LIBS="$LIBS"
+
+
+else
+
+ as_fn_error $? "Could not find libdecaf" "$LINENO" 5
+
+fi
+
+ LIBS="$save_LIBS"
+
+fi
+
+
+ found=false
+
+# Check whether --with-libcrypto was given.
+if test "${with_libcrypto+set}" = set; then :
+ withval=$with_libcrypto;
+ case "$withval" in
+ "" | y | ye | yes | n | no)
+ as_fn_error $? "Invalid --with-libcrypto value" "$LINENO" 5
+ ;;
+ *) ssldirs="$withval"
+ ;;
+ esac
+
+else
+
+ # if pkg-config is installed and openssl has installed a .pc file,
+ # then use that information and don't search ssldirs
+ if test -n "$ac_tool_prefix"; then
+ # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PKG_CONFIG"; then
+ ac_cv_prog_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PKG_CONFIG="${ac_tool_prefix}pkg-config"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PKG_CONFIG=$ac_cv_prog_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+fi
+if test -z "$ac_cv_prog_PKG_CONFIG"; then
+ ac_ct_PKG_CONFIG=$PKG_CONFIG
+ # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_PKG_CONFIG+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$ac_ct_PKG_CONFIG"; then
+ ac_cv_prog_ac_ct_PKG_CONFIG="$ac_ct_PKG_CONFIG" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_ac_ct_PKG_CONFIG="pkg-config"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_PKG_CONFIG=$ac_cv_prog_ac_ct_PKG_CONFIG
+if test -n "$ac_ct_PKG_CONFIG"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_PKG_CONFIG" >&5
+$as_echo "$ac_ct_PKG_CONFIG" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+ if test "x$ac_ct_PKG_CONFIG" = x; then
+ PKG_CONFIG=""
+ else
+ case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+ PKG_CONFIG=$ac_ct_PKG_CONFIG
+ fi
+else
+ PKG_CONFIG="$ac_cv_prog_PKG_CONFIG"
+fi
+
+ if test x"$PKG_CONFIG" != x""; then
+ LIBCRYPTO_LDFLAGS=`$PKG_CONFIG libcrypto --libs-only-L 2>/dev/null`
+ if test $? = 0; then
+ LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null`
+ LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null`
+ ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null`
+ found=true
+ fi
+ fi
+
+ # no such luck; use some default ssldirs
+ if ! $found; then
+ ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
+ fi
+
+
+fi
+
+
+
+ # note that we #include <openssl/foo.h>, so the OpenSSL headers have to be in
+ # an 'openssl' subdirectory
+
+ if ! $found; then
+ LIBCRYPTO_INCLUDES=
+ for ssldir in $ssldirs; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for openssl/crypto.h in $ssldir" >&5
+$as_echo_n "checking for openssl/crypto.h in $ssldir... " >&6; }
+ if test -f "$ssldir/include/openssl/crypto.h"; then
+ LIBCRYPTO_INCLUDES="-I$ssldir/include"
+ LIBCRYPTO_LDFLAGS="-L$ssldir/lib"
+ LIBCRYPTO_LIBS="-lcrypto"
+ found=true
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ break
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ fi
+ done
+
+ # if the file wasn't found, well, go ahead and try the link anyway -- maybe
+ # it will just work!
+ fi
+
+ # try the preprocessor and linker with our new flags,
+ # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether compiling and linking against OpenSSL's libcrypto works" >&5
+$as_echo_n "checking whether compiling and linking against OpenSSL's libcrypto works... " >&6; }
+ echo "Trying link with LIBCRYPTO_LDFLAGS=$LIBCRYPTO_LDFLAGS;" \
+ "LIBCRYPTO_LIBS=$LIBCRYPTO_LIBS; LIBCRYPTO_INCLUDES=$LIBCRYPTO_INCLUDES" >&5
+
+ save_LIBS="$LIBS"
+ save_LDFLAGS="$LDFLAGS"
+ save_CPPFLAGS="$CPPFLAGS"
+ LDFLAGS="$LDFLAGS $LIBCRYPTO_LDFLAGS"
+ LIBS="$LIBCRYPTO_LIBS $LIBS"
+ CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <openssl/crypto.h>
+int
+main ()
+{
+ERR_load_CRYPTO_strings()
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ as_fn_error $? "OpenSSL/libcrypto not found" "$LINENO" 5
+
+
+
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+
+
+
+
+
+
+
+
+ # Set the environment correctly for a possibly non-default OpenSSL path that was found by/supplied to PDNS_CHECK_LIBCRYPTO
+ save_CPPFLAGS="$CPPFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ save_LIBS="$LIBS"
+
+ CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS"
+ LDFLAGS="$LIBCRYPTO_LDFLAGS $LDFLAGS"
+ LIBS="$LIBCRYPTO_LIBS $LIBS"
+
+ # Find the headers we need for ECDSA
+ libcrypto_ecdsa=yes
+ as_ac_Header=`$as_echo "ac_cv_header_$ssldir/include/openssl/ecdsa.h" | $as_tr_sh`
+ac_fn_cxx_check_header_mongrel "$LINENO" "$ssldir/include/openssl/ecdsa.h" "$as_ac_Header" "$ac_includes_default"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+
+ ac_fn_cxx_check_decl "$LINENO" "NID_X9_62_prime256v1" "ac_cv_have_decl_NID_X9_62_prime256v1" "$ac_includes_default
+#include <$ssldir/include/openssl/evp.h>
+
+"
+if test "x$ac_cv_have_decl_NID_X9_62_prime256v1" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NID_X9_62_PRIME256V1 $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+ :
+else
+
+ libcrypto_ecdsa=no
+
+fi
+ac_fn_cxx_check_decl "$LINENO" "NID_secp384r1" "ac_cv_have_decl_NID_secp384r1" "$ac_includes_default
+#include <$ssldir/include/openssl/evp.h>
+
+"
+if test "x$ac_cv_have_decl_NID_secp384r1" = xyes; then :
+ ac_have_decl=1
+else
+ ac_have_decl=0
+fi
+
+cat >>confdefs.h <<_ACEOF
+#define HAVE_DECL_NID_SECP384R1 $ac_have_decl
+_ACEOF
+if test $ac_have_decl = 1; then :
+ :
+else
+
+ libcrypto_ecdsa=no
+
+fi
+
+
+else
+
+ libcrypto_ecdsa=no
+
+fi
+
+
+
+ if test "x$libcrypto_ecdsa" = "xyes"; then :
+
+
+$as_echo "#define HAVE_LIBCRYPTO_ECDSA 1" >>confdefs.h
+
+
+fi
+
+ # Restore variables
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+
+
+
+ # Extract the first word of "ragel", so it can be a program name with args.
+set dummy ragel; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_RAGEL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$RAGEL"; then
+ ac_cv_prog_RAGEL="$RAGEL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_RAGEL="ragel"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+RAGEL=$ac_cv_prog_RAGEL
+if test -n "$RAGEL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $RAGEL" >&5
+$as_echo "$RAGEL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ if test "x$RAGEL" = "x"; then
+ if test ! -f "${srcdir}/pdns/dnslabeltext.cc"; then
+ as_fn_error $? "ragel is missing and you don't have ${srcdir}/pdns/dnslabeltext.cc. Install ragel or download sources from www.powerdns.com" "$LINENO" 5
+ fi
+ fi
+
+
+ OLD_LIBS="$LIBS"; LIBS=""
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for library containing clock_gettime" >&5
+$as_echo_n "checking for library containing clock_gettime... " >&6; }
+if ${ac_cv_search_clock_gettime+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_func_search_save_LIBS=$LIBS
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char clock_gettime ();
+int
+main ()
+{
+return clock_gettime ();
+ ;
+ return 0;
+}
+_ACEOF
+for ac_lib in '' rt; do
+ if test -z "$ac_lib"; then
+ ac_res="none required"
+ else
+ ac_res=-l$ac_lib
+ LIBS="-l$ac_lib $ac_func_search_save_LIBS"
+ fi
+ if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_search_clock_gettime=$ac_res
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext
+ if ${ac_cv_search_clock_gettime+:} false; then :
+ break
+fi
+done
+if ${ac_cv_search_clock_gettime+:} false; then :
+
+else
+ ac_cv_search_clock_gettime=no
+fi
+rm conftest.$ac_ext
+LIBS=$ac_func_search_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_search_clock_gettime" >&5
+$as_echo "$ac_cv_search_clock_gettime" >&6; }
+ac_res=$ac_cv_search_clock_gettime
+if test "$ac_res" != no; then :
+ test "$ac_res" = "none required" || LIBS="$ac_res $LIBS"
+
+$as_echo "#define HAVE_CLOCK_GETTIME 1" >>confdefs.h
+
+fi
+
+ RT_LIBS=$LIBS
+
+ LIBS="$OLD_LIBS"
+
+
+echo "$as_me: this is boost.m4 serial 26 PowerDNS modified" >&5
+boost_save_IFS=$IFS
+boost_version_req=1.35
+IFS=.
+set x $boost_version_req 0 0 0
+IFS=$boost_save_IFS
+shift
+boost_version_req=`expr "$1" '*' 100000 + "$2" '*' 100 + "$3"`
+boost_version_req_string=$1.$2.$3
+
+# Check whether --with-boost was given.
+if test "${with_boost+set}" = set; then :
+ withval=$with_boost;
+fi
+# If BOOST_ROOT is set and the user has not provided a value to
+# --with-boost, then treat BOOST_ROOT as if it the user supplied it.
+if test x"$BOOST_ROOT" != x; then
+ if test x"$with_boost" = x; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&5
+$as_echo "$as_me: Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT" >&6;}
+ with_boost=$BOOST_ROOT
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&5
+$as_echo "$as_me: Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost" >&6;}
+ fi
+fi
+DISTCHECK_CONFIGURE_FLAGS="$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'"
+boost_save_CPPFLAGS=$CPPFLAGS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost headers version >= $boost_version_req_string" >&5
+$as_echo_n "checking for Boost headers version >= $boost_version_req_string... " >&6; }
+if ${boost_cv_inc_path+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_inc_path=no
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/version.hpp>
+#if !defined BOOST_VERSION
+# error BOOST_VERSION is not defined
+#elif BOOST_VERSION < $boost_version_req
+# error Boost headers version < $boost_version_req
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+ # If the user provided a value to --with-boost, use it and only it.
+ case $with_boost in #(
+ ''|yes) set x '' /opt/local/include /usr/local/include /opt/include \
+ /usr/include C:/Boost/include;; #(
+ *) set x "$with_boost/include" "$with_boost";;
+ esac
+ shift
+ for boost_dir
+ do
+ # Without --layout=system, Boost (or at least some versions) installs
+ # itself in <prefix>/include/boost-<version>. This inner loop helps to
+ # find headers in such directories.
+ #
+ # Any ${boost_dir}/boost-x_xx directories are searched in reverse version
+ # order followed by ${boost_dir}. The final '.' is a sentinel for
+ # searching $boost_dir" itself. Entries are whitespace separated.
+ #
+ # I didn't indent this loop on purpose (to avoid over-indented code)
+ boost_layout_system_search_list=`cd "$boost_dir" 2>/dev/null \
+ && ls -1 | "${GREP}" '^boost-' | sort -rn -t- -k2 \
+ && echo .`
+ for boost_inc in $boost_layout_system_search_list
+ do
+ if test x"$boost_inc" != x.; then
+ boost_inc="$boost_dir/$boost_inc"
+ else
+ boost_inc="$boost_dir" # Uses sentinel in boost_layout_system_search_list
+ fi
+ if test x"$boost_inc" != x; then
+ # We are going to check whether the version of Boost installed
+ # in $boost_inc is usable by running a compilation that
+ # #includes it. But if we pass a -I/some/path in which Boost
+ # is not installed, the compiler will just skip this -I and
+ # use other locations (either from CPPFLAGS, or from its list
+ # of system include directories). As a result we would use
+ # header installed on the machine instead of the /some/path
+ # specified by the user. So in that precise case (trying
+ # $boost_inc), make sure the version.hpp exists.
+ #
+ # Use test -e as there can be symlinks.
+ test -e "$boost_inc/boost/version.hpp" || continue
+ CPPFLAGS="$CPPFLAGS -I$boost_inc"
+ fi
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ boost_cv_inc_path=yes
+else
+ boost_cv_version=no
+fi
+rm -f core conftest.err conftest.$ac_objext
+ if test x"$boost_cv_inc_path" = xyes; then
+ if test x"$boost_inc" != x; then
+ boost_cv_inc_path=$boost_inc
+ fi
+ break 2
+ fi
+ done
+ done
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_inc_path" >&5
+$as_echo "$boost_cv_inc_path" >&6; }
+ case $boost_cv_inc_path in #(
+ no)
+ boost_errmsg="cannot find Boost headers version >= $boost_version_req_string"
+ as_fn_error $? "$boost_errmsg" "$LINENO" 5
+
+ ;;#(
+ yes)
+ BOOST_CPPFLAGS=
+ ;;#(
+ *)
+ BOOST_CPPFLAGS="-I$boost_cv_inc_path"
+ ;;
+ esac
+ if test x"$boost_cv_inc_path" != xno; then
+
+$as_echo "#define HAVE_BOOST 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for Boost's header version" >&5
+$as_echo_n "checking for Boost's header version... " >&6; }
+if ${boost_cv_lib_version+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/version.hpp>
+boost-lib-version = BOOST_LIB_VERSION
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+ grep -v '#' |
+ grep -v '^[[:space:]]*$' |
+ tr -d '\r' |
+ tr -s '\n' ' ' |
+ $SED -n -e "/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}" >conftest.i 2>&1; then :
+ boost_cv_lib_version=`cat conftest.i`
+fi
+rm -rf conftest*
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_version" >&5
+$as_echo "$boost_cv_lib_version" >&6; }
+ # e.g. "134" for 1_34_1 or "135" for 1_35
+ boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'`
+ case $boost_major_version in #(
+ '' | *[!0-9]*)
+ as_fn_error $? "invalid value: boost_major_version='$boost_major_version'" "$LINENO" 5
+ ;;
+ esac
+fi
+CPPFLAGS=$boost_save_CPPFLAGS
+
+# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+
+# to be compatible with C++11
+ if test "$boost_major_version" -ge 148; then
+ HAVE_BOOST_GE_148_TRUE=
+ HAVE_BOOST_GE_148_FALSE='#'
+else
+ HAVE_BOOST_GE_148_TRUE='#'
+ HAVE_BOOST_GE_148_FALSE=
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the toolset name used by Boost for $CXX" >&5
+$as_echo_n "checking for the toolset name used by Boost for $CXX... " >&6; }
+if ${boost_cv_lib_tag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_tag=unknown
+if test x$boost_cv_inc_path != xno; then
+ ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+ # The following tests are mostly inspired by boost/config/auto_link.hpp
+ # The list is sorted to most recent/common to oldest compiler (in order
+ # to increase the likelihood of finding the right compiler with the
+ # least number of compilation attempt).
+ # Beware that some tests are sensible to the order (for instance, we must
+ # look for MinGW before looking for GCC3).
+ # I used one compilation test per compiler with a #error to recognize
+ # each compiler so that it works even when cross-compiling (let me know
+ # if you know a better approach).
+ # Known missing tags (known from Boost's tools/build/v2/tools/common.jam):
+ # como, edg, kcc, bck, mp, sw, tru, xlc
+ # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
+ # the same defines as GCC's).
+ for i in \
+ "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw71" \
+ "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc71" \
+ "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw70" \
+ "defined __GNUC__ && __GNUC__ == 7 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc70" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw63" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc63" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw62" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc62" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw61" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc61" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw60" \
+ "defined __GNUC__ && __GNUC__ == 6 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc60" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw54" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc54" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw53" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc53" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw52" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc52" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw51" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc51" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw50" \
+ "defined __GNUC__ && __GNUC__ == 5 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc50" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw410" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 10 && !defined __ICC @ gcc410" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw49" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 9 && !defined __ICC @ gcc49" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw48" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 8 && !defined __ICC @ gcc48" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw47" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 7 && !defined __ICC @ gcc47" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw46" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 6 && !defined __ICC @ gcc46" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw45" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 5 && !defined __ICC @ gcc45" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw44" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc44" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw43" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc43" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw42" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc42" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw41" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc41" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw40" \
+ "defined __GNUC__ && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc40" \
+ "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \
+ && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 4 && !defined __ICC @ gcc34" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 3 && !defined __ICC @ gcc33" \
+ "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \
+ "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 2 && !defined __ICC @ gcc32" \
+ "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 1 && !defined __ICC @ gcc31" \
+ "defined __GNUC__ && __GNUC__ == 3 && __GNUC_MINOR__ == 0 && !defined __ICC @ gcc30" \
+ "defined __BORLANDC__ @ bcb" \
+ "defined __ICC && (defined __unix || defined ) @ il" \
+ "defined __ICL @ iw" \
+ "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \
+ "defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ == 95 && !defined __ICC @ gcc295" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \
+ "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \
+ "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8"
+ do
+ boost_tag_test=`expr "X$i" : 'X\([^@]*\) @ '`
+ boost_tag=`expr "X$i" : 'X[^@]* @ \(.*\)'`
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if $boost_tag_test
+/* OK */
+#else
+# error $boost_tag_test
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ boost_cv_lib_tag=$boost_tag; break
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ done
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+ case $boost_cv_lib_tag in #(
+ # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed
+ # to "gcc41" for instance.
+ *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there.
+ gcc*)
+ boost_tag_x=
+ case $host_os in #(
+ darwin*)
+ if test $boost_major_version -ge 136; then
+ # The `x' added in r46793 of Boost.
+ boost_tag_x=x
+ fi;;
+ esac
+ # We can specify multiple tags in this variable because it's used by
+ # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ...
+ boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
+ ;; #(
+ unknown)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: could not figure out which toolset name to use for $CXX" >&5
+$as_echo "$as_me: WARNING: could not figure out which toolset name to use for $CXX" >&2;}
+ boost_cv_lib_tag=
+ ;;
+ esac
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_tag" >&5
+$as_echo "$boost_cv_lib_tag" >&6; }
+# Check whether --enable-static-boost was given.
+if test "${enable_static_boost+set}" = set; then :
+ enableval=$enable_static_boost; enable_static_boost=yes
+else
+ enable_static_boost=no
+fi
+
+# Check whether we do better use `mt' even though we weren't ask to.
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+#if defined _REENTRANT || defined _MT || defined __MT__
+/* use -mt */
+#else
+# error MT not needed
+#endif
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_compile "$LINENO"; then :
+ boost_guess_use_mt=:
+else
+ boost_guess_use_mt=false
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost program_options library" >&5
+$as_echo "$as_me: Boost not available, not searching for the Boost program_options library" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/program_options.hpp" >&5
+$as_echo "$as_me: Boost not available, not searching for boost/program_options.hpp" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ac_fn_cxx_check_header_mongrel "$LINENO" "boost/program_options.hpp" "ac_cv_header_boost_program_options_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_program_options_hpp" = xyes; then :
+
+$as_echo "#define HAVE_BOOST_PROGRAM_OPTIONS_HPP 1" >>confdefs.h
+
+else
+ as_fn_error $? "cannot find boost/program_options.hpp" "$LINENO" 5
+fi
+
+
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost program_options library" >&5
+$as_echo_n "checking for the Boost program_options library... " >&6; }
+if ${boost_cv_lib_program_options+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_program_options=no
+ case "mt" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "Xmt" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=mt;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/program_options.hpp>
+
+int
+main ()
+{
+boost::program_options::options_description d("test");
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_objext=do_not_rm_me_plz
+else
+ as_fn_error $? "cannot compile a test that uses Boost program_options" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in program_options; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ boost_cv_lib_program_options_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$boost_cv_lib_program_options_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ boost_cv_lib_program_options_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$boost_cv_lib_program_options_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_cv_lib_program_options=yes
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_cv_lib_program_options=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$boost_cv_lib_program_options" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ if ${boost_cv_rpath_link_ldflag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $boost_cv_lib_program_options_LIBS"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_rpath_link_ldflag_found=yes
+ break
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_rpath_link_ldflag_found=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ done
+ ;;
+ esac
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
+fi
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+
+fi
+
+ test x"$boost_ldpath" != x &&
+ boost_cv_lib_program_options_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ boost_cv_lib_program_options_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_program_options" >&5
+$as_echo "$boost_cv_lib_program_options" >&6; }
+case $boost_cv_lib_program_options in #(
+ (yes) $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+$as_echo "#define HAVE_BOOST_PROGRAM_OPTIONS 1" >>confdefs.h
+ BOOST_PROGRAM_OPTIONS_LDFLAGS=$boost_cv_lib_program_options_LDFLAGS
+ BOOST_PROGRAM_OPTIONS_LDPATH=$boost_cv_lib_program_options_LDPATH
+ BOOST_LDPATH=$boost_cv_lib_program_options_LDPATH
+ BOOST_PROGRAM_OPTIONS_LIBS=$boost_cv_lib_program_options_LIBS
+ ;;
+esac
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+
+
+if test "$boost_cv_lib_program_options" = "no"; then :
+
+ as_fn_error $? "Boost Program Options library not found" "$LINENO" 5
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable unit test building" >&5
+$as_echo_n "checking whether to enable unit test building... " >&6; }
+ # Check whether --enable-unit-tests was given.
+if test "${enable_unit_tests+set}" = set; then :
+ enableval=$enable_unit_tests; enable_unit_tests=$enableval
+else
+ enable_unit_tests=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_unit_tests" >&5
+$as_echo "$enable_unit_tests" >&6; }
+ if test "x$enable_unit_tests" != "xno"; then
+ UNIT_TESTS_TRUE=
+ UNIT_TESTS_FALSE='#'
+else
+ UNIT_TESTS_TRUE='#'
+ UNIT_TESTS_FALSE=
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable backend unit test building" >&5
+$as_echo_n "checking whether to enable backend unit test building... " >&6; }
+ # Check whether --enable-backend-unit-tests was given.
+if test "${enable_backend_unit_tests+set}" = set; then :
+ enableval=$enable_backend_unit_tests; enable_backend_unit_tests=$enableval
+else
+ enable_backend_unit_tests=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_backend_unit_tests" >&5
+$as_echo "$enable_backend_unit_tests" >&6; }
+ if test "x$enable_backend_unit_tests" != "xno"; then
+ BACKEND_UNIT_TESTS_TRUE=
+ BACKEND_UNIT_TESTS_FALSE='#'
+else
+ BACKEND_UNIT_TESTS_TRUE='#'
+ BACKEND_UNIT_TESTS_FALSE=
+fi
+
+
+ if test "x$enable_unit_tests" != "xno" || test "x$enable_backend_unit_tests" != "xno"; then :
+
+ if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for the Boost unit_test_framework library" >&5
+$as_echo "$as_me: Boost not available, not searching for the Boost unit_test_framework library" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+if test x"$boost_cv_inc_path" = xno; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Boost not available, not searching for boost/test/unit_test.hpp" >&5
+$as_echo "$as_me: Boost not available, not searching for boost/test/unit_test.hpp" >&6;}
+else
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+ac_fn_cxx_check_header_mongrel "$LINENO" "boost/test/unit_test.hpp" "ac_cv_header_boost_test_unit_test_hpp" "$ac_includes_default"
+if test "x$ac_cv_header_boost_test_unit_test_hpp" = xyes; then :
+
+$as_echo "#define HAVE_BOOST_TEST_UNIT_TEST_HPP 1" >>confdefs.h
+
+else
+ as_fn_error $? "cannot find boost/test/unit_test.hpp" "$LINENO" 5
+fi
+
+
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for the Boost unit_test_framework library" >&5
+$as_echo_n "checking for the Boost unit_test_framework library... " >&6; }
+if ${boost_cv_lib_unit_test_framework+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ boost_cv_lib_unit_test_framework=no
+ case "mt" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "Xmt" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=mt;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[sgpn]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ as_fn_error $? "the libext variable is empty, did you invoke Libtool?" "$LINENO" 5
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <boost/test/unit_test.hpp>
+using boost::unit_test::test_suite;
+ test_suite* init_unit_test_suite(int argc, char ** argv)
+ { return NULL; }
+int
+main ()
+{
+BOOST_CHECK(2 == 2);
+ ;
+ return 0;
+}
+_ACEOF
+ if ac_fn_cxx_try_compile "$LINENO"; then :
+ ac_objext=do_not_rm_me_plz
+else
+ as_fn_error $? "cannot compile a test that uses Boost unit_test_framework" "$LINENO" 5
+fi
+rm -f core conftest.err conftest.$ac_objext
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in unit_test_framework; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ boost_cv_lib_unit_test_framework_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$boost_cv_lib_unit_test_framework_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ boost_cv_lib_unit_test_framework_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$boost_cv_lib_unit_test_framework_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_cv_lib_unit_test_framework=yes
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_cv_lib_unit_test_framework=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$boost_cv_lib_unit_test_framework" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ if ${boost_cv_rpath_link_ldflag+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $boost_cv_lib_unit_test_framework_LIBS"
+ rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ $as_echo "$as_me:${as_lineno-$LINENO}: re-using the existing conftest.$ac_objext" >&5
+if { { ac_try="$ac_link"
+case "(($ac_try" in
+ *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+ *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+ (eval "$ac_link") 2>conftest.err
+ ac_status=$?
+ if test -s conftest.err; then
+ grep -v '^ *+' conftest.err >conftest.er1
+ cat conftest.er1 >&5
+ mv -f conftest.er1 conftest.err
+ fi
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; } && {
+ test -z "$ac_cxx_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+ }; then :
+ boost_rpath_link_ldflag_found=yes
+ break
+else
+ if $boost_use_source; then
+ $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+ fi
+ boost_rpath_link_ldflag_found=no
+fi
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext
+ done
+ ;;
+ esac
+ if test "x$boost_rpath_link_ldflag_found" != "xyes"; then :
+ as_fn_error $? "Unable to determine whether to use -R or -rpath" "$LINENO" 5
+fi
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+
+fi
+
+ test x"$boost_ldpath" != x &&
+ boost_cv_lib_unit_test_framework_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ boost_cv_lib_unit_test_framework_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $boost_cv_lib_unit_test_framework" >&5
+$as_echo "$boost_cv_lib_unit_test_framework" >&6; }
+case $boost_cv_lib_unit_test_framework in #(
+ (yes) $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+
+$as_echo "#define HAVE_BOOST_UNIT_TEST_FRAMEWORK 1" >>confdefs.h
+ BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS=$boost_cv_lib_unit_test_framework_LDFLAGS
+ BOOST_UNIT_TEST_FRAMEWORK_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH
+ BOOST_LDPATH=$boost_cv_lib_unit_test_framework_LDPATH
+ BOOST_UNIT_TEST_FRAMEWORK_LIBS=$boost_cv_lib_unit_test_framework_LIBS
+ ;;
+esac
+CPPFLAGS=$boost_save_CPPFLAGS
+ac_ext=cpp
+ac_cpp='$CXXCPP $CPPFLAGS'
+ac_compile='$CXX -c $CXXFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CXX -o conftest$ac_exeext $CXXFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_cxx_compiler_gnu
+fi
+
+
+
+ if test "$boost_cv_lib_unit_test_framework" = "no"; then :
+
+ as_fn_error $? "Boost Unit Test library not found" "$LINENO" 5
+
+fi
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable reproducible builds." >&5
+$as_echo_n "checking whether to enable reproducible builds.... " >&6; }
+ # Check whether --enable-reproducible was given.
+if test "${enable_reproducible+set}" = set; then :
+ enableval=$enable_reproducible; enable_reproducible=$enableval
+else
+ enable_reproducible=no
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_reproducible" >&5
+$as_echo "$enable_reproducible" >&6; }
+
+ if test x"$enable_reproducible" = "xyes"; then :
+
+
+$as_echo "#define REPRODUCIBLE 1" >>confdefs.h
+
+
+else
+
+ build_user=$(id -u -n)
+
+ case "$host_os" in
+ solaris2.1* | SunOS | openbsd*)
+ build_host_host=$(hostname)
+ build_host_domain=$(domainname)
+ build_host="$build_host_host.$build_host_domain"
+ ;;
+ *)
+ build_host=$(hostname -f || hostname || echo 'localhost')
+ ;;
+ esac
+
+cat >>confdefs.h <<_ACEOF
+#define BUILD_HOST "$build_user@$build_host"
+_ACEOF
+
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether user requires sqlite3" >&5
+$as_echo_n "checking whether user requires sqlite3... " >&6; }
+
+# Check whether --with-sqlite3 was given.
+if test "${with_sqlite3+set}" = set; then :
+ withval=$with_sqlite3; with_sqlite3=$withval
+else
+ with_sqlite3=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_sqlite3" >&5
+$as_echo "$with_sqlite3" >&6; }
+
+ if test "x$with_sqlite3" != "xno"; then :
+
+ needsqlite3=yes
+
+fi
+
+
+
+ # Extract the first word of "pandoc", so it can be a program name with args.
+set dummy pandoc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PANDOC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PANDOC"; then
+ ac_cv_prog_PANDOC="$PANDOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PANDOC="pandoc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_PANDOC" && ac_cv_prog_PANDOC="no"
+fi
+fi
+PANDOC=$ac_cv_prog_PANDOC
+if test -n "$PANDOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PANDOC" >&5
+$as_echo "$PANDOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ if test "x$PANDOC" = "xno"; then :
+
+ if test ! -d "$srcdir/docs/html" -o ! -f "$srcdir/docs/pdns_server.1"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: pandoc is missing, unable to build documentation and manpages." >&5
+$as_echo "$as_me: WARNING: pandoc is missing, unable to build documentation and manpages." >&2;}
+
+fi
+
+fi
+ if test "x$PANDOC" != "xno"; then
+ HAVE_PANDOC_TRUE=
+ HAVE_PANDOC_FALSE='#'
+else
+ HAVE_PANDOC_TRUE='#'
+ HAVE_PANDOC_FALSE=
+fi
+
+ if test -e "$srcdir/docs/pdns_server.1"; then
+ HAVE_MANPAGES_TRUE=
+ HAVE_MANPAGES_FALSE='#'
+else
+ HAVE_MANPAGES_TRUE='#'
+ HAVE_MANPAGES_FALSE=
+fi
+
+
+
+ if test -d "$srcdir/.git"; then
+ FROM_GIT_TRUE=
+ FROM_GIT_FALSE='#'
+else
+ FROM_GIT_TRUE='#'
+ FROM_GIT_FALSE=
+fi
+
+
+
+
+
+
+ for ac_func in $ac_func_list
+do :
+ as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh`
+ac_fn_cxx_check_func "$LINENO" "$ac_func" "$as_ac_var"
+if eval test \"x\$"$as_ac_var"\" = x"yes"; then :
+ cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1
+_ACEOF
+
+fi
+done
+
+
+
+
+
+
+
+
+
+ if test "x$ac_cv_func_recvmmsg" = "xyes"; then
+ HAVE_RECVMMSG_TRUE=
+ HAVE_RECVMMSG_FALSE='#'
+else
+ HAVE_RECVMMSG_TRUE='#'
+ HAVE_RECVMMSG_FALSE=
+fi
+
+
+if test "x$lt_cv_dlopen" = "xno"; then :
+ as_fn_error $? "Your system does not support dlopen" "$LINENO" 5
+
+fi
+
+LIBDL=$lt_cv_dlopen_libs
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable verbose logging" >&5
+$as_echo_n "checking whether to enable verbose logging... " >&6; }
+
+ # Check whether --enable-verbose-logging was given.
+if test "${enable_verbose_logging+set}" = set; then :
+ enableval=$enable_verbose_logging; enable_verbose_logging=$enableval
+else
+ enable_verbose_logging=no
+
+fi
+
+
+ if test "x$enable_verbose_logging" != "xno"; then :
+
+$as_echo "#define VERBOSELOG 1" >>confdefs.h
+
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_verbose_logging" >&5
+$as_echo "$enable_verbose_logging" >&6; }
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable PKCS11 support" >&5
+$as_echo_n "checking whether to enable PKCS11 support... " >&6; }
+ # Check whether --enable-experimental-pkcs11 was given.
+if test "${enable_experimental_pkcs11+set}" = set; then :
+ enableval=$enable_experimental_pkcs11; enable_pkcs11=$enableval
+else
+ enable_pkcs11=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_pkcs11" >&5
+$as_echo "$enable_pkcs11" >&6; }
+ if test "x$enable_pkcs11" != "xno"; then
+ PKCS11_TRUE=
+ PKCS11_FALSE='#'
+else
+ PKCS11_TRUE='#'
+ PKCS11_FALSE=
+fi
+
+
+ if test "x$enable_pkcs11" != "xno"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for P11KIT1" >&5
+$as_echo_n "checking for P11KIT1... " >&6; }
+
+if test -n "$P11KIT1_CFLAGS"; then
+ pkg_cv_P11KIT1_CFLAGS="$P11KIT1_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"p11-kit-1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "p11-kit-1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_P11KIT1_CFLAGS=`$PKG_CONFIG --cflags "p11-kit-1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$P11KIT1_LIBS"; then
+ pkg_cv_P11KIT1_LIBS="$P11KIT1_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"p11-kit-1\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "p11-kit-1") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_P11KIT1_LIBS=`$PKG_CONFIG --libs "p11-kit-1" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ P11KIT1_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "p11-kit-1" 2>&1`
+ else
+ P11KIT1_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "p11-kit-1" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$P11KIT1_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find p11-kit-1" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find p11-kit-1" "$LINENO" 5
+
+else
+ P11KIT1_CFLAGS=$pkg_cv_P11KIT1_CFLAGS
+ P11KIT1_LIBS=$pkg_cv_P11KIT1_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_P11KIT1 1" >>confdefs.h
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for p11_kit_module_for_name in -lp11-kit" >&5
+$as_echo_n "checking for p11_kit_module_for_name in -lp11-kit... " >&6; }
+if ${ac_cv_lib_p11_kit_p11_kit_module_for_name+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lp11-kit $P11KIT1_LIBS $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char p11_kit_module_for_name ();
+int
+main ()
+{
+return p11_kit_module_for_name ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_p11_kit_p11_kit_module_for_name=yes
+else
+ ac_cv_lib_p11_kit_p11_kit_module_for_name=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_p11_kit_p11_kit_module_for_name" >&5
+$as_echo "$ac_cv_lib_p11_kit_p11_kit_module_for_name" >&6; }
+if test "x$ac_cv_lib_p11_kit_p11_kit_module_for_name" = xyes; then :
+
+$as_echo "#define HAVE_P11KIT1_V2 1" >>confdefs.h
+
+fi
+
+
+fi
+
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable experimental GSS-TSIG support" >&5
+$as_echo_n "checking whether to enable experimental GSS-TSIG support... " >&6; }
+ # Check whether --enable-experimental_gss_tsig was given.
+if test "${enable_experimental_gss_tsig+set}" = set; then :
+ enableval=$enable_experimental_gss_tsig; enable_experimental_gss_tsig=$enableval
+else
+ enable_experimental_gss_tsig=no
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_experimental_gss_tsig" >&5
+$as_echo "$enable_experimental_gss_tsig" >&6; }
+
+ if test "x$enable_experimental_gss_tsig" != "xno"; then
+ GSS_TSIG_TRUE=
+ GSS_TSIG_FALSE='#'
+else
+ GSS_TSIG_TRUE='#'
+ GSS_TSIG_FALSE=
+fi
+
+
+ if test "x$enable_experimental_gss_tsig" != "xno"; then :
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSS" >&5
+$as_echo_n "checking for GSS... " >&6; }
+
+if test -n "$GSS_CFLAGS"; then
+ pkg_cv_GSS_CFLAGS="$GSS_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"krb5 krb5-gssapi gss\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "krb5 krb5-gssapi gss") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GSS_CFLAGS=`$PKG_CONFIG --cflags "krb5 krb5-gssapi gss" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GSS_LIBS"; then
+ pkg_cv_GSS_LIBS="$GSS_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"krb5 krb5-gssapi gss\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "krb5 krb5-gssapi gss") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GSS_LIBS=`$PKG_CONFIG --libs "krb5 krb5-gssapi gss" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GSS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "krb5 krb5-gssapi gss" 2>&1`
+ else
+ GSS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "krb5 krb5-gssapi gss" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GSS_PKG_ERRORS" >&5
+
+ as_fn_error $? "Required libraries for GSS-TSIG not found" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Required libraries for GSS-TSIG not found" "$LINENO" 5
+
+else
+ GSS_CFLAGS=$pkg_cv_GSS_CFLAGS
+ GSS_LIBS=$pkg_cv_GSS_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define ENABLE_GSS_TSIG 1" >>confdefs.h
+
+ GSS_TSIG=yes
+
+fi
+else
+ GSS_TSIG=no
+fi
+
+
+
+socketdir="/var/run"
+
+# Check whether --with-socketdir was given.
+if test "${with_socketdir+set}" = set; then :
+ withval=$with_socketdir; socketdir="$withval"
+
+fi
+
+
+modules="bind gmysql random"
+
+# Check whether --with-modules was given.
+if test "${with_modules+set}" = set; then :
+ withval=$with_modules; modules="$withval"
+
+fi
+
+
+dynmodules="pipe"
+
+# Check whether --with-dynmodules was given.
+if test "${with_dynmodules+set}" = set; then :
+ withval=$with_dynmodules; dynmodules="$withval"
+
+fi
+
+
+
+
+
+
+cat >>confdefs.h <<_ACEOF
+#define PDNS_MODULES "$modules"
+_ACEOF
+
+
+if test x"$modules" = "xno"; then :
+ modules=""
+fi
+if test x"$dynmodules" = "xno"; then :
+ dynmodules=""
+fi
+
+for a in $modules $dynmodules; do
+ case "$a" in
+ oracle|goracle)
+
+
+# Check whether --with-oracle_includes was given.
+if test "${with_oracle_includes+set}" = set; then :
+ withval=$with_oracle_includes;
+fi
+
+
+# Check whether --with-oracle_libs was given.
+if test "${with_oracle_libs+set}" = set; then :
+ withval=$with_oracle_libs;
+fi
+
+
+ if test x"$with_oracle_includes" = "x"; then
+ # check possible locations
+ for p1 in /usr/include/oracle /usr/local/include/oracle; do
+ for p2 in $p1/*/client*; do
+ if test -d "$p2"; then
+ with_oracle_includes=$p2
+ fi
+ done
+ done
+ fi
+
+ if test x"$with_oracle_includes" = x && test "$ORACLE_HOME/rdbms/public" != "/rdbms/public"; then
+ if test -d $ORACLE_HOME/rdbms/public; then
+ with_oracle_includes=$ORACLE_HOME/rdbms/public
+ fi
+ fi
+
+ # test header
+ old_CXXFLAGS="$CXXFLAGS"
+ old_CFLAGS="$CFLAGS"
+ CXXFLAGS="$CXXFLAGS -I$with_oracle_includes"
+ CPPFLAGS="$CPPFLAGS -I$with_oracle_includes"
+ ac_fn_cxx_check_header_mongrel "$LINENO" "oci.h" "ac_cv_header_oci_h" "$ac_includes_default"
+if test "x$ac_cv_header_oci_h" = xyes; then :
+ ORACLE_CFLAGS="-I$with_oracle_includes"
+else
+ as_fn_error $? "Could not find oci.h" "$LINENO" 5
+fi
+
+
+ CXXFLAGS="$old_CXXFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
+
+
+
+ if test x"$with_oracle_libs" = "x"; then
+ # check possible locationse
+ for p1 in /usr/lib/oracle /usr/local/lib/oracle; do
+ for p2 in $p1/*/client*/lib; do
+ if test -d "$p2"; then
+ with_oracle_libs=$p2
+ fi
+ done
+ done
+ fi
+
+ if test x"$with_oracle_libs" = x && test "$ORACLE_HOME/lib" != "/lib"; then
+ if test -d $ORACLE_HOME/lib; then
+ with_oracle_libs=$ORACLE_HOME/lib
+ fi
+ fi
+
+ # we have to check for client9 as well...
+ # test -lclntsh
+ old_LDFLAGS="$LDFLAGS"
+ LDFLAGS="-L$with_oracle_libs -locci"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIEnvInit in -lclntsh" >&5
+$as_echo_n "checking for OCIEnvInit in -lclntsh... " >&6; }
+if ${ac_cv_lib_clntsh_OCIEnvInit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lclntsh $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char OCIEnvInit ();
+int
+main ()
+{
+return OCIEnvInit ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_clntsh_OCIEnvInit=yes
+else
+ ac_cv_lib_clntsh_OCIEnvInit=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_clntsh_OCIEnvInit" >&5
+$as_echo "$ac_cv_lib_clntsh_OCIEnvInit" >&6; }
+if test "x$ac_cv_lib_clntsh_OCIEnvInit" = xyes; then :
+ ORACLE_LIBS="-L$with_oracle_libs -lclntsh -locci"
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for OCIEnvInit in -lclient9" >&5
+$as_echo_n "checking for OCIEnvInit in -lclient9... " >&6; }
+if ${ac_cv_lib_client9_OCIEnvInit+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lclient9 $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char OCIEnvInit ();
+int
+main ()
+{
+return OCIEnvInit ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_client9_OCIEnvInit=yes
+else
+ ac_cv_lib_client9_OCIEnvInit=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_client9_OCIEnvInit" >&5
+$as_echo "$ac_cv_lib_client9_OCIEnvInit" >&6; }
+if test "x$ac_cv_lib_client9_OCIEnvInit" = xyes; then :
+ ORACLE_LIBS="-L$with_oracle_libs -lclient9 -lclntsh9"
+else
+ as_fn_error $? "Could not find client libraries" "$LINENO" 5
+
+fi
+
+
+fi
+
+ LDFLAGS="$old_LDFLAGS"
+
+ needoracle=yes
+ ;;
+ godbc)
+
+
+# Check whether --with-unixodbc was given.
+if test "${with_unixodbc+set}" = set; then :
+ withval=$with_unixodbc;
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $with_unixodbc/lib"
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc"
+ UNIXODBC_config_check="$withval/bin/odbc_config"
+
+else
+
+ UNIXODBC_LIBS_check="/usr/local/unixodbc/lib/unixodbc /usr/local/lib/unixodbc /opt/unixodbc/lib/unixodbc \
+ /usr/lib/unixodbc /usr/lib64/unixodbc /usr/local/unixodbc/lib /usr/local/lib /opt/unixodbc/lib /usr/lib \
+ /usr/sfw/lib/ /usr/lib/odbc /usr/lib/x86_64-linux-gnu $full_libdir"
+ UNIXODBC_CFLAGS_check="/usr/local/unixodbc/include/unixodbc /usr/local/include/unixodbc \
+ /opt/unixodbc/include/unixodbc /opt/unixodbc/include /usr/include/unixodbc /usr/sfw/include/unixodbc \
+ /usr/include /usr/local/include"
+
+
+fi
+
+
+
+# Check whether --with-odbc-config was given.
+if test "${with_odbc_config+set}" = set; then :
+ withval=$with_odbc_config; UNIXODBC_config_check=$withval
+
+fi
+
+
+
+# Check whether --with-unixodbc-lib was given.
+if test "${with_unixodbc_lib+set}" = set; then :
+ withval=$with_unixodbc_lib;
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+
+
+fi
+
+
+
+# Check whether --with-unixodbc-includes was given.
+if test "${with_unixodbc_includes+set}" = set; then :
+ withval=$with_unixodbc_includes;
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+
+
+fi
+
+
+ UNIXODBC_config=""
+ if test "x$UNIXODBC_config_check" != "xskip"; then
+ if test "x$UNIXODBC_config_check" = "x"; then
+ # Extract the first word of "odbc_config", so it can be a program name with args.
+set dummy odbc_config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_UNIXODBC_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $UNIXODBC_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_UNIXODBC_config="$UNIXODBC_config" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_UNIXODBC_config="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+UNIXODBC_config=$ac_cv_path_UNIXODBC_config
+if test -n "$UNIXODBC_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNIXODBC_config" >&5
+$as_echo "$UNIXODBC_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $UNIXODBC_config_check" >&5
+$as_echo_n "checking for $UNIXODBC_config_check... " >&6; }
+ if test -x $UNIXODBC_config_check; then
+ UNIXODBC_config="$UNIXODBC_config_check"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ UNIXODBC_config=""
+ as_fn_error $? "not found" "$LINENO" 5
+ fi
+ fi
+ fi
+
+ if test "x$UNIXODBC_config" != "x"; then
+ # use this to configure everything
+ UNIXODBC_LIBS=`$UNIXODBC_config --libs`
+ UNIXODBC_CFLAGS=-I`$UNIXODBC_config --include-prefix`
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unixODBC library directory" >&5
+$as_echo_n "checking for unixODBC library directory... " >&6; }
+ UNIXODBC_libdir=
+ for m in $UNIXODBC_LIBS_check; do
+ if test -d "$m" && \
+ (test -f "$m/libodbc.so" || test -f "$m/libodbc.a")
+ then
+ UNIXODBC_libdir=$m
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_libdir"; then
+ as_fn_error $? "Did not find the unixodbc library dir in '$UNIXODBC_LIBS_check'" "$LINENO" 5
+ fi
+ case "$UNIXODBC_libdir" in
+ /*) UNIXODBC_LIBS="-L$UNIXODBC_libdir -lodbc"
+ ;;
+ *) as_fn_error $? "The unixODBC library directory ($UNIXODBC_libdir) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNIXODBC_libdir" >&5
+$as_echo "$UNIXODBC_libdir" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for unixODBC include directory" >&5
+$as_echo_n "checking for unixODBC include directory... " >&6; }
+ UNIXODBC_CFLAGS=
+ for m in $UNIXODBC_CFLAGS_check; do
+ if test -d "$m" && test -f "$m/sql.h"
+ then
+ UNIXODBC_CFLAGS="$m"
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_CFLAGS"; then
+ as_fn_error $? "Did not find the unixodbc include dir in '$UNIXODBC_CFLAGS_check'" "$LINENO" 5
+ fi
+
+ case "$UNIXODBC_CFLAGS" in
+ /*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $UNIXODBC_CFLAGS" >&5
+$as_echo "$UNIXODBC_CFLAGS" >&6; }
+ ;;
+ *) as_fn_error $? "The unixODBC include directory ($UNIXODBC_CFLAGS) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ UNIXODBC_CFLAGS="-I$UNIXODBC_CFLAGS"
+ fi
+
+
+
+
+ ;;
+ mydns|gmysql|pdns)
+
+
+# Check whether --with-mysql was given.
+if test "${with_mysql+set}" = set; then :
+ withval=$with_mysql;
+ MYSQL_LIBS_check="$withval/lib/mysql $with_mysql/lib"
+ MYSQL_CFLAGS_check="$withval/include/mysql"
+ MYSQL_config_check="$withval/bin/mysql_config"
+
+else
+
+ MYSQL_LIBS_check="/usr/local/mysql/lib/mysql /usr/local/lib/mysql /opt/mysql/lib/mysql \
+ /usr/lib/mysql /usr/lib64/mysql /usr/local/mysql/lib /usr/local/lib /opt/mysql/lib /usr/lib \
+ /usr/sfw/lib/ $full_libdir"
+ MYSQL_CFLAGS_check="/usr/local/mysql/include/mysql /usr/local/include/mysql \
+ /opt/mysql/include/mysql /opt/mysql/include /usr/include/mysql /usr/sfw/include/mysql"
+
+
+fi
+
+
+
+# Check whether --with-mysql-config was given.
+if test "${with_mysql_config+set}" = set; then :
+ withval=$with_mysql_config; MYSQL_config_check=$withval
+
+fi
+
+
+
+# Check whether --with-mysql-lib was given.
+if test "${with_mysql_lib+set}" = set; then :
+ withval=$with_mysql_lib;
+ MYSQL_LIBS_check="$withval/lib/mysql $withval/mysql $withval"
+ MYSQL_config_check="skip"
+
+
+fi
+
+
+
+# Check whether --with-mysql-includes was given.
+if test "${with_mysql_includes+set}" = set; then :
+ withval=$with_mysql_includes;
+ MYSQL_CFLAGS_check="$withval/include/mysql $withval/mysql $withval"
+ MYSQL_config_check="skip"
+
+
+fi
+
+
+ MYSQL_config=""
+ if test "x$MYSQL_config_check" != "xskip"; then
+ if test "x$MYSQL_config_check" = "x"; then
+ # Extract the first word of "mysql_config", so it can be a program name with args.
+set dummy mysql_config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_MYSQL_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $MYSQL_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_MYSQL_config="$MYSQL_config" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_MYSQL_config="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+MYSQL_config=$ac_cv_path_MYSQL_config
+if test -n "$MYSQL_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_config" >&5
+$as_echo "$MYSQL_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $MYSQL_config_check" >&5
+$as_echo_n "checking for $MYSQL_config_check... " >&6; }
+ if test -x $MYSQL_config_check; then
+ MYSQL_config="$MYSQL_config_check"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ else
+ MYSQL_config=""
+ as_fn_error $? "not found" "$LINENO" 5
+ fi
+ fi
+ fi
+
+ if test "x$MYSQL_config" != "x"; then
+ # use this to configure everything
+ MYSQL_LIBS=`$MYSQL_config --libs`
+ MYSQL_CFLAGS=`$MYSQL_config --include`
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MySQL library directory" >&5
+$as_echo_n "checking for MySQL library directory... " >&6; }
+ MYSQL_libdir=
+ for m in $MYSQL_LIBS_check; do
+ if test -d "$m" && \
+ (test -f "$m/libmysqlclient.so" || test -f "$m/libmysqlclient.a")
+ then
+ MYSQL_libdir=$m
+ break
+ fi
+ done
+ if test -z "$MYSQL_libdir"; then
+ as_fn_error $? "Did not find the mysql library dir in '$MYSQL_LIBS_check'" "$LINENO" 5
+ fi
+ case "$MYSQL_libdir" in
+ /*) MYSQL_LIBS="-L$MYSQL_libdir -lmysqlclient"
+ ;;
+ *) as_fn_error $? "The MySQL library directory ($MYSQL_libdir) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_libdir" >&5
+$as_echo "$MYSQL_libdir" >&6; }
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for MySQL include directory" >&5
+$as_echo_n "checking for MySQL include directory... " >&6; }
+ MYSQL_CFLAGS=
+ for m in $MYSQL_CFLAGS_check; do
+ if test -d "$m" && test -f "$m/mysql.h"
+ then
+ MYSQL_CFLAGS="$m"
+ break
+ fi
+ done
+ if test -z "$MYSQL_CFLAGS"; then
+ as_fn_error $? "Did not find the mysql include dir in '$MYSQL_CFLAGS_check'" "$LINENO" 5
+ fi
+
+ case "$MYSQL_CFLAGS" in
+ /*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: $MYSQL_CFLAGS" >&5
+$as_echo "$MYSQL_CFLAGS" >&6; }
+ ;;
+ *) as_fn_error $? "The MySQL include directory ($MYSQL_CFLAGS) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ MYSQL_CFLAGS="-I$MYSQL_CFLAGS"
+ fi
+
+
+
+ ;;
+ gpgsql)
+
+
+# Check whether --with-pgsql was given.
+if test "${with_pgsql+set}" = set; then :
+ withval=$with_pgsql; PGSQL_lib_check="$withval/lib/pgsql $withval/lib"
+ PGSQL_inc_check="$withval/include/pgsql $withval/include"
+
+
+fi
+
+
+
+# Check whether --with-pgsql-lib was given.
+if test "${with_pgsql_lib+set}" = set; then :
+ withval=$with_pgsql_lib; PGSQL_lib_check="$withval/lib/pgsql $withval/pgsql $withval"
+
+fi
+
+
+
+# Check whether --with-pgsql-includes was given.
+if test "${with_pgsql_includes+set}" = set; then :
+ withval=$with_pgsql_includes; PGSQL_inc_check="$withval/include/pgsql $withval/pgsql $withval"
+
+fi
+
+
+
+# Check whether --with-pgsql-config was given.
+if test "${with_pgsql_config+set}" = set; then :
+ withval=$with_pgsql_config; PGSQL_pg_config="$withval"
+ if test "x$PGSQL_pg_config" = "xyes" || test ! -x "$PGSQL_pg_config"; then
+ as_fn_error $? "--with-pgsql-config must provide a valid path to pg_config executable" "$LINENO" 5
+ fi
+
+else
+ # Extract the first word of "pg_config", so it can be a program name with args.
+set dummy pg_config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PGSQL_pg_config+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ case $PGSQL_pg_config in
+ [\\/]* | ?:[\\/]*)
+ ac_cv_path_PGSQL_pg_config="$PGSQL_pg_config" # Let the user override the test with a path.
+ ;;
+ *)
+ as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_path_PGSQL_pg_config="$as_dir/$ac_word$ac_exec_ext"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+fi
+PGSQL_pg_config=$ac_cv_path_PGSQL_pg_config
+if test -n "$PGSQL_pg_config"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PGSQL_pg_config" >&5
+$as_echo "$PGSQL_pg_config" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+
+ if test "x$PGSQL_pg_config" != "x"; then
+ if test "x$PGSQL_lib_check" = "x"; then
+ PGSQL_lib_check=$($PGSQL_pg_config --libdir)
+ fi
+ if test "x$PGSQL_inc_check" = "x"; then
+ PGSQL_inc_check=$($PGSQL_pg_config --includedir)
+ fi
+ PGSQL_CFLAGS=
+ fi
+
+ if test "x$PGSQL_lib_check" = "x"; then
+ PGSQL_lib_check="/usr/local/pgsql/lib/pgsql /usr/local/lib/pgsql /opt/pgsql/lib/pgsql /usr/lib/pgsql /usr/local/pgsql/lib /usr/local/lib /opt/pgsql/lib /usr/lib /usr/lib64 $full_libdir"
+ fi
+
+ if test "x$PGSQL_inc_check" = "x"; then
+ PGSQL_inc_check="/usr/local/pgsql/include/pgsql /usr/include /usr/local/include/postgresql/ /usr/local/include /opt/pgsql/include/pgsql /opt/pgsql/include /usr/include/pgsql/ /usr/include/postgresql"
+ fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PgSQL library directory" >&5
+$as_echo_n "checking for PgSQL library directory... " >&6; }
+ PGSQL_libdir=
+ for m in $PGSQL_lib_check; do
+ if test -d "$m" && (test -f "$m/libpq.a" || test -f "$m/libpq.so"); then
+ PGSQL_libdir=$m
+ break
+ fi
+ done
+ if test -z "$PGSQL_libdir"; then
+ as_fn_error $? "Did not find the pgsql library dir in '$PGSQL_lib_check'" "$LINENO" 5
+ fi
+ case "$PGSQL_libdir" in
+ /usr/lib)
+ PGSQL_lib="-lpq"
+ ;;
+ /usr/lib64)
+ PGSQL_lib="-lpq"
+ ;;
+ $full_libdir)
+ PGSQL_lib="-lpq"
+ ;;
+ /*)
+ PGSQL_lib="-L$PGSQL_libdir -Wl,-rpath,$PGSQL_libdir -lpq"
+ ;;
+ *)
+ as_fn_error $? "The PgSQL library directory ($PGSQL_libdir) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PGSQL_libdir" >&5
+$as_echo "$PGSQL_libdir" >&6; }
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for PgSQL include directory" >&5
+$as_echo_n "checking for PgSQL include directory... " >&6; }
+ PGSQL_incdir=
+ for m in $PGSQL_inc_check; do
+ if test -d "$m" && test -f "$m/libpq-fe.h"; then
+ PGSQL_incdir=$m
+ break
+ fi
+ done
+ if test -z "$PGSQL_incdir"; then
+ as_fn_error $? "Did not find the PgSQL include dir in '$PGSQL_inc_check'" "$LINENO" 5
+ fi
+ case "$PGSQL_incdir" in
+ /*)
+ PGSQL_inc="-I$PGSQL_incdir"
+ ;;
+ * )
+ as_fn_error $? "The PgSQL include directory ($PGSQL_incdir) must be an absolute path." "$LINENO" 5
+ ;;
+ esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PGSQL_incdir" >&5
+$as_echo "$PGSQL_incdir" >&6; }
+
+ ;;
+ gsqlite3)
+ needsqlite3=yes
+ ;;
+ ldap)
+
+ for ac_header in ldap.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "ldap.h" "ac_cv_header_ldap_h" "$ac_includes_default"
+if test "x$ac_cv_header_ldap_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LDAP_H 1
+_ACEOF
+
+else
+ as_fn_error $? "ldap header (ldap.h) not found" "$LINENO" 5
+
+fi
+
+done
+
+
+ for ac_header in lber.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "lber.h" "ac_cv_header_lber_h" "$ac_includes_default"
+if test "x$ac_cv_header_lber_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_LBER_H 1
+_ACEOF
+
+else
+ as_fn_error $? "ldap header (lber.h) not found" "$LINENO" 5
+
+fi
+
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_set_option in -lldap_r" >&5
+$as_echo_n "checking for ldap_set_option in -lldap_r... " >&6; }
+if ${ac_cv_lib_ldap_r_ldap_set_option+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap_r $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_set_option ();
+int
+main ()
+{
+return ldap_set_option ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_r_ldap_set_option=yes
+else
+ ac_cv_lib_ldap_r_ldap_set_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_r_ldap_set_option" >&5
+$as_echo "$ac_cv_lib_ldap_r_ldap_set_option" >&6; }
+if test "x$ac_cv_lib_ldap_r_ldap_set_option" = xyes; then :
+
+
+$as_echo "#define HAVE_LIBLDAP_R 1" >>confdefs.h
+
+ LIBLDAP="ldap_r"
+ LDAP_LIBS="-lldap_r -llber"
+
+else
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_set_option in -lldap" >&5
+$as_echo_n "checking for ldap_set_option in -lldap... " >&6; }
+if ${ac_cv_lib_ldap_ldap_set_option+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lldap $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_set_option ();
+int
+main ()
+{
+return ldap_set_option ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_ldap_ldap_set_option=yes
+else
+ ac_cv_lib_ldap_ldap_set_option=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_ldap_ldap_set_option" >&5
+$as_echo "$ac_cv_lib_ldap_ldap_set_option" >&6; }
+if test "x$ac_cv_lib_ldap_ldap_set_option" = xyes; then :
+
+
+$as_echo "#define HAVE_LIBLDAP 1" >>confdefs.h
+
+ LIBLDAP="ldap"
+ LDAP_LIBS="-lldap -llber"
+
+else
+ as_fn_error $? "ldap library (libldap) not found" "$LINENO" 5
+
+fi
+
+
+
+fi
+
+
+ as_ac_Lib=`$as_echo "ac_cv_lib_$LIBLDAP''_ldap_initialize" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_initialize in -l$LIBLDAP" >&5
+$as_echo_n "checking for ldap_initialize in -l$LIBLDAP... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$LIBLDAP $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_initialize ();
+int
+main ()
+{
+return ldap_initialize ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+
+$as_echo "#define HAVE_LDAP_INITIALIZE 1" >>confdefs.h
+
+
+fi
+
+
+ as_ac_Lib=`$as_echo "ac_cv_lib_$LIBLDAP''_ldap_sasl_bind" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ldap_sasl_bind in -l$LIBLDAP" >&5
+$as_echo_n "checking for ldap_sasl_bind in -l$LIBLDAP... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$LIBLDAP $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char ldap_sasl_bind ();
+int
+main ()
+{
+return ldap_sasl_bind ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+
+$as_echo "#define HAVE_LDAP_SASL_BIND 1" >>confdefs.h
+
+
+fi
+
+
+
+
+ needldap=yes
+ ;;
+ opendbx)
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for OPENDBX" >&5
+$as_echo_n "checking for OPENDBX... " >&6; }
+
+if test -n "$OPENDBX_CFLAGS"; then
+ pkg_cv_OPENDBX_CFLAGS="$OPENDBX_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"opendbx\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "opendbx") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_OPENDBX_CFLAGS=`$PKG_CONFIG --cflags "opendbx" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$OPENDBX_LIBS"; then
+ pkg_cv_OPENDBX_LIBS="$OPENDBX_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"opendbx\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "opendbx") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_OPENDBX_LIBS=`$PKG_CONFIG --libs "opendbx" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ OPENDBX_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "opendbx" 2>&1`
+ else
+ OPENDBX_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "opendbx" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$OPENDBX_PKG_ERRORS" >&5
+
+
+ for ac_header in odbx.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "odbx.h" "ac_cv_header_odbx_h" "$ac_includes_default"
+if test "x$ac_cv_header_odbx_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ODBX_H 1
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for odbx_init in -lopendbx" >&5
+$as_echo_n "checking for odbx_init in -lopendbx... " >&6; }
+if ${ac_cv_lib_opendbx_odbx_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lopendbx $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char odbx_init ();
+int
+main ()
+{
+return odbx_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_opendbx_odbx_init=yes
+else
+ ac_cv_lib_opendbx_odbx_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_opendbx_odbx_init" >&5
+$as_echo "$ac_cv_lib_opendbx_odbx_init" >&6; }
+if test "x$ac_cv_lib_opendbx_odbx_init" = xyes; then :
+ OPENDBX_LIBS="-lopendbx"
+else
+ as_fn_error $? "libopendbx not found" "$LINENO" 5
+
+fi
+
+else
+
+ as_fn_error $? "opendbx header (odbx.h) not found" "$LINENO" 5
+
+
+fi
+
+done
+
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+ for ac_header in odbx.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "odbx.h" "ac_cv_header_odbx_h" "$ac_includes_default"
+if test "x$ac_cv_header_odbx_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_ODBX_H 1
+_ACEOF
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for odbx_init in -lopendbx" >&5
+$as_echo_n "checking for odbx_init in -lopendbx... " >&6; }
+if ${ac_cv_lib_opendbx_odbx_init+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lopendbx $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char odbx_init ();
+int
+main ()
+{
+return odbx_init ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_opendbx_odbx_init=yes
+else
+ ac_cv_lib_opendbx_odbx_init=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_opendbx_odbx_init" >&5
+$as_echo "$ac_cv_lib_opendbx_odbx_init" >&6; }
+if test "x$ac_cv_lib_opendbx_odbx_init" = xyes; then :
+ OPENDBX_LIBS="-lopendbx"
+else
+ as_fn_error $? "libopendbx not found" "$LINENO" 5
+
+fi
+
+else
+
+ as_fn_error $? "opendbx header (odbx.h) not found" "$LINENO" 5
+
+
+fi
+
+done
+
+
+else
+ OPENDBX_CFLAGS=$pkg_cv_OPENDBX_CFLAGS
+ OPENDBX_LIBS=$pkg_cv_OPENDBX_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+
+ ;;
+ remote)
+ if test "x$enable_unit_tests" = "xyes"; then :
+
+ # Extract the first word of "curl", so it can be a program name with args.
+set dummy curl; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CURL+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$CURL"; then
+ ac_cv_prog_CURL="$CURL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_CURL="curl"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+ test -z "$ac_cv_prog_CURL" && ac_cv_prog_CURL="no"
+fi
+fi
+CURL=$ac_cv_prog_CURL
+if test -n "$CURL"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CURL" >&5
+$as_echo "$CURL" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+ if test "x$CURL" = "xno"; then :
+
+ as_fn_error $? "curl program is missing, required for running remotebackend unit tests" "$LINENO" 5
+
+fi
+
+
+fi
+ have_remotebackend=yes
+ ;;
+ tinydns)
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CDB" >&5
+$as_echo_n "checking for CDB... " >&6; }
+
+if test -n "$CDB_CFLAGS"; then
+ pkg_cv_CDB_CFLAGS="$CDB_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libcdb") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_CDB_CFLAGS=`$PKG_CONFIG --cflags "libcdb" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$CDB_LIBS"; then
+ pkg_cv_CDB_LIBS="$CDB_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libcdb\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libcdb") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_CDB_LIBS=`$PKG_CONFIG --libs "libcdb" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ CDB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libcdb" 2>&1`
+ else
+ CDB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libcdb" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$CDB_PKG_ERRORS" >&5
+
+ for ac_header in cdb.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_cdb_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CDB_H 1
+_ACEOF
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
+$as_echo_n "checking for cdb_find in -lcdb... " >&6; }
+if ${ac_cv_lib_cdb_cdb_find+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcdb $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cdb_find ();
+int
+main ()
+{
+return cdb_find ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_cdb_cdb_find=yes
+else
+ ac_cv_lib_cdb_cdb_find=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
+$as_echo "$ac_cv_lib_cdb_cdb_find" >&6; }
+if test "x$ac_cv_lib_cdb_cdb_find" = xyes; then :
+ CDB_LIBS="-lcdb"
+else
+ as_fn_error $? "Could not find libcdb" "$LINENO" 5
+
+fi
+
+else
+ as_fn_error $? "Could not find cdb.h" "$LINENO" 5
+
+fi
+
+done
+
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ for ac_header in cdb.h
+do :
+ ac_fn_cxx_check_header_mongrel "$LINENO" "cdb.h" "ac_cv_header_cdb_h" "$ac_includes_default"
+if test "x$ac_cv_header_cdb_h" = xyes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_CDB_H 1
+_ACEOF
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for cdb_find in -lcdb" >&5
+$as_echo_n "checking for cdb_find in -lcdb... " >&6; }
+if ${ac_cv_lib_cdb_cdb_find+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lcdb $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char cdb_find ();
+int
+main ()
+{
+return cdb_find ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_cdb_cdb_find=yes
+else
+ ac_cv_lib_cdb_cdb_find=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_cdb_cdb_find" >&5
+$as_echo "$ac_cv_lib_cdb_cdb_find" >&6; }
+if test "x$ac_cv_lib_cdb_cdb_find" = xyes; then :
+ CDB_LIBS="-lcdb"
+else
+ as_fn_error $? "Could not find libcdb" "$LINENO" 5
+
+fi
+
+else
+ as_fn_error $? "Could not find cdb.h" "$LINENO" 5
+
+fi
+
+done
+
+
+else
+ CDB_CFLAGS=$pkg_cv_CDB_CFLAGS
+ CDB_LIBS=$pkg_cv_CDB_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+
+
+ ;;
+ geoip)
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GEOIP" >&5
+$as_echo_n "checking for GEOIP... " >&6; }
+
+if test -n "$GEOIP_CFLAGS"; then
+ pkg_cv_GEOIP_CFLAGS="$GEOIP_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"geoip\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "geoip") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GEOIP_CFLAGS=`$PKG_CONFIG --cflags "geoip" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$GEOIP_LIBS"; then
+ pkg_cv_GEOIP_LIBS="$GEOIP_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"geoip\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "geoip") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_GEOIP_LIBS=`$PKG_CONFIG --libs "geoip" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ GEOIP_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "geoip" 2>&1`
+ else
+ GEOIP_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "geoip" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$GEOIP_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find libGeoIP" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find libGeoIP" "$LINENO" 5
+
+else
+ GEOIP_CFLAGS=$pkg_cv_GEOIP_CFLAGS
+ GEOIP_LIBS=$pkg_cv_GEOIP_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for YAML" >&5
+$as_echo_n "checking for YAML... " >&6; }
+
+if test -n "$YAML_CFLAGS"; then
+ pkg_cv_YAML_CFLAGS="$YAML_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"yaml-cpp >= 0.5\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "yaml-cpp >= 0.5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_YAML_CFLAGS=`$PKG_CONFIG --cflags "yaml-cpp >= 0.5" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$YAML_LIBS"; then
+ pkg_cv_YAML_LIBS="$YAML_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"yaml-cpp >= 0.5\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "yaml-cpp >= 0.5") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_YAML_LIBS=`$PKG_CONFIG --libs "yaml-cpp >= 0.5" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ YAML_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "yaml-cpp >= 0.5" 2>&1`
+ else
+ YAML_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "yaml-cpp >= 0.5" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$YAML_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find yaml-cpp" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find yaml-cpp" "$LINENO" 5
+
+else
+ YAML_CFLAGS=$pkg_cv_YAML_CFLAGS
+ YAML_LIBS=$pkg_cv_YAML_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+ ;;
+ lua)
+ if test "x$with_lua" = "xno"; then :
+ as_fn_error $? "Lua backend needs lua
+else
+ run ./configure --with-lua" "$LINENO" 5
+
+fi
+ if test "x$LUAPC" = "x"; then :
+ as_fn_error $? "Lua backend needs lua but we cannot find it" "$LINENO" 5
+
+fi
+ ;;
+ esac
+done
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ZeroMQ connector in remotebackend" >&5
+$as_echo_n "checking whether to enable ZeroMQ connector in remotebackend... " >&6; }
+ # Check whether --enable-remotebackend_zeromq was given.
+if test "${enable_remotebackend_zeromq+set}" = set; then :
+ enableval=$enable_remotebackend_zeromq; enable_remotebackend_zeromq=$enableval
+else
+ enable_remotebackend_zeromq=no
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_remotebackend_zeromq" >&5
+$as_echo "$enable_remotebackend_zeromq" >&6; }
+
+ if test "x$enable_remotebackend_zeromq" != "xno"; then
+ REMOTEBACKEND_ZEROMQ_TRUE=
+ REMOTEBACKEND_ZEROMQ_FALSE='#'
+else
+ REMOTEBACKEND_ZEROMQ_TRUE='#'
+ REMOTEBACKEND_ZEROMQ_FALSE=
+fi
+
+
+
+ if test "x$enable_remotebackend_zeromq" != "xno"; then :
+
+ if test "x$have_remotebackend" = "xyes"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for LIBZMQ" >&5
+$as_echo_n "checking for LIBZMQ... " >&6; }
+
+if test -n "$LIBZMQ_CFLAGS"; then
+ pkg_cv_LIBZMQ_CFLAGS="$LIBZMQ_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzmq\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libzmq") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBZMQ_CFLAGS=`$PKG_CONFIG --cflags "libzmq" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$LIBZMQ_LIBS"; then
+ pkg_cv_LIBZMQ_LIBS="$LIBZMQ_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libzmq\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "libzmq") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_LIBZMQ_LIBS=`$PKG_CONFIG --libs "libzmq" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ LIBZMQ_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libzmq" 2>&1`
+ else
+ LIBZMQ_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libzmq" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$LIBZMQ_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find libzmq" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find libzmq" "$LINENO" 5
+
+else
+ LIBZMQ_CFLAGS=$pkg_cv_LIBZMQ_CFLAGS
+ LIBZMQ_LIBS=$pkg_cv_LIBZMQ_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+
+$as_echo "#define HAVE_LIBZMQ 1" >>confdefs.h
+
+
+$as_echo "#define REMOTEBACKEND_ZEROMQ 1" >>confdefs.h
+
+ REMOTEBACKEND_ZEROMQ=yes
+
+fi
+
+ old_CXXFLAGS="$CXXFLAGS"
+ old_LDFLAGS="$LDFLAGS"
+ CXXFLAGS="$CFLAGS $LIBZMQ_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBZMQ_LIBS"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for zmq_msg_send in -lzmq" >&5
+$as_echo_n "checking for zmq_msg_send in -lzmq... " >&6; }
+if ${ac_cv_lib_zmq_zmq_msg_send+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-lzmq $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char zmq_msg_send ();
+int
+main ()
+{
+return zmq_msg_send ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ ac_cv_lib_zmq_zmq_msg_send=yes
+else
+ ac_cv_lib_zmq_zmq_msg_send=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_zmq_zmq_msg_send" >&5
+$as_echo "$ac_cv_lib_zmq_zmq_msg_send" >&6; }
+if test "x$ac_cv_lib_zmq_zmq_msg_send" = xyes; then :
+
+
+$as_echo "#define HAVE_ZMQ_MSG_SEND 1" >>confdefs.h
+
+
+
+fi
+
+ CXXFLAGS="$old_CXXFLAGS"
+ LDFLAGS="$old_LDFLAGS"
+
+else
+ as_fn_error $? "remotebackend \"zeromq\" selected but the \"remote\" backend itself is not selected. Please add \"remote\" to your modules or dynmodules list and re-run configure!" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we will be building and installing the extra tools" >&5
+$as_echo_n "checking whether we will be building and installing the extra tools... " >&6; }
+# Check whether --enable-tools was given.
+if test "${enable_tools+set}" = set; then :
+ enableval=$enable_tools; enable_tools=$enableval
+else
+ enable_tools=no
+
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tools" >&5
+$as_echo "$enable_tools" >&6; }
+ if test "x$enable_tools" != "xno"; then
+ TOOLS_TRUE=
+ TOOLS_FALSE='#'
+else
+ TOOLS_TRUE='#'
+ TOOLS_FALSE=
+fi
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking if we need to link in protobuf" >&5
+$as_echo_n "checking if we need to link in protobuf... " >&6; }
+
+# Check whether --with-protobuf was given.
+if test "${with_protobuf+set}" = set; then :
+ withval=$with_protobuf; with_protobuf=$withval
+else
+ with_protobuf=auto
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $with_protobuf" >&5
+$as_echo "$with_protobuf" >&6; }
+
+ if test "x$with_protobuf" != "xno"; then :
+
+ if test "x$with_protobuf" = "xyes" -o "x$with_protobuf" = "xauto"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for PROTOBUF" >&5
+$as_echo_n "checking for PROTOBUF... " >&6; }
+
+if test -n "$PROTOBUF_CFLAGS"; then
+ pkg_cv_PROTOBUF_CFLAGS="$PROTOBUF_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"protobuf\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "protobuf") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_PROTOBUF_CFLAGS=`$PKG_CONFIG --cflags "protobuf" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$PROTOBUF_LIBS"; then
+ pkg_cv_PROTOBUF_LIBS="$PROTOBUF_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"protobuf\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "protobuf") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_PROTOBUF_LIBS=`$PKG_CONFIG --libs "protobuf" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ PROTOBUF_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "protobuf" 2>&1`
+ else
+ PROTOBUF_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "protobuf" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$PROTOBUF_PKG_ERRORS" >&5
+
+ :
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ :
+else
+ PROTOBUF_CFLAGS=$pkg_cv_PROTOBUF_CFLAGS
+ PROTOBUF_LIBS=$pkg_cv_PROTOBUF_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ :
+fi
+ # Extract the first word of "protoc", so it can be a program name with args.
+set dummy protoc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_PROTOC+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ if test -n "$PROTOC"; then
+ ac_cv_prog_PROTOC="$PROTOC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+ ac_cv_prog_PROTOC="protoc"
+ $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+ break 2
+ fi
+done
+ done
+IFS=$as_save_IFS
+
+fi
+fi
+PROTOC=$ac_cv_prog_PROTOC
+if test -n "$PROTOC"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PROTOC" >&5
+$as_echo "$PROTOC" >&6; }
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+fi
+
+fi
+ if test "x$with_protobuf" = "xyes"; then :
+
+ if test x"$PROTOBUF_LIBS" = "x"; then :
+
+ as_fn_error $? "Protobuf requested but libraries were not found" "$LINENO" 5
+
+fi
+ if test x"$PROTOC" = "x"; then :
+
+ as_fn_error $? "Protobuf requested but the protobuf compiler was not found" "$LINENO" 5
+
+fi
+
+fi
+ if test x"$PROTOBUF_LIBS" != "x"; then
+ HAVE_PROTOBUF_TRUE=
+ HAVE_PROTOBUF_FALSE='#'
+else
+ HAVE_PROTOBUF_TRUE='#'
+ HAVE_PROTOBUF_FALSE=
+fi
+
+ if test x"$PROTOC" != "x"; then
+ HAVE_PROTOC_TRUE=
+ HAVE_PROTOC_FALSE='#'
+else
+ HAVE_PROTOC_TRUE='#'
+ HAVE_PROTOC_FALSE=
+fi
+
+ if test x"$PROTOBUF_LIBS" != "x"; then :
+
+$as_echo "#define HAVE_PROTOBUF 1" >>confdefs.h
+
+fi
+
+
+
+ if test "x$needoracle" = "xyes"; then
+ ORACLE_TRUE=
+ ORACLE_FALSE='#'
+else
+ ORACLE_TRUE='#'
+ ORACLE_FALSE=
+fi
+
+
+ if test "x$needldap" = "xyes"; then
+ LDAP_TRUE=
+ LDAP_FALSE='#'
+else
+ LDAP_TRUE='#'
+ LDAP_FALSE=
+fi
+
+
+
+ if test "x$needsqlite3" = "xyes"; then :
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SQLITE3" >&5
+$as_echo_n "checking for SQLITE3... " >&6; }
+
+if test -n "$SQLITE3_CFLAGS"; then
+ pkg_cv_SQLITE3_CFLAGS="$SQLITE3_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "sqlite3") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_SQLITE3_CFLAGS=`$PKG_CONFIG --cflags "sqlite3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$SQLITE3_LIBS"; then
+ pkg_cv_SQLITE3_LIBS="$SQLITE3_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sqlite3\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "sqlite3") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_SQLITE3_LIBS=`$PKG_CONFIG --libs "sqlite3" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ SQLITE3_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sqlite3" 2>&1`
+ else
+ SQLITE3_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sqlite3" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$SQLITE3_PKG_ERRORS" >&5
+
+ as_fn_error $? "Could not find libsqlite3" "$LINENO" 5
+
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Could not find libsqlite3" "$LINENO" 5
+
+else
+ SQLITE3_CFLAGS=$pkg_cv_SQLITE3_CFLAGS
+ SQLITE3_LIBS=$pkg_cv_SQLITE3_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+$as_echo "#define HAVE_SQLITE3 1" >>confdefs.h
+
+fi
+
+fi
+
+ if test "x$needsqlite3" = "xyes"; then
+ SQLITE3_TRUE=
+ SQLITE3_FALSE='#'
+else
+ SQLITE3_TRUE='#'
+ SQLITE3_FALSE=
+fi
+
+
+for a in $modules; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can build module \"${a}\"" >&5
+$as_echo_n "checking whether we can build module \"${a}\"... " >&6; }
+ if [ -d "$srcdir/modules/${a}backend" ]; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ moduledirs="$moduledirs ${a}backend"
+
+ for b in `cat $srcdir/modules/${a}backend/OBJECTFILES`; do
+ moduleobjects="$moduleobjects ../modules/${a}backend/$b"
+ done
+ modulelibs="$modulelibs `cat $srcdir/modules/${a}backend/OBJECTLIBS`"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Do not know how to build module \"$a\", \"$srcdir/modules/${a}backend\" does not exist! Please review --with-modules parameter for supported values." "$LINENO" 5
+ fi
+done
+
+for a in $dynmodules; do
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we can build dynamic module \"${a}\"" >&5
+$as_echo_n "checking whether we can build dynamic module \"${a}\"... " >&6; }
+ if [ -d "$srcdir/modules/${a}backend" ]; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+ moduledirs="$moduledirs ${a}backend"
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ as_fn_error $? "Do not know how to build module \"$a\", \"$srcdir/modules/${a}backend\" does not exist! Please review --with-dynmodules parameter for supported values." "$LINENO" 5
+ fi
+done
+
+
+
+
+# Check whether --enable-systemd was given.
+if test "${enable_systemd+set}" = set; then :
+ enableval=$enable_systemd;
+fi
+
+
+if test "x$enable_systemd" = "xno"; then :
+
+ ax_cv_systemd="n"
+
+elif test "x$enable_systemd" = "xyes"; then :
+
+ ax_cv_systemd="y"
+
+elif test -z $ax_cv_systemd; then :
+
+ ax_cv_systemd="n"
+
+fi
+systemd=$ax_cv_systemd
+
+
+
+
+# Check whether --with-systemd was given.
+if test "${with_systemd+set}" = set; then :
+ withval=$with_systemd; SYSTEMD_DIR="$withval"
+else
+ SYSTEMD_DIR=""
+fi
+
+
+
+
+# Check whether --with-systemd was given.
+if test "${with_systemd+set}" = set; then :
+ withval=$with_systemd; SYSTEMD_MODULES_LOAD="$withval"
+else
+ SYSTEMD_MODULES_LOAD=""
+fi
+
+
+
+
+
+ ac_fn_cxx_check_header_mongrel "$LINENO" "systemd/sd-daemon.h" "ac_cv_header_systemd_sd_daemon_h" "$ac_includes_default"
+if test "x$ac_cv_header_systemd_sd_daemon_h" = xyes; then :
+
+ for libname in systemd-daemon systemd; do
+ as_ac_Lib=`$as_echo "ac_cv_lib_$libname''_sd_listen_fds" | $as_tr_sh`
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for sd_listen_fds in -l$libname" >&5
+$as_echo_n "checking for sd_listen_fds in -l$libname... " >&6; }
+if eval \${$as_ac_Lib+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+ ac_check_lib_save_LIBS=$LIBS
+LIBS="-l$libname $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+/* Override any GCC internal prototype to avoid an error.
+ Use char because int might match the return type of a GCC
+ builtin and then its argument prototype would still apply. */
+#ifdef __cplusplus
+extern "C"
+#endif
+char sd_listen_fds ();
+int
+main ()
+{
+return sd_listen_fds ();
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ eval "$as_ac_Lib=yes"
+else
+ eval "$as_ac_Lib=no"
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+eval ac_res=\$$as_ac_Lib
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+if eval test \"x\$"$as_ac_Lib"\" = x"yes"; then :
+
+ libsystemd_daemon="lib$libname"
+ systemd=y
+ libsystemd=y
+
+fi
+
+ done
+
+fi
+
+
+
+
+ if test "x$enable_systemd" != "xno"; then :
+
+ if test "x$systemd" = "xy" ; then :
+
+
+$as_echo "#define HAVE_SYSTEMD 1" >>confdefs.h
+
+ systemd=y
+
+
+ if test "x$libsystemd" = x; then :
+
+ as_fn_error $? "Unable to find a suitable libsystemd library" "$LINENO" 5
+
+fi
+
+
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SYSTEMD" >&5
+$as_echo_n "checking for SYSTEMD... " >&6; }
+
+if test -n "$SYSTEMD_CFLAGS"; then
+ pkg_cv_SYSTEMD_CFLAGS="$SYSTEMD_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_SYSTEMD_CFLAGS=`$PKG_CONFIG --cflags "$libsystemd_daemon" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+if test -n "$SYSTEMD_LIBS"; then
+ pkg_cv_SYSTEMD_LIBS="$SYSTEMD_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+ if test -n "$PKG_CONFIG" && \
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"\$libsystemd_daemon\""; } >&5
+ ($PKG_CONFIG --exists --print-errors "$libsystemd_daemon") 2>&5
+ ac_status=$?
+ $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+ test $ac_status = 0; }; then
+ pkg_cv_SYSTEMD_LIBS=`$PKG_CONFIG --libs "$libsystemd_daemon" 2>/dev/null`
+ test "x$?" != "x0" && pkg_failed=yes
+else
+ pkg_failed=yes
+fi
+ else
+ pkg_failed=untried
+fi
+
+
+
+if test $pkg_failed = yes; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi
+ if test $_pkg_short_errors_supported = yes; then
+ SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
+ else
+ SYSTEMD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "$libsystemd_daemon" 2>&1`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$SYSTEMD_PKG_ERRORS" >&5
+
+ as_fn_error $? "Package requirements ($libsystemd_daemon) were not met:
+
+$SYSTEMD_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+Alternatively, you may set the environment variables SYSTEMD_CFLAGS
+and SYSTEMD_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details." "$LINENO" 5
+elif test $pkg_failed = untried; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+ { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+Alternatively, you may set the environment variables SYSTEMD_CFLAGS
+and SYSTEMD_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.
+
+To get pkg-config, see <http://pkg-config.freedesktop.org/>.
+See \`config.log' for more details" "$LINENO" 5; }
+else
+ SYSTEMD_CFLAGS=$pkg_cv_SYSTEMD_CFLAGS
+ SYSTEMD_LIBS=$pkg_cv_SYSTEMD_LIBS
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+
+fi
+
+
+
+ if test "x$SYSTEMD_DIR" = x; then :
+
+ SYSTEMD_DIR="\$(prefix)/lib/systemd/system/"
+
+fi
+
+ if test "x$SYSTEMD_DIR" = x; then :
+
+ as_fn_error $? "SYSTEMD_DIR is unset" "$LINENO" 5
+
+fi
+
+ if test "x$SYSTEMD_MODULES_LOAD" = x; then :
+
+ SYSTEMD_MODULES_LOAD="\$(prefix)/lib/modules-load.d/"
+
+fi
+
+ if test "x$SYSTEMD_MODULES_LOAD" = x; then :
+
+ as_fn_error $? "SYSTEMD_MODULES_LOAD is unset" "$LINENO" 5
+
+fi
+
+
+else
+ systemd=n
+fi
+
+else
+ systemd=n
+fi
+
+
+ if test x"$systemd" = "xy" ; then
+ HAVE_SYSTEMD_TRUE=
+ HAVE_SYSTEMD_FALSE='#'
+else
+ HAVE_SYSTEMD_TRUE='#'
+ HAVE_SYSTEMD_FALSE=
+fi
+
+
+LDFLAGS="$RELRO_LDFLAGS $LDFLAGS"
+
+CFLAGS="$PIE_CFLAGS $CFLAGS"
+CXXFLAGS="$PIE_CFLAGS $CXXFLAGS"
+PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS"
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable code coverage" >&5
+$as_echo_n "checking whether to enable code coverage... " >&6; }
+ # Check whether --enable-coverage was given.
+if test "${enable_coverage+set}" = set; then :
+ enableval=$enable_coverage; enable_coverage=$enableval
+else
+ enable_coverage=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_coverage" >&5
+$as_echo "$enable_coverage" >&6; }
+ if test "x$enable_coverage" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fprofile-arcs -ftest-coverage" >&5
+$as_echo_n "checking whether C++ compiler handles -fprofile-arcs -ftest-coverage... " >&6; }
+if ${gl_cv_warn_cxx__fprofile_arcs__ftest_coverage+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fprofile-arcs -ftest-coverage"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fprofile_arcs__ftest_coverage=yes
+else
+ gl_cv_warn_cxx__fprofile_arcs__ftest_coverage=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" >&5
+$as_echo "$gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" >&6; }
+if test "x$gl_cv_warn_cxx__fprofile_arcs__ftest_coverage" = xyes; then :
+
+ CXXFLAGS="$CXXFLAGS -U_FORTIFY_SOURCE -g -O0 -fprofile-arcs -ftest-coverage"
+
+else
+
+ as_fn_error $? "$CXX does not support gathering coverage data" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable AddressSanitizer" >&5
+$as_echo_n "checking whether to enable AddressSanitizer... " >&6; }
+ # Check whether --enable-asan was given.
+if test "${enable_asan+set}" = set; then :
+ enableval=$enable_asan; enable_asan=$enableval
+else
+ enable_asan=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_asan" >&5
+$as_echo "$enable_asan" >&6; }
+
+ if test "x$enable_asan" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=address" >&5
+$as_echo_n "checking whether C++ compiler handles -fsanitize=address... " >&6; }
+if ${gl_cv_warn_cxx__fsanitize_address+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=address"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fsanitize_address=yes
+else
+ gl_cv_warn_cxx__fsanitize_address=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_address" >&5
+$as_echo "$gl_cv_warn_cxx__fsanitize_address" >&6; }
+if test "x$gl_cv_warn_cxx__fsanitize_address" = xyes; then :
+ SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"
+else
+ as_fn_error $? "Cannot enable AddressSanitizer" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable MemorySanitizer" >&5
+$as_echo_n "checking whether to enable MemorySanitizer... " >&6; }
+ # Check whether --enable-msan was given.
+if test "${enable_msan+set}" = set; then :
+ enableval=$enable_msan; enable_msan=$enableval
+else
+ enable_msan=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_msan" >&5
+$as_echo "$enable_msan" >&6; }
+
+ if test "x$enable_msan" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=memory" >&5
+$as_echo_n "checking whether C++ compiler handles -fsanitize=memory... " >&6; }
+if ${gl_cv_warn_cxx__fsanitize_memory+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=memory"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fsanitize_memory=yes
+else
+ gl_cv_warn_cxx__fsanitize_memory=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_memory" >&5
+$as_echo "$gl_cv_warn_cxx__fsanitize_memory" >&6; }
+if test "x$gl_cv_warn_cxx__fsanitize_memory" = xyes; then :
+ SANITIZER_FLAGS="-fsanitize=memory $SANITIZER_FLAGS"
+else
+ as_fn_error $? "Cannot enable MemorySanitizer" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable ThreadSanitizer" >&5
+$as_echo_n "checking whether to enable ThreadSanitizer... " >&6; }
+ # Check whether --enable-tsan was given.
+if test "${enable_tsan+set}" = set; then :
+ enableval=$enable_tsan; enable_tsan=$enableval
+else
+ enable_tsan=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_tsan" >&5
+$as_echo "$enable_tsan" >&6; }
+
+ if test "x$enable_tsan" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=thread" >&5
+$as_echo_n "checking whether C++ compiler handles -fsanitize=thread... " >&6; }
+if ${gl_cv_warn_cxx__fsanitize_thread+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=thread"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fsanitize_thread=yes
+else
+ gl_cv_warn_cxx__fsanitize_thread=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_thread" >&5
+$as_echo "$gl_cv_warn_cxx__fsanitize_thread" >&6; }
+if test "x$gl_cv_warn_cxx__fsanitize_thread" = xyes; then :
+ SANITIZER_FLAGS="-fsanitize=thread $SANITIZER_FLAGS"
+else
+ as_fn_error $? "Cannot enable ThreadSanitizer" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable LeakSanitizer" >&5
+$as_echo_n "checking whether to enable LeakSanitizer... " >&6; }
+ # Check whether --enable-lsan was given.
+if test "${enable_lsan+set}" = set; then :
+ enableval=$enable_lsan; enable_lsan=$enableval
+else
+ enable_lsan=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_lsan" >&5
+$as_echo "$enable_lsan" >&6; }
+
+ if test "x$enable_lsan" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=leak" >&5
+$as_echo_n "checking whether C++ compiler handles -fsanitize=leak... " >&6; }
+if ${gl_cv_warn_cxx__fsanitize_leak+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=leak"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fsanitize_leak=yes
+else
+ gl_cv_warn_cxx__fsanitize_leak=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_leak" >&5
+$as_echo "$gl_cv_warn_cxx__fsanitize_leak" >&6; }
+if test "x$gl_cv_warn_cxx__fsanitize_leak" = xyes; then :
+ SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS"
+else
+ as_fn_error $? "Cannot enable LeakSanitizer" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable Undefined Behaviour Sanitizer" >&5
+$as_echo_n "checking whether to enable Undefined Behaviour Sanitizer... " >&6; }
+ # Check whether --enable-ubsan was given.
+if test "${enable_ubsan+set}" = set; then :
+ enableval=$enable_ubsan; enable_ubsan=$enableval
+else
+ enable_ubsan=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_ubsan" >&5
+$as_echo "$enable_ubsan" >&6; }
+
+ if test "x$enable_ubsan" != "xno"; then :
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fsanitize=undefined" >&5
+$as_echo_n "checking whether C++ compiler handles -fsanitize=undefined... " >&6; }
+if ${gl_cv_warn_cxx__fsanitize_undefined+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fsanitize=undefined"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fsanitize_undefined=yes
+else
+ gl_cv_warn_cxx__fsanitize_undefined=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fsanitize_undefined" >&5
+$as_echo "$gl_cv_warn_cxx__fsanitize_undefined" >&6; }
+if test "x$gl_cv_warn_cxx__fsanitize_undefined" = xyes; then :
+ SANITIZER_FLAGS="-fsanitize=undefined $SANITIZER_FLAGS"
+else
+ as_fn_error $? "Cannot enable Undefined Behaviour Sanitizer" "$LINENO" 5
+
+fi
+
+
+fi
+
+
+
+ if test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"; then :
+
+ as_fn_error $? "Address Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5
+
+fi
+
+ if test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"; then :
+
+ as_fn_error $? "Memory Sanitizer is not compatible with Address Sanitizer" "$LINENO" 5
+
+fi
+
+ if test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"; then :
+
+ as_fn_error $? "Memory Sanitizer is not compatible with Leak Sanitizer" "$LINENO" 5
+
+fi
+
+ if test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"; then :
+
+ as_fn_error $? "Memory Sanitizer is not compatible with Thread Sanitizer" "$LINENO" 5
+
+fi
+
+ if test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"; then :
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether C++ compiler handles -fno-omit-frame-pointer" >&5
+$as_echo_n "checking whether C++ compiler handles -fno-omit-frame-pointer... " >&6; }
+if ${gl_cv_warn_cxx__fno_omit_frame_pointer+:} false; then :
+ $as_echo_n "(cached) " >&6
+else
+
+ gl_save_compiler_FLAGS="$CXXFLAGS"
+ as_fn_append CXXFLAGS " $gl_unknown_warnings_are_errors -fno-omit-frame-pointer"
+ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+
+int
+main ()
+{
+
+ ;
+ return 0;
+}
+_ACEOF
+if ac_fn_cxx_try_link "$LINENO"; then :
+ gl_cv_warn_cxx__fno_omit_frame_pointer=yes
+else
+ gl_cv_warn_cxx__fno_omit_frame_pointer=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+ conftest$ac_exeext conftest.$ac_ext
+ CXXFLAGS="$gl_save_compiler_FLAGS"
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gl_cv_warn_cxx__fno_omit_frame_pointer" >&5
+$as_echo "$gl_cv_warn_cxx__fno_omit_frame_pointer" >&6; }
+if test "x$gl_cv_warn_cxx__fno_omit_frame_pointer" = xyes; then :
+ as_fn_append WARN_CFLAGS " -fno-omit-frame-pointer"
+fi
+
+
+
+fi
+
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable code malloc-trace" >&5
+$as_echo_n "checking whether to enable code malloc-trace... " >&6; }
+ # Check whether --enable-malloc-trace was given.
+if test "${enable_malloc_trace+set}" = set; then :
+ enableval=$enable_malloc_trace; enable_malloc_trace=$enableval
+else
+ enable_malloc_trace=no
+
+fi
+
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $enable_malloc_trace" >&5
+$as_echo "$enable_malloc_trace" >&6; }
+ if test "x$enable_malloc_trace" = "xyes"; then
+ MALLOC_TRACE_TRUE=
+ MALLOC_TRACE_FALSE='#'
+else
+ MALLOC_TRACE_TRUE='#'
+ MALLOC_TRACE_FALSE=
+fi
+
+ if test "x$enable_malloc_trace" = "xyes"; then :
+
+$as_echo "#define MALLOC_TRACE 1" >>confdefs.h
+
+fi
+
+
+
+
+AM_CPPFLAGS="-I\$(top_builddir) -I\$(top_srcdir) $THREADFLAGS $BOOST_CPPFLAGS"
+
+
+
+YAHTTP_CFLAGS='-I$(top_srcdir)/ext/yahttp'
+
+YAHTTP_LIBS='$(top_builddir)/ext/yahttp/yahttp/libyahttp.la'
+
+
+CXXFLAGS="$SANITIZER_FLAGS $CXXFLAGS"
+
+
+if test "x$PACKAGEVERSION" != "x"; then :
+
+cat >>confdefs.h <<_ACEOF
+#define PACKAGEVERSION "$PACKAGEVERSION"
+_ACEOF
+
+
+fi
+
+export moduledirs moduleobjects modulelibs
+
+ac_config_files="$ac_config_files Makefile modules/Makefile pdns/Makefile codedocs/Makefile docs/Makefile pdns/pdns.init ext/Makefile ext/yahttp/Makefile ext/yahttp/yahttp/Makefile ext/json11/Makefile modules/bindbackend/Makefile modules/geoipbackend/Makefile modules/gmysqlbackend/Makefile modules/godbcbackend/Makefile modules/goraclebackend/Makefile modules/gpgsqlbackend/Makefile modules/gsqlite3backend/Makefile modules/ldapbackend/Makefile modules/luabackend/Makefile modules/mydnsbackend/Makefile modules/opendbxbackend/Makefile modules/oraclebackend/Makefile modules/pipebackend/Makefile modules/randombackend/Makefile modules/remotebackend/Makefile modules/tinydnsbackend/Makefile"
+
+cat >confcache <<\_ACEOF
+# This file is a shell script that caches the results of configure
+# tests run on this system so they can be shared between configure
+# scripts and configure runs, see configure's option --config-cache.
+# It is not useful on other systems. If it contains results you don't
+# want to keep, you may remove or edit it.
+#
+# config.status only pays attention to the cache file if you give it
+# the --recheck option to rerun configure.
+#
+# `ac_cv_env_foo' variables (set or unset) will be overridden when
+# loading this file, other *unset* `ac_cv_foo' will be assigned the
+# following values.
+
+_ACEOF
+
+# The following way of writing the cache mishandles newlines in values,
+# but we know of no workaround that is simple, portable, and efficient.
+# So, we kill variables containing newlines.
+# Ultrix sh set writes to stderr and can't be redirected directly,
+# and sets the high bit in the cache file unless we assign to the vars.
+(
+ for ac_var in `(set) 2>&1 | sed -n 's/^\([a-zA-Z_][a-zA-Z0-9_]*\)=.*/\1/p'`; do
+ eval ac_val=\$$ac_var
+ case $ac_val in #(
+ *${as_nl}*)
+ case $ac_var in #(
+ *_cv_*) { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: cache variable $ac_var contains a newline" >&5
+$as_echo "$as_me: WARNING: cache variable $ac_var contains a newline" >&2;} ;;
+ esac
+ case $ac_var in #(
+ _ | IFS | as_nl) ;; #(
+ BASH_ARGV | BASH_SOURCE) eval $ac_var= ;; #(
+ *) { eval $ac_var=; unset $ac_var;} ;;
+ esac ;;
+ esac
+ done
+
+ (set) 2>&1 |
+ case $as_nl`(ac_space=' '; set) 2>&1` in #(
+ *${as_nl}ac_space=\ *)
+ # `set' does not quote correctly, so add quotes: double-quote
+ # substitution turns \\\\ into \\, and sed turns \\ into \.
+ sed -n \
+ "s/'/'\\\\''/g;
+ s/^\\([_$as_cr_alnum]*_cv_[_$as_cr_alnum]*\\)=\\(.*\\)/\\1='\\2'/p"
+ ;; #(
+ *)
+ # `set' quotes correctly as required by POSIX, so do not add quotes.
+ sed -n "/^[_$as_cr_alnum]*_cv_[_$as_cr_alnum]*=/p"
+ ;;
+ esac |
+ sort
+) |
+ sed '
+ /^ac_cv_env_/b end
+ t clear
+ :clear
+ s/^\([^=]*\)=\(.*[{}].*\)$/test "${\1+set}" = set || &/
+ t end
+ s/^\([^=]*\)=\(.*\)$/\1=${\1=\2}/
+ :end' >>confcache
+if diff "$cache_file" confcache >/dev/null 2>&1; then :; else
+ if test -w "$cache_file"; then
+ if test "x$cache_file" != "x/dev/null"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: updating cache $cache_file" >&5
+$as_echo "$as_me: updating cache $cache_file" >&6;}
+ if test ! -f "$cache_file" || test -h "$cache_file"; then
+ cat confcache >"$cache_file"
+ else
+ case $cache_file in #(
+ */* | ?:*)
+ mv -f confcache "$cache_file"$$ &&
+ mv -f "$cache_file"$$ "$cache_file" ;; #(
+ *)
+ mv -f confcache "$cache_file" ;;
+ esac
+ fi
+ fi
+ else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: not updating unwritable cache $cache_file" >&5
+$as_echo "$as_me: not updating unwritable cache $cache_file" >&6;}
+ fi
+fi
+rm -f confcache
+
+test "x$prefix" = xNONE && prefix=$ac_default_prefix
+# Let make expand exec_prefix.
+test "x$exec_prefix" = xNONE && exec_prefix='${prefix}'
+
+DEFS=-DHAVE_CONFIG_H
+
+ac_libobjs=
+ac_ltlibobjs=
+U=
+for ac_i in : $LIBOBJS; do test "x$ac_i" = x: && continue
+ # 1. Remove the extension, and $U if already installed.
+ ac_script='s/\$U\././;s/\.o$//;s/\.obj$//'
+ ac_i=`$as_echo "$ac_i" | sed "$ac_script"`
+ # 2. Prepend LIBOBJDIR. When used with automake>=1.10 LIBOBJDIR
+ # will be set to the directory where LIBOBJS objects are built.
+ as_fn_append ac_libobjs " \${LIBOBJDIR}$ac_i\$U.$ac_objext"
+ as_fn_append ac_ltlibobjs " \${LIBOBJDIR}$ac_i"'$U.lo'
+done
+LIBOBJS=$ac_libobjs
+
+LTLIBOBJS=$ac_ltlibobjs
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking that generated files are newer than configure" >&5
+$as_echo_n "checking that generated files are newer than configure... " >&6; }
+ if test -n "$am_sleep_pid"; then
+ # Hide warnings about reused PIDs.
+ wait $am_sleep_pid 2>/dev/null
+ fi
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: done" >&5
+$as_echo "done" >&6; }
+ if test -n "$EXEEXT"; then
+ am__EXEEXT_TRUE=
+ am__EXEEXT_FALSE='#'
+else
+ am__EXEEXT_TRUE='#'
+ am__EXEEXT_FALSE=
+fi
+
+if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
+ as_fn_error $? "conditional \"AMDEP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${am__fastdepCXX_TRUE}" && test -z "${am__fastdepCXX_FALSE}"; then
+ as_fn_error $? "conditional \"am__fastdepCXX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_FREEBSD_TRUE}" && test -z "${HAVE_FREEBSD_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_FREEBSD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_LINUX_TRUE}" && test -z "${HAVE_LINUX_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_LINUX\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_SOLARIS_TRUE}" && test -z "${HAVE_SOLARIS_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_SOLARIS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LUA_TRUE}" && test -z "${LUA_FALSE}"; then
+ as_fn_error $? "conditional \"LUA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LUA_TRUE}" && test -z "${LUA_FALSE}"; then
+ as_fn_error $? "conditional \"LUA\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_LUA_HPP_TRUE}" && test -z "${HAVE_LUA_HPP_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_LUA_HPP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BOTAN110_TRUE}" && test -z "${BOTAN110_FALSE}"; then
+ as_fn_error $? "conditional \"BOTAN110\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBSODIUM_TRUE}" && test -z "${LIBSODIUM_FALSE}"; then
+ as_fn_error $? "conditional \"LIBSODIUM\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LIBDECAF_TRUE}" && test -z "${LIBDECAF_FALSE}"; then
+ as_fn_error $? "conditional \"LIBDECAF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_BOOST_GE_148_TRUE}" && test -z "${HAVE_BOOST_GE_148_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_BOOST_GE_148\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${UNIT_TESTS_TRUE}" && test -z "${UNIT_TESTS_FALSE}"; then
+ as_fn_error $? "conditional \"UNIT_TESTS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${BACKEND_UNIT_TESTS_TRUE}" && test -z "${BACKEND_UNIT_TESTS_FALSE}"; then
+ as_fn_error $? "conditional \"BACKEND_UNIT_TESTS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_PANDOC_TRUE}" && test -z "${HAVE_PANDOC_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_PANDOC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_MANPAGES_TRUE}" && test -z "${HAVE_MANPAGES_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_MANPAGES\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${FROM_GIT_TRUE}" && test -z "${FROM_GIT_FALSE}"; then
+ as_fn_error $? "conditional \"FROM_GIT\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_RECVMMSG_TRUE}" && test -z "${HAVE_RECVMMSG_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_RECVMMSG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${PKCS11_TRUE}" && test -z "${PKCS11_FALSE}"; then
+ as_fn_error $? "conditional \"PKCS11\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${GSS_TSIG_TRUE}" && test -z "${GSS_TSIG_FALSE}"; then
+ as_fn_error $? "conditional \"GSS_TSIG\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${REMOTEBACKEND_ZEROMQ_TRUE}" && test -z "${REMOTEBACKEND_ZEROMQ_FALSE}"; then
+ as_fn_error $? "conditional \"REMOTEBACKEND_ZEROMQ\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${TOOLS_TRUE}" && test -z "${TOOLS_FALSE}"; then
+ as_fn_error $? "conditional \"TOOLS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_PROTOBUF_TRUE}" && test -z "${HAVE_PROTOBUF_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_PROTOBUF\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_PROTOC_TRUE}" && test -z "${HAVE_PROTOC_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_PROTOC\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${ORACLE_TRUE}" && test -z "${ORACLE_FALSE}"; then
+ as_fn_error $? "conditional \"ORACLE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${LDAP_TRUE}" && test -z "${LDAP_FALSE}"; then
+ as_fn_error $? "conditional \"LDAP\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${SQLITE3_TRUE}" && test -z "${SQLITE3_FALSE}"; then
+ as_fn_error $? "conditional \"SQLITE3\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${HAVE_SYSTEMD_TRUE}" && test -z "${HAVE_SYSTEMD_FALSE}"; then
+ as_fn_error $? "conditional \"HAVE_SYSTEMD\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${MALLOC_TRACE_TRUE}" && test -z "${MALLOC_TRACE_FALSE}"; then
+ as_fn_error $? "conditional \"MALLOC_TRACE\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+
+: "${CONFIG_STATUS=./config.status}"
+ac_write_fail=0
+ac_clean_files_save=$ac_clean_files
+ac_clean_files="$ac_clean_files $CONFIG_STATUS"
+{ $as_echo "$as_me:${as_lineno-$LINENO}: creating $CONFIG_STATUS" >&5
+$as_echo "$as_me: creating $CONFIG_STATUS" >&6;}
+as_write_fail=0
+cat >$CONFIG_STATUS <<_ASEOF || as_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+# Run this file to recreate the current configuration.
+# Compiler output produced by configure, useful for debugging
+# configure, is in config.log if it exists.
+
+debug=false
+ac_cs_recheck=false
+ac_cs_silent=false
+
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$CONFIG_STATUS <<\_ASEOF || as_write_fail=1
+## -------------------- ##
+## M4sh Initialization. ##
+## -------------------- ##
+
+# Be more Bourne compatible
+DUALCASE=1; export DUALCASE # for MKS sh
+if test -n "${ZSH_VERSION+set}" && (emulate sh) >/dev/null 2>&1; then :
+ emulate sh
+ NULLCMD=:
+ # Pre-4.2 versions of Zsh do word splitting on ${1+"$@"}, which
+ # is contrary to our usage. Disable this feature.
+ alias -g '${1+"$@"}'='"$@"'
+ setopt NO_GLOB_SUBST
+else
+ case `(set -o) 2>/dev/null` in #(
+ *posix*) :
+ set -o posix ;; #(
+ *) :
+ ;;
+esac
+fi
+
+
+as_nl='
+'
+export as_nl
+# Printing a long string crashes Solaris 7 /usr/bin/printf.
+as_echo='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo
+as_echo=$as_echo$as_echo$as_echo$as_echo$as_echo$as_echo
+# Prefer a ksh shell builtin over an external printf program on Solaris,
+# but without wasting forks for bash or zsh.
+if test -z "$BASH_VERSION$ZSH_VERSION" \
+ && (test "X`print -r -- $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='print -r --'
+ as_echo_n='print -rn --'
+elif (test "X`printf %s $as_echo`" = "X$as_echo") 2>/dev/null; then
+ as_echo='printf %s\n'
+ as_echo_n='printf %s'
+else
+ if test "X`(/usr/ucb/echo -n -n $as_echo) 2>/dev/null`" = "X-n $as_echo"; then
+ as_echo_body='eval /usr/ucb/echo -n "$1$as_nl"'
+ as_echo_n='/usr/ucb/echo -n'
+ else
+ as_echo_body='eval expr "X$1" : "X\\(.*\\)"'
+ as_echo_n_body='eval
+ arg=$1;
+ case $arg in #(
+ *"$as_nl"*)
+ expr "X$arg" : "X\\(.*\\)$as_nl";
+ arg=`expr "X$arg" : ".*$as_nl\\(.*\\)"`;;
+ esac;
+ expr "X$arg" : "X\\(.*\\)" | tr -d "$as_nl"
+ '
+ export as_echo_n_body
+ as_echo_n='sh -c $as_echo_n_body as_echo'
+ fi
+ export as_echo_body
+ as_echo='sh -c $as_echo_body as_echo'
+fi
+
+# The user is always right.
+if test "${PATH_SEPARATOR+set}" != set; then
+ PATH_SEPARATOR=:
+ (PATH='/bin;/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 && {
+ (PATH='/bin:/bin'; FPATH=$PATH; sh -c :) >/dev/null 2>&1 ||
+ PATH_SEPARATOR=';'
+ }
+fi
+
+
+# IFS
+# We need space, tab and new line, in precisely that order. Quoting is
+# there to prevent editors from complaining about space-tab.
+# (If _AS_PATH_WALK were called with IFS unset, it would disable word
+# splitting by setting IFS to empty value.)
+IFS=" "" $as_nl"
+
+# Find who we are. Look in the path if we contain no directory separator.
+as_myself=
+case $0 in #((
+ *[\\/]* ) as_myself=$0 ;;
+ *) as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ test -r "$as_dir/$0" && as_myself=$as_dir/$0 && break
+ done
+IFS=$as_save_IFS
+
+ ;;
+esac
+# We did not find ourselves, most probably we were run as `sh COMMAND'
+# in which case we are not to be found in the path.
+if test "x$as_myself" = x; then
+ as_myself=$0
+fi
+if test ! -f "$as_myself"; then
+ $as_echo "$as_myself: error: cannot find myself; rerun with an absolute file name" >&2
+ exit 1
+fi
+
+# Unset variables that we do not need and which cause bugs (e.g. in
+# pre-3.0 UWIN ksh). But do not cause bugs in bash 2.01; the "|| exit 1"
+# suppresses any "Segmentation fault" message there. '((' could
+# trigger a bug in pdksh 5.2.14.
+for as_var in BASH_ENV ENV MAIL MAILPATH
+do eval test x\${$as_var+set} = xset \
+ && ( (unset $as_var) || exit 1) >/dev/null 2>&1 && unset $as_var || :
+done
+PS1='$ '
+PS2='> '
+PS4='+ '
+
+# NLS nuisances.
+LC_ALL=C
+export LC_ALL
+LANGUAGE=C
+export LANGUAGE
+
+# CDPATH.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+
+# as_fn_error STATUS ERROR [LINENO LOG_FD]
+# ----------------------------------------
+# Output "`basename $0`: error: ERROR" to stderr. If LINENO and LOG_FD are
+# provided, also output the error to LOG_FD, referencing LINENO. Then exit the
+# script with STATUS, using 1 if that was 0.
+as_fn_error ()
+{
+ as_status=$1; test $as_status -eq 0 && as_status=1
+ if test "$4"; then
+ as_lineno=${as_lineno-"$3"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ $as_echo "$as_me:${as_lineno-$LINENO}: error: $2" >&$4
+ fi
+ $as_echo "$as_me: error: $2" >&2
+ as_fn_exit $as_status
+} # as_fn_error
+
+
+# as_fn_set_status STATUS
+# -----------------------
+# Set $? to STATUS, without forking.
+as_fn_set_status ()
+{
+ return $1
+} # as_fn_set_status
+
+# as_fn_exit STATUS
+# -----------------
+# Exit the shell with STATUS, even in a "trap 0" or "set -e" context.
+as_fn_exit ()
+{
+ set +e
+ as_fn_set_status $1
+ exit $1
+} # as_fn_exit
+
+# as_fn_unset VAR
+# ---------------
+# Portably unset VAR.
+as_fn_unset ()
+{
+ { eval $1=; unset $1;}
+}
+as_unset=as_fn_unset
+# as_fn_append VAR VALUE
+# ----------------------
+# Append the text in VALUE to the end of the definition contained in VAR. Take
+# advantage of any shell optimizations that allow amortized linear growth over
+# repeated appends, instead of the typical quadratic growth present in naive
+# implementations.
+if (eval "as_var=1; as_var+=2; test x\$as_var = x12") 2>/dev/null; then :
+ eval 'as_fn_append ()
+ {
+ eval $1+=\$2
+ }'
+else
+ as_fn_append ()
+ {
+ eval $1=\$$1\$2
+ }
+fi # as_fn_append
+
+# as_fn_arith ARG...
+# ------------------
+# Perform arithmetic evaluation on the ARGs, and store the result in the
+# global $as_val. Take advantage of shells that can avoid forks. The arguments
+# must be portable across $(()) and expr.
+if (eval "test \$(( 1 + 1 )) = 2") 2>/dev/null; then :
+ eval 'as_fn_arith ()
+ {
+ as_val=$(( $* ))
+ }'
+else
+ as_fn_arith ()
+ {
+ as_val=`expr "$@" || test $? -eq 1`
+ }
+fi # as_fn_arith
+
+
+if expr a : '\(a\)' >/dev/null 2>&1 &&
+ test "X`expr 00001 : '.*\(...\)'`" = X001; then
+ as_expr=expr
+else
+ as_expr=false
+fi
+
+if (basename -- /) >/dev/null 2>&1 && test "X`basename -- / 2>&1`" = "X/"; then
+ as_basename=basename
+else
+ as_basename=false
+fi
+
+if (as_dir=`dirname -- /` && test "X$as_dir" = X/) >/dev/null 2>&1; then
+ as_dirname=dirname
+else
+ as_dirname=false
+fi
+
+as_me=`$as_basename -- "$0" ||
+$as_expr X/"$0" : '.*/\([^/][^/]*\)/*$' \| \
+ X"$0" : 'X\(//\)$' \| \
+ X"$0" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X/"$0" |
+ sed '/^.*\/\([^/][^/]*\)\/*$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\/\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+
+# Avoid depending upon Character Ranges.
+as_cr_letters='abcdefghijklmnopqrstuvwxyz'
+as_cr_LETTERS='ABCDEFGHIJKLMNOPQRSTUVWXYZ'
+as_cr_Letters=$as_cr_letters$as_cr_LETTERS
+as_cr_digits='0123456789'
+as_cr_alnum=$as_cr_Letters$as_cr_digits
+
+ECHO_C= ECHO_N= ECHO_T=
+case `echo -n x` in #(((((
+-n*)
+ case `echo 'xy\c'` in
+ *c*) ECHO_T=' ';; # ECHO_T is single tab character.
+ xy) ECHO_C='\c';;
+ *) echo `echo ksh88 bug on AIX 6.1` > /dev/null
+ ECHO_T=' ';;
+ esac;;
+*)
+ ECHO_N='-n';;
+esac
+
+rm -f conf$$ conf$$.exe conf$$.file
+if test -d conf$$.dir; then
+ rm -f conf$$.dir/conf$$.file
+else
+ rm -f conf$$.dir
+ mkdir conf$$.dir 2>/dev/null
+fi
+if (echo >conf$$.file) 2>/dev/null; then
+ if ln -s conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s='ln -s'
+ # ... but there are two gotchas:
+ # 1) On MSYS, both `ln -s file dir' and `ln file dir' fail.
+ # 2) DJGPP < 2.04 has no symlinks; `ln -s' creates a wrapper executable.
+ # In both cases, we have to default to `cp -pR'.
+ ln -s conf$$.file conf$$.dir 2>/dev/null && test ! -f conf$$.exe ||
+ as_ln_s='cp -pR'
+ elif ln conf$$.file conf$$ 2>/dev/null; then
+ as_ln_s=ln
+ else
+ as_ln_s='cp -pR'
+ fi
+else
+ as_ln_s='cp -pR'
+fi
+rm -f conf$$ conf$$.exe conf$$.dir/conf$$.file conf$$.file
+rmdir conf$$.dir 2>/dev/null
+
+
+# as_fn_mkdir_p
+# -------------
+# Create "$as_dir" as a directory, including parents if necessary.
+as_fn_mkdir_p ()
+{
+
+ case $as_dir in #(
+ -*) as_dir=./$as_dir;;
+ esac
+ test -d "$as_dir" || eval $as_mkdir_p || {
+ as_dirs=
+ while :; do
+ case $as_dir in #(
+ *\'*) as_qdir=`$as_echo "$as_dir" | sed "s/'/'\\\\\\\\''/g"`;; #'(
+ *) as_qdir=$as_dir;;
+ esac
+ as_dirs="'$as_qdir' $as_dirs"
+ as_dir=`$as_dirname -- "$as_dir" ||
+$as_expr X"$as_dir" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$as_dir" : 'X\(//\)[^/]' \| \
+ X"$as_dir" : 'X\(//\)$' \| \
+ X"$as_dir" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$as_dir" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ test -d "$as_dir" && break
+ done
+ test -z "$as_dirs" || eval "mkdir $as_dirs"
+ } || test -d "$as_dir" || as_fn_error $? "cannot create directory $as_dir"
+
+
+} # as_fn_mkdir_p
+if mkdir -p . 2>/dev/null; then
+ as_mkdir_p='mkdir -p "$as_dir"'
+else
+ test -d ./-p && rmdir ./-p
+ as_mkdir_p=false
+fi
+
+
+# as_fn_executable_p FILE
+# -----------------------
+# Test if FILE is an executable regular file.
+as_fn_executable_p ()
+{
+ test -f "$1" && test -x "$1"
+} # as_fn_executable_p
+as_test_x='test -x'
+as_executable_p=as_fn_executable_p
+
+# Sed expression to map a string onto a valid CPP name.
+as_tr_cpp="eval sed 'y%*$as_cr_letters%P$as_cr_LETTERS%;s%[^_$as_cr_alnum]%_%g'"
+
+# Sed expression to map a string onto a valid variable name.
+as_tr_sh="eval sed 'y%*+%pp%;s%[^_$as_cr_alnum]%_%g'"
+
+
+exec 6>&1
+## ----------------------------------- ##
+## Main body of $CONFIG_STATUS script. ##
+## ----------------------------------- ##
+_ASEOF
+test $as_write_fail = 0 && chmod +x $CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# Save the log message, to keep $0 and so on meaningful, and to
+# report actual input values of CONFIG_FILES etc. instead of their
+# values after options handling.
+ac_log="
+This file was extended by pdns $as_me 4.0.4, which was
+generated by GNU Autoconf 2.69. Invocation command line was
+
+ CONFIG_FILES = $CONFIG_FILES
+ CONFIG_HEADERS = $CONFIG_HEADERS
+ CONFIG_LINKS = $CONFIG_LINKS
+ CONFIG_COMMANDS = $CONFIG_COMMANDS
+ $ $0 $@
+
+on `(hostname || uname -n) 2>/dev/null | sed 1q`
+"
+
+_ACEOF
+
+case $ac_config_files in *"
+"*) set x $ac_config_files; shift; ac_config_files=$*;;
+esac
+
+case $ac_config_headers in *"
+"*) set x $ac_config_headers; shift; ac_config_headers=$*;;
+esac
+
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+# Files that config.status was made for.
+config_files="$ac_config_files"
+config_headers="$ac_config_headers"
+config_commands="$ac_config_commands"
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ac_cs_usage="\
+\`$as_me' instantiates files and other configuration actions
+from templates according to the current configuration. Unless the files
+and actions are specified as TAGs, all are instantiated by default.
+
+Usage: $0 [OPTION]... [TAG]...
+
+ -h, --help print this help, then exit
+ -V, --version print version number and configuration settings, then exit
+ --config print configuration, then exit
+ -q, --quiet, --silent
+ do not print progress messages
+ -d, --debug don't remove temporary files
+ --recheck update $as_me by reconfiguring in the same conditions
+ --file=FILE[:TEMPLATE]
+ instantiate the configuration file FILE
+ --header=FILE[:TEMPLATE]
+ instantiate the configuration header FILE
+
+Configuration files:
+$config_files
+
+Configuration headers:
+$config_headers
+
+Configuration commands:
+$config_commands
+
+Report bugs to the package provider."
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
+ac_cs_version="\\
+pdns config.status 4.0.4
+configured by $0, generated by GNU Autoconf 2.69,
+ with options \\"\$ac_cs_config\\"
+
+Copyright (C) 2012 Free Software Foundation, Inc.
+This config.status script is free software; the Free Software Foundation
+gives unlimited permission to copy, distribute and modify it."
+
+ac_pwd='$ac_pwd'
+srcdir='$srcdir'
+INSTALL='$INSTALL'
+MKDIR_P='$MKDIR_P'
+AWK='$AWK'
+test -n "\$AWK" || AWK=awk
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# The default lists apply if the user does not specify any file.
+ac_need_defaults=:
+while test $# != 0
+do
+ case $1 in
+ --*=?*)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=`expr "X$1" : 'X[^=]*=\(.*\)'`
+ ac_shift=:
+ ;;
+ --*=)
+ ac_option=`expr "X$1" : 'X\([^=]*\)='`
+ ac_optarg=
+ ac_shift=:
+ ;;
+ *)
+ ac_option=$1
+ ac_optarg=$2
+ ac_shift=shift
+ ;;
+ esac
+
+ case $ac_option in
+ # Handling of the options.
+ -recheck | --recheck | --rechec | --reche | --rech | --rec | --re | --r)
+ ac_cs_recheck=: ;;
+ --version | --versio | --versi | --vers | --ver | --ve | --v | -V )
+ $as_echo "$ac_cs_version"; exit ;;
+ --config | --confi | --conf | --con | --co | --c )
+ $as_echo "$ac_cs_config"; exit ;;
+ --debug | --debu | --deb | --de | --d | -d )
+ debug=: ;;
+ --file | --fil | --fi | --f )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ '') as_fn_error $? "missing file argument" ;;
+ esac
+ as_fn_append CONFIG_FILES " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --header | --heade | --head | --hea )
+ $ac_shift
+ case $ac_optarg in
+ *\'*) ac_optarg=`$as_echo "$ac_optarg" | sed "s/'/'\\\\\\\\''/g"` ;;
+ esac
+ as_fn_append CONFIG_HEADERS " '$ac_optarg'"
+ ac_need_defaults=false;;
+ --he | --h)
+ # Conflict between --help and --header
+ as_fn_error $? "ambiguous option: \`$1'
+Try \`$0 --help' for more information.";;
+ --help | --hel | -h )
+ $as_echo "$ac_cs_usage"; exit ;;
+ -q | -quiet | --quiet | --quie | --qui | --qu | --q \
+ | -silent | --silent | --silen | --sile | --sil | --si | --s)
+ ac_cs_silent=: ;;
+
+ # This is an error.
+ -*) as_fn_error $? "unrecognized option: \`$1'
+Try \`$0 --help' for more information." ;;
+
+ *) as_fn_append ac_config_targets " $1"
+ ac_need_defaults=false ;;
+
+ esac
+ shift
+done
+
+ac_configure_extra_args=
+
+if $ac_cs_silent; then
+ exec 6>/dev/null
+ ac_configure_extra_args="$ac_configure_extra_args --silent"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+if \$ac_cs_recheck; then
+ set X $SHELL '$0' $ac_configure_args \$ac_configure_extra_args --no-create --no-recursion
+ shift
+ \$as_echo "running CONFIG_SHELL=$SHELL \$*" >&6
+ CONFIG_SHELL='$SHELL'
+ export CONFIG_SHELL
+ exec "\$@"
+fi
+
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+exec 5>>config.log
+{
+ echo
+ sed 'h;s/./-/g;s/^.../## /;s/...$/ ##/;p;x;p;x' <<_ASBOX
+## Running $as_me. ##
+_ASBOX
+ $as_echo "$ac_log"
+} >&5
+
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+#
+# INIT-COMMANDS
+#
+AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"
+
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+macro_version='`$ECHO "$macro_version" | $SED "$delay_single_quote_subst"`'
+macro_revision='`$ECHO "$macro_revision" | $SED "$delay_single_quote_subst"`'
+enable_static='`$ECHO "$enable_static" | $SED "$delay_single_quote_subst"`'
+enable_shared='`$ECHO "$enable_shared" | $SED "$delay_single_quote_subst"`'
+pic_mode='`$ECHO "$pic_mode" | $SED "$delay_single_quote_subst"`'
+enable_fast_install='`$ECHO "$enable_fast_install" | $SED "$delay_single_quote_subst"`'
+SHELL='`$ECHO "$SHELL" | $SED "$delay_single_quote_subst"`'
+ECHO='`$ECHO "$ECHO" | $SED "$delay_single_quote_subst"`'
+PATH_SEPARATOR='`$ECHO "$PATH_SEPARATOR" | $SED "$delay_single_quote_subst"`'
+host_alias='`$ECHO "$host_alias" | $SED "$delay_single_quote_subst"`'
+host='`$ECHO "$host" | $SED "$delay_single_quote_subst"`'
+host_os='`$ECHO "$host_os" | $SED "$delay_single_quote_subst"`'
+build_alias='`$ECHO "$build_alias" | $SED "$delay_single_quote_subst"`'
+build='`$ECHO "$build" | $SED "$delay_single_quote_subst"`'
+build_os='`$ECHO "$build_os" | $SED "$delay_single_quote_subst"`'
+SED='`$ECHO "$SED" | $SED "$delay_single_quote_subst"`'
+Xsed='`$ECHO "$Xsed" | $SED "$delay_single_quote_subst"`'
+GREP='`$ECHO "$GREP" | $SED "$delay_single_quote_subst"`'
+EGREP='`$ECHO "$EGREP" | $SED "$delay_single_quote_subst"`'
+FGREP='`$ECHO "$FGREP" | $SED "$delay_single_quote_subst"`'
+LD='`$ECHO "$LD" | $SED "$delay_single_quote_subst"`'
+NM='`$ECHO "$NM" | $SED "$delay_single_quote_subst"`'
+LN_S='`$ECHO "$LN_S" | $SED "$delay_single_quote_subst"`'
+max_cmd_len='`$ECHO "$max_cmd_len" | $SED "$delay_single_quote_subst"`'
+ac_objext='`$ECHO "$ac_objext" | $SED "$delay_single_quote_subst"`'
+exeext='`$ECHO "$exeext" | $SED "$delay_single_quote_subst"`'
+lt_unset='`$ECHO "$lt_unset" | $SED "$delay_single_quote_subst"`'
+lt_SP2NL='`$ECHO "$lt_SP2NL" | $SED "$delay_single_quote_subst"`'
+lt_NL2SP='`$ECHO "$lt_NL2SP" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_host_file_cmd='`$ECHO "$lt_cv_to_host_file_cmd" | $SED "$delay_single_quote_subst"`'
+lt_cv_to_tool_file_cmd='`$ECHO "$lt_cv_to_tool_file_cmd" | $SED "$delay_single_quote_subst"`'
+reload_flag='`$ECHO "$reload_flag" | $SED "$delay_single_quote_subst"`'
+reload_cmds='`$ECHO "$reload_cmds" | $SED "$delay_single_quote_subst"`'
+OBJDUMP='`$ECHO "$OBJDUMP" | $SED "$delay_single_quote_subst"`'
+deplibs_check_method='`$ECHO "$deplibs_check_method" | $SED "$delay_single_quote_subst"`'
+file_magic_cmd='`$ECHO "$file_magic_cmd" | $SED "$delay_single_quote_subst"`'
+file_magic_glob='`$ECHO "$file_magic_glob" | $SED "$delay_single_quote_subst"`'
+want_nocaseglob='`$ECHO "$want_nocaseglob" | $SED "$delay_single_quote_subst"`'
+DLLTOOL='`$ECHO "$DLLTOOL" | $SED "$delay_single_quote_subst"`'
+sharedlib_from_linklib_cmd='`$ECHO "$sharedlib_from_linklib_cmd" | $SED "$delay_single_quote_subst"`'
+AR='`$ECHO "$AR" | $SED "$delay_single_quote_subst"`'
+AR_FLAGS='`$ECHO "$AR_FLAGS" | $SED "$delay_single_quote_subst"`'
+archiver_list_spec='`$ECHO "$archiver_list_spec" | $SED "$delay_single_quote_subst"`'
+STRIP='`$ECHO "$STRIP" | $SED "$delay_single_quote_subst"`'
+RANLIB='`$ECHO "$RANLIB" | $SED "$delay_single_quote_subst"`'
+old_postinstall_cmds='`$ECHO "$old_postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_postuninstall_cmds='`$ECHO "$old_postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds='`$ECHO "$old_archive_cmds" | $SED "$delay_single_quote_subst"`'
+lock_old_archive_extraction='`$ECHO "$lock_old_archive_extraction" | $SED "$delay_single_quote_subst"`'
+CC='`$ECHO "$CC" | $SED "$delay_single_quote_subst"`'
+CFLAGS='`$ECHO "$CFLAGS" | $SED "$delay_single_quote_subst"`'
+compiler='`$ECHO "$compiler" | $SED "$delay_single_quote_subst"`'
+GCC='`$ECHO "$GCC" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_pipe='`$ECHO "$lt_cv_sys_global_symbol_pipe" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_cdecl='`$ECHO "$lt_cv_sys_global_symbol_to_cdecl" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address" | $SED "$delay_single_quote_subst"`'
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix='`$ECHO "$lt_cv_sys_global_symbol_to_c_name_address_lib_prefix" | $SED "$delay_single_quote_subst"`'
+nm_file_list_spec='`$ECHO "$nm_file_list_spec" | $SED "$delay_single_quote_subst"`'
+lt_sysroot='`$ECHO "$lt_sysroot" | $SED "$delay_single_quote_subst"`'
+objdir='`$ECHO "$objdir" | $SED "$delay_single_quote_subst"`'
+MAGIC_CMD='`$ECHO "$MAGIC_CMD" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag='`$ECHO "$lt_prog_compiler_no_builtin_flag" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic='`$ECHO "$lt_prog_compiler_pic" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl='`$ECHO "$lt_prog_compiler_wl" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static='`$ECHO "$lt_prog_compiler_static" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o='`$ECHO "$lt_cv_prog_compiler_c_o" | $SED "$delay_single_quote_subst"`'
+need_locks='`$ECHO "$need_locks" | $SED "$delay_single_quote_subst"`'
+MANIFEST_TOOL='`$ECHO "$MANIFEST_TOOL" | $SED "$delay_single_quote_subst"`'
+DSYMUTIL='`$ECHO "$DSYMUTIL" | $SED "$delay_single_quote_subst"`'
+NMEDIT='`$ECHO "$NMEDIT" | $SED "$delay_single_quote_subst"`'
+LIPO='`$ECHO "$LIPO" | $SED "$delay_single_quote_subst"`'
+OTOOL='`$ECHO "$OTOOL" | $SED "$delay_single_quote_subst"`'
+OTOOL64='`$ECHO "$OTOOL64" | $SED "$delay_single_quote_subst"`'
+libext='`$ECHO "$libext" | $SED "$delay_single_quote_subst"`'
+shrext_cmds='`$ECHO "$shrext_cmds" | $SED "$delay_single_quote_subst"`'
+extract_expsyms_cmds='`$ECHO "$extract_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc='`$ECHO "$archive_cmds_need_lc" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes='`$ECHO "$enable_shared_with_static_runtimes" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec='`$ECHO "$export_dynamic_flag_spec" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec='`$ECHO "$whole_archive_flag_spec" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object='`$ECHO "$compiler_needs_object" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds='`$ECHO "$old_archive_from_new_cmds" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds='`$ECHO "$old_archive_from_expsyms_cmds" | $SED "$delay_single_quote_subst"`'
+archive_cmds='`$ECHO "$archive_cmds" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds='`$ECHO "$archive_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+module_cmds='`$ECHO "$module_cmds" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds='`$ECHO "$module_expsym_cmds" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld='`$ECHO "$with_gnu_ld" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag='`$ECHO "$allow_undefined_flag" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag='`$ECHO "$no_undefined_flag" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec='`$ECHO "$hardcode_libdir_flag_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator='`$ECHO "$hardcode_libdir_separator" | $SED "$delay_single_quote_subst"`'
+hardcode_direct='`$ECHO "$hardcode_direct" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute='`$ECHO "$hardcode_direct_absolute" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L='`$ECHO "$hardcode_minus_L" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var='`$ECHO "$hardcode_shlibpath_var" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic='`$ECHO "$hardcode_automatic" | $SED "$delay_single_quote_subst"`'
+inherit_rpath='`$ECHO "$inherit_rpath" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs='`$ECHO "$link_all_deplibs" | $SED "$delay_single_quote_subst"`'
+always_export_symbols='`$ECHO "$always_export_symbols" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds='`$ECHO "$export_symbols_cmds" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms='`$ECHO "$exclude_expsyms" | $SED "$delay_single_quote_subst"`'
+include_expsyms='`$ECHO "$include_expsyms" | $SED "$delay_single_quote_subst"`'
+prelink_cmds='`$ECHO "$prelink_cmds" | $SED "$delay_single_quote_subst"`'
+postlink_cmds='`$ECHO "$postlink_cmds" | $SED "$delay_single_quote_subst"`'
+file_list_spec='`$ECHO "$file_list_spec" | $SED "$delay_single_quote_subst"`'
+variables_saved_for_relink='`$ECHO "$variables_saved_for_relink" | $SED "$delay_single_quote_subst"`'
+need_lib_prefix='`$ECHO "$need_lib_prefix" | $SED "$delay_single_quote_subst"`'
+need_version='`$ECHO "$need_version" | $SED "$delay_single_quote_subst"`'
+version_type='`$ECHO "$version_type" | $SED "$delay_single_quote_subst"`'
+runpath_var='`$ECHO "$runpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_var='`$ECHO "$shlibpath_var" | $SED "$delay_single_quote_subst"`'
+shlibpath_overrides_runpath='`$ECHO "$shlibpath_overrides_runpath" | $SED "$delay_single_quote_subst"`'
+libname_spec='`$ECHO "$libname_spec" | $SED "$delay_single_quote_subst"`'
+library_names_spec='`$ECHO "$library_names_spec" | $SED "$delay_single_quote_subst"`'
+soname_spec='`$ECHO "$soname_spec" | $SED "$delay_single_quote_subst"`'
+install_override_mode='`$ECHO "$install_override_mode" | $SED "$delay_single_quote_subst"`'
+postinstall_cmds='`$ECHO "$postinstall_cmds" | $SED "$delay_single_quote_subst"`'
+postuninstall_cmds='`$ECHO "$postuninstall_cmds" | $SED "$delay_single_quote_subst"`'
+finish_cmds='`$ECHO "$finish_cmds" | $SED "$delay_single_quote_subst"`'
+finish_eval='`$ECHO "$finish_eval" | $SED "$delay_single_quote_subst"`'
+hardcode_into_libs='`$ECHO "$hardcode_into_libs" | $SED "$delay_single_quote_subst"`'
+sys_lib_search_path_spec='`$ECHO "$sys_lib_search_path_spec" | $SED "$delay_single_quote_subst"`'
+sys_lib_dlsearch_path_spec='`$ECHO "$sys_lib_dlsearch_path_spec" | $SED "$delay_single_quote_subst"`'
+hardcode_action='`$ECHO "$hardcode_action" | $SED "$delay_single_quote_subst"`'
+enable_dlopen='`$ECHO "$enable_dlopen" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self='`$ECHO "$enable_dlopen_self" | $SED "$delay_single_quote_subst"`'
+enable_dlopen_self_static='`$ECHO "$enable_dlopen_self_static" | $SED "$delay_single_quote_subst"`'
+old_striplib='`$ECHO "$old_striplib" | $SED "$delay_single_quote_subst"`'
+striplib='`$ECHO "$striplib" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs='`$ECHO "$compiler_lib_search_dirs" | $SED "$delay_single_quote_subst"`'
+predep_objects='`$ECHO "$predep_objects" | $SED "$delay_single_quote_subst"`'
+postdep_objects='`$ECHO "$postdep_objects" | $SED "$delay_single_quote_subst"`'
+predeps='`$ECHO "$predeps" | $SED "$delay_single_quote_subst"`'
+postdeps='`$ECHO "$postdeps" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path='`$ECHO "$compiler_lib_search_path" | $SED "$delay_single_quote_subst"`'
+LD_CXX='`$ECHO "$LD_CXX" | $SED "$delay_single_quote_subst"`'
+reload_flag_CXX='`$ECHO "$reload_flag_CXX" | $SED "$delay_single_quote_subst"`'
+reload_cmds_CXX='`$ECHO "$reload_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_cmds_CXX='`$ECHO "$old_archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_CXX='`$ECHO "$compiler_CXX" | $SED "$delay_single_quote_subst"`'
+GCC_CXX='`$ECHO "$GCC_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_no_builtin_flag_CXX='`$ECHO "$lt_prog_compiler_no_builtin_flag_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_pic_CXX='`$ECHO "$lt_prog_compiler_pic_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_wl_CXX='`$ECHO "$lt_prog_compiler_wl_CXX" | $SED "$delay_single_quote_subst"`'
+lt_prog_compiler_static_CXX='`$ECHO "$lt_prog_compiler_static_CXX" | $SED "$delay_single_quote_subst"`'
+lt_cv_prog_compiler_c_o_CXX='`$ECHO "$lt_cv_prog_compiler_c_o_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_need_lc_CXX='`$ECHO "$archive_cmds_need_lc_CXX" | $SED "$delay_single_quote_subst"`'
+enable_shared_with_static_runtimes_CXX='`$ECHO "$enable_shared_with_static_runtimes_CXX" | $SED "$delay_single_quote_subst"`'
+export_dynamic_flag_spec_CXX='`$ECHO "$export_dynamic_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+whole_archive_flag_spec_CXX='`$ECHO "$whole_archive_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_needs_object_CXX='`$ECHO "$compiler_needs_object_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_new_cmds_CXX='`$ECHO "$old_archive_from_new_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+old_archive_from_expsyms_cmds_CXX='`$ECHO "$old_archive_from_expsyms_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_cmds_CXX='`$ECHO "$archive_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+archive_expsym_cmds_CXX='`$ECHO "$archive_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_cmds_CXX='`$ECHO "$module_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+module_expsym_cmds_CXX='`$ECHO "$module_expsym_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+with_gnu_ld_CXX='`$ECHO "$with_gnu_ld_CXX" | $SED "$delay_single_quote_subst"`'
+allow_undefined_flag_CXX='`$ECHO "$allow_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+no_undefined_flag_CXX='`$ECHO "$no_undefined_flag_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_flag_spec_CXX='`$ECHO "$hardcode_libdir_flag_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_libdir_separator_CXX='`$ECHO "$hardcode_libdir_separator_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_CXX='`$ECHO "$hardcode_direct_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_direct_absolute_CXX='`$ECHO "$hardcode_direct_absolute_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_minus_L_CXX='`$ECHO "$hardcode_minus_L_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_shlibpath_var_CXX='`$ECHO "$hardcode_shlibpath_var_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_automatic_CXX='`$ECHO "$hardcode_automatic_CXX" | $SED "$delay_single_quote_subst"`'
+inherit_rpath_CXX='`$ECHO "$inherit_rpath_CXX" | $SED "$delay_single_quote_subst"`'
+link_all_deplibs_CXX='`$ECHO "$link_all_deplibs_CXX" | $SED "$delay_single_quote_subst"`'
+always_export_symbols_CXX='`$ECHO "$always_export_symbols_CXX" | $SED "$delay_single_quote_subst"`'
+export_symbols_cmds_CXX='`$ECHO "$export_symbols_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+exclude_expsyms_CXX='`$ECHO "$exclude_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+include_expsyms_CXX='`$ECHO "$include_expsyms_CXX" | $SED "$delay_single_quote_subst"`'
+prelink_cmds_CXX='`$ECHO "$prelink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+postlink_cmds_CXX='`$ECHO "$postlink_cmds_CXX" | $SED "$delay_single_quote_subst"`'
+file_list_spec_CXX='`$ECHO "$file_list_spec_CXX" | $SED "$delay_single_quote_subst"`'
+hardcode_action_CXX='`$ECHO "$hardcode_action_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_dirs_CXX='`$ECHO "$compiler_lib_search_dirs_CXX" | $SED "$delay_single_quote_subst"`'
+predep_objects_CXX='`$ECHO "$predep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+postdep_objects_CXX='`$ECHO "$postdep_objects_CXX" | $SED "$delay_single_quote_subst"`'
+predeps_CXX='`$ECHO "$predeps_CXX" | $SED "$delay_single_quote_subst"`'
+postdeps_CXX='`$ECHO "$postdeps_CXX" | $SED "$delay_single_quote_subst"`'
+compiler_lib_search_path_CXX='`$ECHO "$compiler_lib_search_path_CXX" | $SED "$delay_single_quote_subst"`'
+
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in SHELL \
+ECHO \
+PATH_SEPARATOR \
+SED \
+GREP \
+EGREP \
+FGREP \
+LD \
+NM \
+LN_S \
+lt_SP2NL \
+lt_NL2SP \
+reload_flag \
+OBJDUMP \
+deplibs_check_method \
+file_magic_cmd \
+file_magic_glob \
+want_nocaseglob \
+DLLTOOL \
+sharedlib_from_linklib_cmd \
+AR \
+AR_FLAGS \
+archiver_list_spec \
+STRIP \
+RANLIB \
+CC \
+CFLAGS \
+compiler \
+lt_cv_sys_global_symbol_pipe \
+lt_cv_sys_global_symbol_to_cdecl \
+lt_cv_sys_global_symbol_to_c_name_address \
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix \
+nm_file_list_spec \
+lt_prog_compiler_no_builtin_flag \
+lt_prog_compiler_pic \
+lt_prog_compiler_wl \
+lt_prog_compiler_static \
+lt_cv_prog_compiler_c_o \
+need_locks \
+MANIFEST_TOOL \
+DSYMUTIL \
+NMEDIT \
+LIPO \
+OTOOL \
+OTOOL64 \
+shrext_cmds \
+export_dynamic_flag_spec \
+whole_archive_flag_spec \
+compiler_needs_object \
+with_gnu_ld \
+allow_undefined_flag \
+no_undefined_flag \
+hardcode_libdir_flag_spec \
+hardcode_libdir_separator \
+exclude_expsyms \
+include_expsyms \
+file_list_spec \
+variables_saved_for_relink \
+libname_spec \
+library_names_spec \
+soname_spec \
+install_override_mode \
+finish_eval \
+old_striplib \
+striplib \
+compiler_lib_search_dirs \
+predep_objects \
+postdep_objects \
+predeps \
+postdeps \
+compiler_lib_search_path \
+LD_CXX \
+reload_flag_CXX \
+compiler_CXX \
+lt_prog_compiler_no_builtin_flag_CXX \
+lt_prog_compiler_pic_CXX \
+lt_prog_compiler_wl_CXX \
+lt_prog_compiler_static_CXX \
+lt_cv_prog_compiler_c_o_CXX \
+export_dynamic_flag_spec_CXX \
+whole_archive_flag_spec_CXX \
+compiler_needs_object_CXX \
+with_gnu_ld_CXX \
+allow_undefined_flag_CXX \
+no_undefined_flag_CXX \
+hardcode_libdir_flag_spec_CXX \
+hardcode_libdir_separator_CXX \
+exclude_expsyms_CXX \
+include_expsyms_CXX \
+file_list_spec_CXX \
+compiler_lib_search_dirs_CXX \
+predep_objects_CXX \
+postdep_objects_CXX \
+predeps_CXX \
+postdeps_CXX \
+compiler_lib_search_path_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in reload_cmds \
+old_postinstall_cmds \
+old_postuninstall_cmds \
+old_archive_cmds \
+extract_expsyms_cmds \
+old_archive_from_new_cmds \
+old_archive_from_expsyms_cmds \
+archive_cmds \
+archive_expsym_cmds \
+module_cmds \
+module_expsym_cmds \
+export_symbols_cmds \
+prelink_cmds \
+postlink_cmds \
+postinstall_cmds \
+postuninstall_cmds \
+finish_cmds \
+sys_lib_search_path_spec \
+sys_lib_dlsearch_path_spec \
+reload_cmds_CXX \
+old_archive_cmds_CXX \
+old_archive_from_new_cmds_CXX \
+old_archive_from_expsyms_cmds_CXX \
+archive_cmds_CXX \
+archive_expsym_cmds_CXX \
+module_cmds_CXX \
+module_expsym_cmds_CXX \
+export_symbols_cmds_CXX \
+prelink_cmds_CXX \
+postlink_cmds_CXX; do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[\\\\\\\`\\"\\\$]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+ac_aux_dir='$ac_aux_dir'
+xsi_shell='$xsi_shell'
+lt_shell_append='$lt_shell_append'
+
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'
+
+
+
+
+
+
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+
+# Handling of arguments.
+for ac_config_target in $ac_config_targets
+do
+ case $ac_config_target in
+ "config.h") CONFIG_HEADERS="$CONFIG_HEADERS config.h" ;;
+ "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
+ "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
+ "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
+ "modules/Makefile") CONFIG_FILES="$CONFIG_FILES modules/Makefile" ;;
+ "pdns/Makefile") CONFIG_FILES="$CONFIG_FILES pdns/Makefile" ;;
+ "codedocs/Makefile") CONFIG_FILES="$CONFIG_FILES codedocs/Makefile" ;;
+ "docs/Makefile") CONFIG_FILES="$CONFIG_FILES docs/Makefile" ;;
+ "pdns/pdns.init") CONFIG_FILES="$CONFIG_FILES pdns/pdns.init" ;;
+ "ext/Makefile") CONFIG_FILES="$CONFIG_FILES ext/Makefile" ;;
+ "ext/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/Makefile" ;;
+ "ext/yahttp/yahttp/Makefile") CONFIG_FILES="$CONFIG_FILES ext/yahttp/yahttp/Makefile" ;;
+ "ext/json11/Makefile") CONFIG_FILES="$CONFIG_FILES ext/json11/Makefile" ;;
+ "modules/bindbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/bindbackend/Makefile" ;;
+ "modules/geoipbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/geoipbackend/Makefile" ;;
+ "modules/gmysqlbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/gmysqlbackend/Makefile" ;;
+ "modules/godbcbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/godbcbackend/Makefile" ;;
+ "modules/goraclebackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/goraclebackend/Makefile" ;;
+ "modules/gpgsqlbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/gpgsqlbackend/Makefile" ;;
+ "modules/gsqlite3backend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/gsqlite3backend/Makefile" ;;
+ "modules/ldapbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/ldapbackend/Makefile" ;;
+ "modules/luabackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/luabackend/Makefile" ;;
+ "modules/mydnsbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/mydnsbackend/Makefile" ;;
+ "modules/opendbxbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/opendbxbackend/Makefile" ;;
+ "modules/oraclebackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/oraclebackend/Makefile" ;;
+ "modules/pipebackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/pipebackend/Makefile" ;;
+ "modules/randombackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/randombackend/Makefile" ;;
+ "modules/remotebackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/remotebackend/Makefile" ;;
+ "modules/tinydnsbackend/Makefile") CONFIG_FILES="$CONFIG_FILES modules/tinydnsbackend/Makefile" ;;
+
+ *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
+ esac
+done
+
+
+# If the user did not use the arguments to specify the items to instantiate,
+# then the envvar interface is used. Set only those that are not.
+# We use the long form for the default assignment because of an extremely
+# bizarre bug on SunOS 4.1.3.
+if $ac_need_defaults; then
+ test "${CONFIG_FILES+set}" = set || CONFIG_FILES=$config_files
+ test "${CONFIG_HEADERS+set}" = set || CONFIG_HEADERS=$config_headers
+ test "${CONFIG_COMMANDS+set}" = set || CONFIG_COMMANDS=$config_commands
+fi
+
+# Have a temporary directory for convenience. Make it in the build tree
+# simply because there is no reason against having it here, and in addition,
+# creating and moving files from /tmp can sometimes cause problems.
+# Hook for its removal unless debugging.
+# Note that there is a small window in which the directory will not be cleaned:
+# after its creation but before its name has been assigned to `$tmp'.
+$debug ||
+{
+ tmp= ac_tmp=
+ trap 'exit_status=$?
+ : "${ac_tmp:=$tmp}"
+ { test ! -d "$ac_tmp" || rm -fr "$ac_tmp"; } && exit $exit_status
+' 0
+ trap 'as_fn_exit 1' 1 2 13 15
+}
+# Create a (secure) tmp directory for tmp files.
+
+{
+ tmp=`(umask 077 && mktemp -d "./confXXXXXX") 2>/dev/null` &&
+ test -d "$tmp"
+} ||
+{
+ tmp=./conf$$-$RANDOM
+ (umask 077 && mkdir "$tmp")
+} || as_fn_error $? "cannot create a temporary directory in ." "$LINENO" 5
+ac_tmp=$tmp
+
+# Set up the scripts for CONFIG_FILES section.
+# No need to generate them if there are no CONFIG_FILES.
+# This happens for instance with `./config.status config.h'.
+if test -n "$CONFIG_FILES"; then
+
+
+ac_cr=`echo X | tr X '\015'`
+# On cygwin, bash can eat \r inside `` if the user requested igncr.
+# But we know of no other shell where ac_cr would be empty at this
+# point, so we can use a bashism as a fallback.
+if test "x$ac_cr" = x; then
+ eval ac_cr=\$\'\\r\'
+fi
+ac_cs_awk_cr=`$AWK 'BEGIN { print "a\rb" }' </dev/null 2>/dev/null`
+if test "$ac_cs_awk_cr" = "a${ac_cr}b"; then
+ ac_cs_awk_cr='\\r'
+else
+ ac_cs_awk_cr=$ac_cr
+fi
+
+echo 'BEGIN {' >"$ac_tmp/subs1.awk" &&
+_ACEOF
+
+
+{
+ echo "cat >conf$$subs.awk <<_ACEOF" &&
+ echo "$ac_subst_vars" | sed 's/.*/&!$&$ac_delim/' &&
+ echo "_ACEOF"
+} >conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ac_delim_num=`echo "$ac_subst_vars" | grep -c '^'`
+ac_delim='%!_!# '
+for ac_last_try in false false false false false :; do
+ . ./conf$$subs.sh ||
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+
+ ac_delim_n=`sed -n "s/.*$ac_delim\$/X/p" conf$$subs.awk | grep -c X`
+ if test $ac_delim_n = $ac_delim_num; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_STATUS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+rm -f conf$$subs.sh
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+cat >>"\$ac_tmp/subs1.awk" <<\\_ACAWK &&
+_ACEOF
+sed -n '
+h
+s/^/S["/; s/!.*/"]=/
+p
+g
+s/^[^!]*!//
+:repl
+t repl
+s/'"$ac_delim"'$//
+t delim
+:nl
+h
+s/\(.\{148\}\)..*/\1/
+t more1
+s/["\\]/\\&/g; s/^/"/; s/$/\\n"\\/
+p
+n
+b repl
+:more1
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t nl
+:delim
+h
+s/\(.\{148\}\)..*/\1/
+t more2
+s/["\\]/\\&/g; s/^/"/; s/$/"/
+p
+b
+:more2
+s/["\\]/\\&/g; s/^/"/; s/$/"\\/
+p
+g
+s/.\{148\}//
+t delim
+' <conf$$subs.awk | sed '
+/^[^""]/{
+ N
+ s/\n//
+}
+' >>$CONFIG_STATUS || ac_write_fail=1
+rm -f conf$$subs.awk
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+_ACAWK
+cat >>"\$ac_tmp/subs1.awk" <<_ACAWK &&
+ for (key in S) S_is_set[key] = 1
+ FS = "\a"
+
+}
+{
+ line = $ 0
+ nfields = split(line, field, "@")
+ substed = 0
+ len = length(field[1])
+ for (i = 2; i < nfields; i++) {
+ key = field[i]
+ keylen = length(key)
+ if (S_is_set[key]) {
+ value = S[key]
+ line = substr(line, 1, len) "" value "" substr(line, len + keylen + 3)
+ len += length(value) + length(field[++i])
+ substed = 1
+ } else
+ len += 1 + keylen
+ }
+
+ print line
+}
+
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+if sed "s/$ac_cr//" < /dev/null > /dev/null 2>&1; then
+ sed "s/$ac_cr\$//; s/$ac_cr/$ac_cs_awk_cr/g"
+else
+ cat
+fi < "$ac_tmp/subs1.awk" > "$ac_tmp/subs.awk" \
+ || as_fn_error $? "could not setup config files machinery" "$LINENO" 5
+_ACEOF
+
+# VPATH may cause trouble with some makes, so we remove sole $(srcdir),
+# ${srcdir} and @srcdir@ entries from VPATH if srcdir is ".", strip leading and
+# trailing colons and then remove the whole line if VPATH becomes empty
+# (actually we leave an empty line to preserve line numbers).
+if test "x$srcdir" = x.; then
+ ac_vpsub='/^[ ]*VPATH[ ]*=[ ]*/{
+h
+s///
+s/^/:/
+s/[ ]*$/:/
+s/:\$(srcdir):/:/g
+s/:\${srcdir}:/:/g
+s/:@srcdir@:/:/g
+s/^:*//
+s/:*$//
+x
+s/\(=[ ]*\).*/\1/
+G
+s/\n//
+s/^[^=]*=[ ]*$//
+}'
+fi
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+fi # test -n "$CONFIG_FILES"
+
+# Set up the scripts for CONFIG_HEADERS section.
+# No need to generate them if there are no CONFIG_HEADERS.
+# This happens for instance with `./config.status Makefile'.
+if test -n "$CONFIG_HEADERS"; then
+cat >"$ac_tmp/defines.awk" <<\_ACAWK ||
+BEGIN {
+_ACEOF
+
+# Transform confdefs.h into an awk script `defines.awk', embedded as
+# here-document in config.status, that substitutes the proper values into
+# config.h.in to produce config.h.
+
+# Create a delimiter string that does not exist in confdefs.h, to ease
+# handling of long lines.
+ac_delim='%!_!# '
+for ac_last_try in false false :; do
+ ac_tt=`sed -n "/$ac_delim/p" confdefs.h`
+ if test -z "$ac_tt"; then
+ break
+ elif $ac_last_try; then
+ as_fn_error $? "could not make $CONFIG_HEADERS" "$LINENO" 5
+ else
+ ac_delim="$ac_delim!$ac_delim _$ac_delim!! "
+ fi
+done
+
+# For the awk script, D is an array of macro values keyed by name,
+# likewise P contains macro parameters if any. Preserve backslash
+# newline sequences.
+
+ac_word_re=[_$as_cr_Letters][_$as_cr_alnum]*
+sed -n '
+s/.\{148\}/&'"$ac_delim"'/g
+t rset
+:rset
+s/^[ ]*#[ ]*define[ ][ ]*/ /
+t def
+d
+:def
+s/\\$//
+t bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3"/p
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2"/p
+d
+:bsnl
+s/["\\]/\\&/g
+s/^ \('"$ac_word_re"'\)\(([^()]*)\)[ ]*\(.*\)/P["\1"]="\2"\
+D["\1"]=" \3\\\\\\n"\\/p
+t cont
+s/^ \('"$ac_word_re"'\)[ ]*\(.*\)/D["\1"]=" \2\\\\\\n"\\/p
+t cont
+d
+:cont
+n
+s/.\{148\}/&'"$ac_delim"'/g
+t clear
+:clear
+s/\\$//
+t bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/"/p
+d
+:bsnlc
+s/["\\]/\\&/g; s/^/"/; s/$/\\\\\\n"\\/p
+b cont
+' <confdefs.h | sed '
+s/'"$ac_delim"'/"\\\
+"/g' >>$CONFIG_STATUS || ac_write_fail=1
+
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ for (key in D) D_is_set[key] = 1
+ FS = "\a"
+}
+/^[\t ]*#[\t ]*(define|undef)[\t ]+$ac_word_re([\t (]|\$)/ {
+ line = \$ 0
+ split(line, arg, " ")
+ if (arg[1] == "#") {
+ defundef = arg[2]
+ mac1 = arg[3]
+ } else {
+ defundef = substr(arg[1], 2)
+ mac1 = arg[2]
+ }
+ split(mac1, mac2, "(") #)
+ macro = mac2[1]
+ prefix = substr(line, 1, index(line, defundef) - 1)
+ if (D_is_set[macro]) {
+ # Preserve the white space surrounding the "#".
+ print prefix "define", macro P[macro] D[macro]
+ next
+ } else {
+ # Replace #undef with comments. This is necessary, for example,
+ # in the case of _POSIX_SOURCE, which is predefined and required
+ # on some systems where configure will not decide to define it.
+ if (defundef == "undef") {
+ print "/*", prefix defundef, macro, "*/"
+ next
+ }
+ }
+}
+{ print }
+_ACAWK
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+ as_fn_error $? "could not setup config headers machinery" "$LINENO" 5
+fi # test -n "$CONFIG_HEADERS"
+
+
+eval set X " :F $CONFIG_FILES :H $CONFIG_HEADERS :C $CONFIG_COMMANDS"
+shift
+for ac_tag
+do
+ case $ac_tag in
+ :[FHLC]) ac_mode=$ac_tag; continue;;
+ esac
+ case $ac_mode$ac_tag in
+ :[FHL]*:*);;
+ :L* | :C*:*) as_fn_error $? "invalid tag \`$ac_tag'" "$LINENO" 5;;
+ :[FH]-) ac_tag=-:-;;
+ :[FH]*) ac_tag=$ac_tag:$ac_tag.in;;
+ esac
+ ac_save_IFS=$IFS
+ IFS=:
+ set x $ac_tag
+ IFS=$ac_save_IFS
+ shift
+ ac_file=$1
+ shift
+
+ case $ac_mode in
+ :L) ac_source=$1;;
+ :[FH])
+ ac_file_inputs=
+ for ac_f
+ do
+ case $ac_f in
+ -) ac_f="$ac_tmp/stdin";;
+ *) # Look for the file first in the build tree, then in the source tree
+ # (if the path is not absolute). The absolute path cannot be DOS-style,
+ # because $ac_f cannot contain `:'.
+ test -f "$ac_f" ||
+ case $ac_f in
+ [\\/$]*) false;;
+ *) test -f "$srcdir/$ac_f" && ac_f="$srcdir/$ac_f";;
+ esac ||
+ as_fn_error 1 "cannot find input file: \`$ac_f'" "$LINENO" 5;;
+ esac
+ case $ac_f in *\'*) ac_f=`$as_echo "$ac_f" | sed "s/'/'\\\\\\\\''/g"`;; esac
+ as_fn_append ac_file_inputs " '$ac_f'"
+ done
+
+ # Let's still pretend it is `configure' which instantiates (i.e., don't
+ # use $as_me), people would be surprised to read:
+ # /* config.h. Generated by config.status. */
+ configure_input='Generated from '`
+ $as_echo "$*" | sed 's|^[^:]*/||;s|:[^:]*/|, |g'
+ `' by configure.'
+ if test x"$ac_file" != x-; then
+ configure_input="$ac_file. $configure_input"
+ { $as_echo "$as_me:${as_lineno-$LINENO}: creating $ac_file" >&5
+$as_echo "$as_me: creating $ac_file" >&6;}
+ fi
+ # Neutralize special characters interpreted by sed in replacement strings.
+ case $configure_input in #(
+ *\&* | *\|* | *\\* )
+ ac_sed_conf_input=`$as_echo "$configure_input" |
+ sed 's/[\\\\&|]/\\\\&/g'`;; #(
+ *) ac_sed_conf_input=$configure_input;;
+ esac
+
+ case $ac_tag in
+ *:-:* | *:-) cat >"$ac_tmp/stdin" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5 ;;
+ esac
+ ;;
+ esac
+
+ ac_dir=`$as_dirname -- "$ac_file" ||
+$as_expr X"$ac_file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$ac_file" : 'X\(//\)[^/]' \| \
+ X"$ac_file" : 'X\(//\)$' \| \
+ X"$ac_file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$ac_file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir="$ac_dir"; as_fn_mkdir_p
+ ac_builddir=.
+
+case "$ac_dir" in
+.) ac_dir_suffix= ac_top_builddir_sub=. ac_top_build_prefix= ;;
+*)
+ ac_dir_suffix=/`$as_echo "$ac_dir" | sed 's|^\.[\\/]||'`
+ # A ".." for each directory in $ac_dir_suffix.
+ ac_top_builddir_sub=`$as_echo "$ac_dir_suffix" | sed 's|/[^\\/]*|/..|g;s|/||'`
+ case $ac_top_builddir_sub in
+ "") ac_top_builddir_sub=. ac_top_build_prefix= ;;
+ *) ac_top_build_prefix=$ac_top_builddir_sub/ ;;
+ esac ;;
+esac
+ac_abs_top_builddir=$ac_pwd
+ac_abs_builddir=$ac_pwd$ac_dir_suffix
+# for backward compatibility:
+ac_top_builddir=$ac_top_build_prefix
+
+case $srcdir in
+ .) # We are building in place.
+ ac_srcdir=.
+ ac_top_srcdir=$ac_top_builddir_sub
+ ac_abs_top_srcdir=$ac_pwd ;;
+ [\\/]* | ?:[\\/]* ) # Absolute name.
+ ac_srcdir=$srcdir$ac_dir_suffix;
+ ac_top_srcdir=$srcdir
+ ac_abs_top_srcdir=$srcdir ;;
+ *) # Relative name.
+ ac_srcdir=$ac_top_build_prefix$srcdir$ac_dir_suffix
+ ac_top_srcdir=$ac_top_build_prefix$srcdir
+ ac_abs_top_srcdir=$ac_pwd/$srcdir ;;
+esac
+ac_abs_srcdir=$ac_abs_top_srcdir$ac_dir_suffix
+
+
+ case $ac_mode in
+ :F)
+ #
+ # CONFIG_FILE
+ #
+
+ case $INSTALL in
+ [\\/$]* | ?:[\\/]* ) ac_INSTALL=$INSTALL ;;
+ *) ac_INSTALL=$ac_top_build_prefix$INSTALL ;;
+ esac
+ ac_MKDIR_P=$MKDIR_P
+ case $MKDIR_P in
+ [\\/$]* | ?:[\\/]* ) ;;
+ */*) ac_MKDIR_P=$ac_top_build_prefix$MKDIR_P ;;
+ esac
+_ACEOF
+
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+# If the template does not know about datarootdir, expand it.
+# FIXME: This hack should be removed a few years after 2.60.
+ac_datarootdir_hack=; ac_datarootdir_seen=
+ac_sed_dataroot='
+/datarootdir/ {
+ p
+ q
+}
+/@datadir@/p
+/@docdir@/p
+/@infodir@/p
+/@localedir@/p
+/@mandir@/p'
+case `eval "sed -n \"\$ac_sed_dataroot\" $ac_file_inputs"` in
+*datarootdir*) ac_datarootdir_seen=yes;;
+*@datadir@*|*@docdir@*|*@infodir@*|*@localedir@*|*@mandir@*)
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&5
+$as_echo "$as_me: WARNING: $ac_file_inputs seems to ignore the --datarootdir setting" >&2;}
+_ACEOF
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ ac_datarootdir_hack='
+ s&@datadir@&$datadir&g
+ s&@docdir@&$docdir&g
+ s&@infodir@&$infodir&g
+ s&@localedir@&$localedir&g
+ s&@mandir@&$mandir&g
+ s&\\\${datarootdir}&$datarootdir&g' ;;
+esac
+_ACEOF
+
+# Neutralize VPATH when `$srcdir' = `.'.
+# Shell code in configure.ac might set extrasub.
+# FIXME: do we really want to maintain this feature?
+cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
+ac_sed_extra="$ac_vpsub
+$extrasub
+_ACEOF
+cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
+:t
+/@[a-zA-Z_][a-zA-Z_0-9]*@/!b
+s|@configure_input@|$ac_sed_conf_input|;t t
+s&@top_builddir@&$ac_top_builddir_sub&;t t
+s&@top_build_prefix@&$ac_top_build_prefix&;t t
+s&@srcdir@&$ac_srcdir&;t t
+s&@abs_srcdir@&$ac_abs_srcdir&;t t
+s&@top_srcdir@&$ac_top_srcdir&;t t
+s&@abs_top_srcdir@&$ac_abs_top_srcdir&;t t
+s&@builddir@&$ac_builddir&;t t
+s&@abs_builddir@&$ac_abs_builddir&;t t
+s&@abs_top_builddir@&$ac_abs_top_builddir&;t t
+s&@INSTALL@&$ac_INSTALL&;t t
+s&@MKDIR_P@&$ac_MKDIR_P&;t t
+$ac_datarootdir_hack
+"
+eval sed \"\$ac_sed_extra\" "$ac_file_inputs" | $AWK -f "$ac_tmp/subs.awk" \
+ >$ac_tmp/out || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+
+test -z "$ac_datarootdir_hack$ac_datarootdir_seen" &&
+ { ac_out=`sed -n '/\${datarootdir}/p' "$ac_tmp/out"`; test -n "$ac_out"; } &&
+ { ac_out=`sed -n '/^[ ]*datarootdir[ ]*:*=/p' \
+ "$ac_tmp/out"`; test -z "$ac_out"; } &&
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&5
+$as_echo "$as_me: WARNING: $ac_file contains a reference to the variable \`datarootdir'
+which seems to be undefined. Please make sure it is defined" >&2;}
+
+ rm -f "$ac_tmp/stdin"
+ case $ac_file in
+ -) cat "$ac_tmp/out" && rm -f "$ac_tmp/out";;
+ *) rm -f "$ac_file" && mv "$ac_tmp/out" "$ac_file";;
+ esac \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ ;;
+ :H)
+ #
+ # CONFIG_HEADER
+ #
+ if test x"$ac_file" != x-; then
+ {
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs"
+ } >"$ac_tmp/config.h" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ if diff "$ac_file" "$ac_tmp/config.h" >/dev/null 2>&1; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: $ac_file is unchanged" >&5
+$as_echo "$as_me: $ac_file is unchanged" >&6;}
+ else
+ rm -f "$ac_file"
+ mv "$ac_tmp/config.h" "$ac_file" \
+ || as_fn_error $? "could not create $ac_file" "$LINENO" 5
+ fi
+ else
+ $as_echo "/* $configure_input */" \
+ && eval '$AWK -f "$ac_tmp/defines.awk"' "$ac_file_inputs" \
+ || as_fn_error $? "could not create -" "$LINENO" 5
+ fi
+# Compute "$ac_file"'s index in $config_headers.
+_am_arg="$ac_file"
+_am_stamp_count=1
+for _am_header in $config_headers :; do
+ case $_am_header in
+ $_am_arg | $_am_arg:* )
+ break ;;
+ * )
+ _am_stamp_count=`expr $_am_stamp_count + 1` ;;
+ esac
+done
+echo "timestamp for $_am_arg" >`$as_dirname -- "$_am_arg" ||
+$as_expr X"$_am_arg" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$_am_arg" : 'X\(//\)[^/]' \| \
+ X"$_am_arg" : 'X\(//\)$' \| \
+ X"$_am_arg" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$_am_arg" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`/stamp-h$_am_stamp_count
+ ;;
+
+ :C) { $as_echo "$as_me:${as_lineno-$LINENO}: executing $ac_file commands" >&5
+$as_echo "$as_me: executing $ac_file commands" >&6;}
+ ;;
+ esac
+
+
+ case $ac_file$ac_mode in
+ "depfiles":C) test x"$AMDEP_TRUE" != x"" || {
+ # Older Autoconf quotes --file arguments for eval, but not when files
+ # are listed without --file. Let's play safe and only enable the eval
+ # if we detect the quoting.
+ case $CONFIG_FILES in
+ *\'*) eval set x "$CONFIG_FILES" ;;
+ *) set x $CONFIG_FILES ;;
+ esac
+ shift
+ for mf
+ do
+ # Strip MF so we end up with the name of the file.
+ mf=`echo "$mf" | sed -e 's/:.*$//'`
+ # Check whether this is an Automake generated Makefile or not.
+ # We used to match only the files named 'Makefile.in', but
+ # some people rename them; so instead we look at the file content.
+ # Grep'ing the first line is not enough: some people post-process
+ # each Makefile.in and add a new line on top of each file to say so.
+ # Grep'ing the whole file is not good either: AIX grep has a line
+ # limit of 2048, but all sed's we know have understand at least 4000.
+ if sed -n 's,^#.*generated by automake.*,X,p' "$mf" | grep X >/dev/null 2>&1; then
+ dirpart=`$as_dirname -- "$mf" ||
+$as_expr X"$mf" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$mf" : 'X\(//\)[^/]' \| \
+ X"$mf" : 'X\(//\)$' \| \
+ X"$mf" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$mf" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ else
+ continue
+ fi
+ # Extract the definition of DEPDIR, am__include, and am__quote
+ # from the Makefile without running 'make'.
+ DEPDIR=`sed -n 's/^DEPDIR = //p' < "$mf"`
+ test -z "$DEPDIR" && continue
+ am__include=`sed -n 's/^am__include = //p' < "$mf"`
+ test -z "$am__include" && continue
+ am__quote=`sed -n 's/^am__quote = //p' < "$mf"`
+ # Find all dependency output files, they are included files with
+ # $(DEPDIR) in their names. We invoke sed twice because it is the
+ # simplest approach to changing $(DEPDIR) to its actual value in the
+ # expansion.
+ for file in `sed -n "
+ s/^$am__include $am__quote\(.*(DEPDIR).*\)$am__quote"'$/\1/p' <"$mf" | \
+ sed -e 's/\$(DEPDIR)/'"$DEPDIR"'/g'`; do
+ # Make sure the directory exists.
+ test -f "$dirpart/$file" && continue
+ fdir=`$as_dirname -- "$file" ||
+$as_expr X"$file" : 'X\(.*[^/]\)//*[^/][^/]*/*$' \| \
+ X"$file" : 'X\(//\)[^/]' \| \
+ X"$file" : 'X\(//\)$' \| \
+ X"$file" : 'X\(/\)' \| . 2>/dev/null ||
+$as_echo X"$file" |
+ sed '/^X\(.*[^/]\)\/\/*[^/][^/]*\/*$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)[^/].*/{
+ s//\1/
+ q
+ }
+ /^X\(\/\/\)$/{
+ s//\1/
+ q
+ }
+ /^X\(\/\).*/{
+ s//\1/
+ q
+ }
+ s/.*/./; q'`
+ as_dir=$dirpart/$fdir; as_fn_mkdir_p
+ # echo "creating $dirpart/$file"
+ echo '# dummy' > "$dirpart/$file"
+ done
+ done
+}
+ ;;
+ "libtool":C)
+
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+
+# The names of the tagged configurations supported by this script.
+available_tags="CXX "
+
+# ### BEGIN LIBTOOL CONFIG
+
+# Which release of libtool.m4 was used?
+macro_version=$macro_version
+macro_revision=$macro_revision
+
+# Whether or not to build static libraries.
+build_old_libs=$enable_static
+
+# Whether or not to build shared libraries.
+build_libtool_libs=$enable_shared
+
+# What type of objects to build.
+pic_mode=$pic_mode
+
+# Whether or not to optimize for fast installation.
+fast_install=$enable_fast_install
+
+# Shell to use when invoking shell scripts.
+SHELL=$lt_SHELL
+
+# An echo program that protects backslashes.
+ECHO=$lt_ECHO
+
+# The PATH separator for the build system.
+PATH_SEPARATOR=$lt_PATH_SEPARATOR
+
+# The host system.
+host_alias=$host_alias
+host=$host
+host_os=$host_os
+
+# The build system.
+build_alias=$build_alias
+build=$build
+build_os=$build_os
+
+# A sed program that does not truncate output.
+SED=$lt_SED
+
+# Sed that helps us avoid accidentally triggering echo(1) options like -n.
+Xsed="\$SED -e 1s/^X//"
+
+# A grep program that handles long lines.
+GREP=$lt_GREP
+
+# An ERE matcher.
+EGREP=$lt_EGREP
+
+# A literal string matcher.
+FGREP=$lt_FGREP
+
+# A BSD- or MS-compatible name lister.
+NM=$lt_NM
+
+# Whether we need soft or hard links.
+LN_S=$lt_LN_S
+
+# What is the maximum length of a command?
+max_cmd_len=$max_cmd_len
+
+# Object file suffix (normally "o").
+objext=$ac_objext
+
+# Executable file suffix (normally "").
+exeext=$exeext
+
+# whether the shell understands "unset".
+lt_unset=$lt_unset
+
+# turn spaces into newlines.
+SP2NL=$lt_lt_SP2NL
+
+# turn newlines into spaces.
+NL2SP=$lt_lt_NL2SP
+
+# convert \$build file names to \$host format.
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+
+# convert \$build files to toolchain format.
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+
+# An object symbol dumper.
+OBJDUMP=$lt_OBJDUMP
+
+# Method to check whether dependent libraries are shared objects.
+deplibs_check_method=$lt_deplibs_check_method
+
+# Command to use when deplibs_check_method = "file_magic".
+file_magic_cmd=$lt_file_magic_cmd
+
+# How to find potential files when deplibs_check_method = "file_magic".
+file_magic_glob=$lt_file_magic_glob
+
+# Find potential files using nocaseglob when deplibs_check_method = "file_magic".
+want_nocaseglob=$lt_want_nocaseglob
+
+# DLL creation program.
+DLLTOOL=$lt_DLLTOOL
+
+# Command to associate shared and link libraries.
+sharedlib_from_linklib_cmd=$lt_sharedlib_from_linklib_cmd
+
+# The archiver.
+AR=$lt_AR
+
+# Flags to create an archive.
+AR_FLAGS=$lt_AR_FLAGS
+
+# How to feed a file listing to the archiver.
+archiver_list_spec=$lt_archiver_list_spec
+
+# A symbol stripping program.
+STRIP=$lt_STRIP
+
+# Commands used to install an old-style archive.
+RANLIB=$lt_RANLIB
+old_postinstall_cmds=$lt_old_postinstall_cmds
+old_postuninstall_cmds=$lt_old_postuninstall_cmds
+
+# Whether to use a lock for old archive extraction.
+lock_old_archive_extraction=$lock_old_archive_extraction
+
+# A C compiler.
+LTCC=$lt_CC
+
+# LTCC compiler flags.
+LTCFLAGS=$lt_CFLAGS
+
+# Take the output of nm and produce a listing of raw symbols and C names.
+global_symbol_pipe=$lt_lt_cv_sys_global_symbol_pipe
+
+# Transform the output of nm in a proper C declaration.
+global_symbol_to_cdecl=$lt_lt_cv_sys_global_symbol_to_cdecl
+
+# Transform the output of nm in a C name address pair.
+global_symbol_to_c_name_address=$lt_lt_cv_sys_global_symbol_to_c_name_address
+
+# Transform the output of nm in a C name address pair when lib prefix is needed.
+global_symbol_to_c_name_address_lib_prefix=$lt_lt_cv_sys_global_symbol_to_c_name_address_lib_prefix
+
+# Specify filename containing input files for \$NM.
+nm_file_list_spec=$lt_nm_file_list_spec
+
+# The root where to search for dependent libraries,and in which our libraries should be installed.
+lt_sysroot=$lt_sysroot
+
+# The name of the directory that contains temporary libtool files.
+objdir=$objdir
+
+# Used to examine libraries when file_magic_cmd begins with "file".
+MAGIC_CMD=$MAGIC_CMD
+
+# Must we lock files when doing compilation?
+need_locks=$lt_need_locks
+
+# Manifest tool.
+MANIFEST_TOOL=$lt_MANIFEST_TOOL
+
+# Tool to manipulate archived DWARF debug symbol files on Mac OS X.
+DSYMUTIL=$lt_DSYMUTIL
+
+# Tool to change global to local symbols on Mac OS X.
+NMEDIT=$lt_NMEDIT
+
+# Tool to manipulate fat objects and archives on Mac OS X.
+LIPO=$lt_LIPO
+
+# ldd/readelf like tool for Mach-O binaries on Mac OS X.
+OTOOL=$lt_OTOOL
+
+# ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4.
+OTOOL64=$lt_OTOOL64
+
+# Old archive suffix (normally "a").
+libext=$libext
+
+# Shared library suffix (normally ".so").
+shrext_cmds=$lt_shrext_cmds
+
+# The commands to extract the exported symbol list from a shared archive.
+extract_expsyms_cmds=$lt_extract_expsyms_cmds
+
+# Variables whose values should be saved in libtool wrapper scripts and
+# restored at link time.
+variables_saved_for_relink=$lt_variables_saved_for_relink
+
+# Do we need the "lib" prefix for modules?
+need_lib_prefix=$need_lib_prefix
+
+# Do we need a version for libraries?
+need_version=$need_version
+
+# Library versioning type.
+version_type=$version_type
+
+# Shared library runtime path variable.
+runpath_var=$runpath_var
+
+# Shared library path variable.
+shlibpath_var=$shlibpath_var
+
+# Is shlibpath searched before the hard-coded library search path?
+shlibpath_overrides_runpath=$shlibpath_overrides_runpath
+
+# Format of library name prefix.
+libname_spec=$lt_libname_spec
+
+# List of archive names. First name is the real one, the rest are links.
+# The last name is the one that the linker finds with -lNAME
+library_names_spec=$lt_library_names_spec
+
+# The coded name of the library, if different from the real name.
+soname_spec=$lt_soname_spec
+
+# Permission mode override for installation of shared libraries.
+install_override_mode=$lt_install_override_mode
+
+# Command to use after installation of a shared archive.
+postinstall_cmds=$lt_postinstall_cmds
+
+# Command to use after uninstallation of a shared archive.
+postuninstall_cmds=$lt_postuninstall_cmds
+
+# Commands used to finish a libtool library installation in a directory.
+finish_cmds=$lt_finish_cmds
+
+# As "finish_cmds", except a single script fragment to be evaled but
+# not shown.
+finish_eval=$lt_finish_eval
+
+# Whether we should hardcode library paths into libraries.
+hardcode_into_libs=$hardcode_into_libs
+
+# Compile-time system search path for libraries.
+sys_lib_search_path_spec=$lt_sys_lib_search_path_spec
+
+# Run-time system search path for libraries.
+sys_lib_dlsearch_path_spec=$lt_sys_lib_dlsearch_path_spec
+
+# Whether dlopen is supported.
+dlopen_support=$enable_dlopen
+
+# Whether dlopen of programs is supported.
+dlopen_self=$enable_dlopen_self
+
+# Whether dlopen of statically linked programs is supported.
+dlopen_self_static=$enable_dlopen_self_static
+
+# Commands to strip libraries.
+old_striplib=$lt_old_striplib
+striplib=$lt_striplib
+
+
+# The linker used to build libraries.
+LD=$lt_LD
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag
+reload_cmds=$lt_reload_cmds
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds
+
+# A language specific compiler.
+CC=$lt_compiler
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds
+archive_expsym_cmds=$lt_archive_expsym_cmds
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds
+module_expsym_cmds=$lt_module_expsym_cmds
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects
+postdep_objects=$lt_postdep_objects
+predeps=$lt_predeps
+postdeps=$lt_postdeps
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path
+
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ if test x"$xsi_shell" = xyes; then
+ sed -e '/^func_dirname ()$/,/^} # func_dirname /c\
+func_dirname ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+} # Extended-shell func_dirname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_basename ()$/,/^} # func_basename /c\
+func_basename ()\
+{\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_dirname_and_basename ()$/,/^} # func_dirname_and_basename /c\
+func_dirname_and_basename ()\
+{\
+\ case ${1} in\
+\ */*) func_dirname_result="${1%/*}${2}" ;;\
+\ * ) func_dirname_result="${3}" ;;\
+\ esac\
+\ func_basename_result="${1##*/}"\
+} # Extended-shell func_dirname_and_basename implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_stripname ()$/,/^} # func_stripname /c\
+func_stripname ()\
+{\
+\ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are\
+\ # positional parameters, so assign one to ordinary parameter first.\
+\ func_stripname_result=${3}\
+\ func_stripname_result=${func_stripname_result#"${1}"}\
+\ func_stripname_result=${func_stripname_result%"${2}"}\
+} # Extended-shell func_stripname implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_long_opt ()$/,/^} # func_split_long_opt /c\
+func_split_long_opt ()\
+{\
+\ func_split_long_opt_name=${1%%=*}\
+\ func_split_long_opt_arg=${1#*=}\
+} # Extended-shell func_split_long_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_split_short_opt ()$/,/^} # func_split_short_opt /c\
+func_split_short_opt ()\
+{\
+\ func_split_short_opt_arg=${1#??}\
+\ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}\
+} # Extended-shell func_split_short_opt implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_lo2o ()$/,/^} # func_lo2o /c\
+func_lo2o ()\
+{\
+\ case ${1} in\
+\ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;\
+\ *) func_lo2o_result=${1} ;;\
+\ esac\
+} # Extended-shell func_lo2o implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_xform ()$/,/^} # func_xform /c\
+func_xform ()\
+{\
+ func_xform_result=${1%.*}.lo\
+} # Extended-shell func_xform implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_arith ()$/,/^} # func_arith /c\
+func_arith ()\
+{\
+ func_arith_result=$(( $* ))\
+} # Extended-shell func_arith implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_len ()$/,/^} # func_len /c\
+func_len ()\
+{\
+ func_len_result=${#1}\
+} # Extended-shell func_len implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ sed -e '/^func_append ()$/,/^} # func_append /c\
+func_append ()\
+{\
+ eval "${1}+=\\${2}"\
+} # Extended-shell func_append implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ sed -e '/^func_append_quoted ()$/,/^} # func_append_quoted /c\
+func_append_quoted ()\
+{\
+\ func_quote_for_eval "${2}"\
+\ eval "${1}+=\\\\ \\$func_quote_for_eval_result"\
+} # Extended-shell func_append_quoted implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([a-zA-Z_]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Unable to substitute extended shell functions in $ofile" >&5
+$as_echo "$as_me: WARNING: Unable to substitute extended shell functions in $ofile" >&2;}
+fi
+
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+
+
+ cat <<_LT_EOF >> "$ofile"
+
+# ### BEGIN LIBTOOL TAG CONFIG: CXX
+
+# The linker used to build libraries.
+LD=$lt_LD_CXX
+
+# How to create reloadable object files.
+reload_flag=$lt_reload_flag_CXX
+reload_cmds=$lt_reload_cmds_CXX
+
+# Commands used to build an old-style archive.
+old_archive_cmds=$lt_old_archive_cmds_CXX
+
+# A language specific compiler.
+CC=$lt_compiler_CXX
+
+# Is the compiler the GNU compiler?
+with_gcc=$GCC_CXX
+
+# Compiler flag to turn off builtin functions.
+no_builtin_flag=$lt_lt_prog_compiler_no_builtin_flag_CXX
+
+# Additional compiler flags for building library objects.
+pic_flag=$lt_lt_prog_compiler_pic_CXX
+
+# How to pass a linker flag through the compiler.
+wl=$lt_lt_prog_compiler_wl_CXX
+
+# Compiler flag to prevent dynamic linking.
+link_static_flag=$lt_lt_prog_compiler_static_CXX
+
+# Does compiler simultaneously support -c and -o options?
+compiler_c_o=$lt_lt_cv_prog_compiler_c_o_CXX
+
+# Whether or not to add -lc for building shared libraries.
+build_libtool_need_lc=$archive_cmds_need_lc_CXX
+
+# Whether or not to disallow shared libs when runtime libs are static.
+allow_libtool_libs_with_static_runtimes=$enable_shared_with_static_runtimes_CXX
+
+# Compiler flag to allow reflexive dlopens.
+export_dynamic_flag_spec=$lt_export_dynamic_flag_spec_CXX
+
+# Compiler flag to generate shared objects directly from archives.
+whole_archive_flag_spec=$lt_whole_archive_flag_spec_CXX
+
+# Whether the compiler copes with passing no objects directly.
+compiler_needs_object=$lt_compiler_needs_object_CXX
+
+# Create an old-style archive from a shared archive.
+old_archive_from_new_cmds=$lt_old_archive_from_new_cmds_CXX
+
+# Create a temporary old-style archive to link instead of a shared archive.
+old_archive_from_expsyms_cmds=$lt_old_archive_from_expsyms_cmds_CXX
+
+# Commands used to build a shared archive.
+archive_cmds=$lt_archive_cmds_CXX
+archive_expsym_cmds=$lt_archive_expsym_cmds_CXX
+
+# Commands used to build a loadable module if different from building
+# a shared archive.
+module_cmds=$lt_module_cmds_CXX
+module_expsym_cmds=$lt_module_expsym_cmds_CXX
+
+# Whether we are building with GNU ld or not.
+with_gnu_ld=$lt_with_gnu_ld_CXX
+
+# Flag that allows shared libraries with undefined symbols to be built.
+allow_undefined_flag=$lt_allow_undefined_flag_CXX
+
+# Flag that enforces no undefined symbols.
+no_undefined_flag=$lt_no_undefined_flag_CXX
+
+# Flag to hardcode \$libdir into a binary during linking.
+# This must work even if \$libdir does not exist
+hardcode_libdir_flag_spec=$lt_hardcode_libdir_flag_spec_CXX
+
+# Whether we need a single "-rpath" flag with a separated argument.
+hardcode_libdir_separator=$lt_hardcode_libdir_separator_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary.
+hardcode_direct=$hardcode_direct_CXX
+
+# Set to "yes" if using DIR/libNAME\${shared_ext} during linking hardcodes
+# DIR into the resulting binary and the resulting library dependency is
+# "absolute",i.e impossible to change by setting \${shlibpath_var} if the
+# library is relocated.
+hardcode_direct_absolute=$hardcode_direct_absolute_CXX
+
+# Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+# into the resulting binary.
+hardcode_minus_L=$hardcode_minus_L_CXX
+
+# Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+# into the resulting binary.
+hardcode_shlibpath_var=$hardcode_shlibpath_var_CXX
+
+# Set to "yes" if building a shared library automatically hardcodes DIR
+# into the library and all subsequent libraries and executables linked
+# against it.
+hardcode_automatic=$hardcode_automatic_CXX
+
+# Set to yes if linker adds runtime paths of dependent libraries
+# to runtime path list.
+inherit_rpath=$inherit_rpath_CXX
+
+# Whether libtool must link a program against all its dependency libraries.
+link_all_deplibs=$link_all_deplibs_CXX
+
+# Set to "yes" if exported symbols are required.
+always_export_symbols=$always_export_symbols_CXX
+
+# The commands to list exported symbols.
+export_symbols_cmds=$lt_export_symbols_cmds_CXX
+
+# Symbols that should not be listed in the preloaded symbols.
+exclude_expsyms=$lt_exclude_expsyms_CXX
+
+# Symbols that must always be exported.
+include_expsyms=$lt_include_expsyms_CXX
+
+# Commands necessary for linking programs (against libraries) with templates.
+prelink_cmds=$lt_prelink_cmds_CXX
+
+# Commands necessary for finishing linking programs.
+postlink_cmds=$lt_postlink_cmds_CXX
+
+# Specify filename containing input files.
+file_list_spec=$lt_file_list_spec_CXX
+
+# How to hardcode a shared library path into an executable.
+hardcode_action=$hardcode_action_CXX
+
+# The directories searched by this compiler when creating a shared library.
+compiler_lib_search_dirs=$lt_compiler_lib_search_dirs_CXX
+
+# Dependencies to place before and after the objects being linked to
+# create a shared library.
+predep_objects=$lt_predep_objects_CXX
+postdep_objects=$lt_postdep_objects_CXX
+predeps=$lt_predeps_CXX
+postdeps=$lt_postdeps_CXX
+
+# The library search path used internally by the compiler when linking
+# a shared library.
+compiler_lib_search_path=$lt_compiler_lib_search_path_CXX
+
+# ### END LIBTOOL TAG CONFIG: CXX
+_LT_EOF
+
+ ;;
+
+ esac
+done # for ac_tag
+
+
+as_fn_exit 0
+_ACEOF
+ac_clean_files=$ac_clean_files_save
+
+test $ac_write_fail = 0 ||
+ as_fn_error $? "write failure creating $CONFIG_STATUS" "$LINENO" 5
+
+
+# configure is writing to config.log, and then calls config.status.
+# config.status does its own redirection, appending to config.log.
+# Unfortunately, on DOS this fails, as config.log is still kept open
+# by configure, so config.status won't be able to write to it; its
+# output is simply discarded. So we exec the FD to /dev/null,
+# effectively closing config.log, so it can be properly (re)opened and
+# appended to by config.status. When coming back to configure, we
+# need to make the FD available again.
+if test "$no_create" != yes; then
+ ac_cs_success=:
+ ac_config_status_args=
+ test "$silent" = yes &&
+ ac_config_status_args="$ac_config_status_args --quiet"
+ exec 5>/dev/null
+ $SHELL $CONFIG_STATUS $ac_config_status_args || ac_cs_success=false
+ exec 5>>config.log
+ # Use ||, not &&, to avoid exiting from the if with $? = 1, which
+ # would make configure fail if this is the last instruction.
+ $ac_cs_success || as_fn_exit 1
+fi
+if test -n "$ac_unrecognized_opts" && test "$enable_option_checking" != no; then
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: unrecognized options: $ac_unrecognized_opts" >&5
+$as_echo "$as_me: WARNING: unrecognized options: $ac_unrecognized_opts" >&2;}
+fi
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Configuration summary" >&5
+$as_echo "$as_me: Configuration summary" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: =====================" >&5
+$as_echo "$as_me: =====================" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Configured with: $pdns_configure_args" >&5
+$as_echo "$as_me: Configured with: $pdns_configure_args" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CC: $CC" >&5
+$as_echo "$as_me: CC: $CC" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CXX: $CXX" >&5
+$as_echo "$as_me: CXX: $CXX" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: LD: $LD" >&5
+$as_echo "$as_me: LD: $LD" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CFLAGS: $CFLAGS" >&5
+$as_echo "$as_me: CFLAGS: $CFLAGS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CPPFLAGS: $CPPFLAGS" >&5
+$as_echo "$as_me: CPPFLAGS: $CPPFLAGS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: CXXFLAGS: $CXXFLAGS" >&5
+$as_echo "$as_me: CXXFLAGS: $CXXFLAGS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: LDFLAGS: $LDFLAGS" >&5
+$as_echo "$as_me: LDFLAGS: $LDFLAGS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: LIBS: $LIBS" >&5
+$as_echo "$as_me: LIBS: $LIBS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&5
+$as_echo "$as_me: BOOST_CPPFLAGS: $BOOST_CPPFLAGS" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Features enabled" >&5
+$as_echo "$as_me: Features enabled" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: ----------------" >&5
+$as_echo "$as_me: ----------------" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Built-in modules: $modules" >&5
+$as_echo "$as_me: Built-in modules: $modules" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: Dynamic modules: $dynmodules" >&5
+$as_echo "$as_me: Dynamic modules: $dynmodules" >&6;}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
+if test "x$libcrypto_ecdsa" = "xyes"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL ecdsa: yes" >&5
+$as_echo "$as_me: OpenSSL ecdsa: yes" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: OpenSSL ecdsa: no" >&5
+$as_echo "$as_me: OpenSSL ecdsa: no" >&6;}
+
+fi
+if test "x$LIBSODIUM_LIBS" != "x" || test "x$LIBDECAF_LIBS" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ed25519: yes" >&5
+$as_echo "$as_me: ed25519: yes" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ed25519: no" >&5
+$as_echo "$as_me: ed25519: no" >&6;}
+
+fi
+if test "x$LIBDECAF_LIBS" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ed448: yes" >&5
+$as_echo "$as_me: ed448: yes" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ed448: no" >&5
+$as_echo "$as_me: ed448: no" >&6;}
+
+fi
+if test "x$needsqlite3" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: SQLite3: yes" >&5
+$as_echo "$as_me: SQLite3: yes" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: SQLite3: no" >&5
+$as_echo "$as_me: SQLite3: no" >&6;}
+
+fi
+if test "x$LUAPC" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Lua: $LUAPC" >&5
+$as_echo "$as_me: Lua: $LUAPC" >&6;}
+else
+ if test "x$LUAJITPC" != "x"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: LuaJit: $LUAJITPC" >&5
+$as_echo "$as_me: LuaJit: $LUAJITPC" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: Lua/LuaJit: no" >&5
+$as_echo "$as_me: Lua/LuaJit: no" >&6;}
+fi
+
+fi
+if test "x$enable_experimental_gss_tsig" = "xyes"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: GSS-TSIG: yes" >&5
+$as_echo "$as_me: GSS-TSIG: yes" >&6;}
+
+fi
+if test "x$systemd" != "xn"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: yes" >&5
+$as_echo "$as_me: systemd: yes" >&6;}
+else
+ { $as_echo "$as_me:${as_lineno-$LINENO}: systemd: no" >&5
+$as_echo "$as_me: systemd: no" >&6;}
+
+fi
+if test "x$enable_remotebackend_zeromq" != "xno"; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: ZeroMQ connector for remotebackend: yes" >&5
+$as_echo "$as_me: ZeroMQ connector for remotebackend: yes" >&6;}
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: " >&5
+$as_echo "$as_me: " >&6;}
--- /dev/null
+AC_PREREQ([2.61])
+
+AC_INIT([pdns], m4_esyscmd([build-aux/gen-version]))
+
+AC_CONFIG_SRCDIR([pdns/receiver.cc])
+AC_CONFIG_MACRO_DIR([m4])
+AC_CONFIG_HEADERS([config.h])
+AC_CONFIG_AUX_DIR([build-aux])
+
+AC_SUBST([pdns_configure_args], ["$ac_configure_args"])
+AC_DEFINE_UNQUOTED([PDNS_CONFIG_ARGS],
+ ["$pdns_configure_args"],
+ [pdns configure arguments]
+)
+
+AM_INIT_AUTOMAKE([foreign dist-bzip2 no-dist-gzip tar-ustar -Wno-portability subdir-objects parallel-tests 1.11])
+AM_SILENT_RULES([yes])
+
+AC_CANONICAL_HOST
+: ${CFLAGS="-Wall -g -O2"}
+: ${CXXFLAGS="-Wall -g -O2"}
+
+AC_PROG_CC
+AM_PROG_CC_C_O
+PDNS_CHECK_BISON
+PDNS_CHECK_FLEX
+AC_PROG_INSTALL
+AC_PROG_MAKE_SET
+
+AC_PROG_CXX
+AS_IF([test "x$CXX" = "xno" || test "x$CXX:x$GXX" = "xg++:x"],
+ AC_MSG_ERROR([no C++ compiler found])
+)
+
+AC_LANG([C++])
+
+AC_DEFINE([_GNU_SOURCE], [1],
+ [Define _GNU_SOURCE so that we get all necessary prototypes]
+)
+
+# Warn when pkg.m4 is missing
+m4_pattern_forbid([^_?PKG_[A-Z_]+$], [*** pkg.m4 missing, please install pkg-config])
+
+PDNS_CHECK_OS
+
+PDNS_WITH_LUAJIT
+AS_IF([test "x$with_luajit" = "xno"], [
+ PDNS_WITH_LUA
+])
+PDNS_CHECK_LUA_HPP
+
+AX_CXX_COMPILE_STDCXX_11
+
+AC_MSG_CHECKING([whether we will enable compiler security checks])
+AC_ARG_ENABLE([hardening],
+ [AS_HELP_STRING([--disable-hardening], [disable compiler security checks @<:@default=no@:>@])],
+ [enable_hardening=$enableval],
+ [enable_hardening=yes]
+)
+AC_MSG_RESULT([$enable_hardening])
+
+AS_IF([test "x$enable_hardening" != "xno"], [
+ AC_CC_PIE
+ AC_CC_STACK_PROTECTOR
+ AC_CC_PARAM_SSP_BUFFER_SIZE([4])
+ AC_CC_D_FORTIFY_SOURCE
+ AC_LD_RELRO
+])
+
+PDNS_CHECK_NETWORK_LIBS
+
+LT_PREREQ([2.2.2])
+LT_INIT([disable-static dlopen])
+
+
+MC_TM_GMTOFF
+
+# Define full_libdir to be the fully expanded (${exec_prefix}, etc.)
+# "system" library path.
+# We use this to search for other libraries.
+eval full_libdir="\"$libdir\""
+
+# detect pkg-config explicitly
+PKG_PROG_PKG_CONFIG
+
+AC_CHECK_HEADERS(
+ [sys/mman.h],
+ [AC_CHECK_FUNC(
+ [mmap],
+ [AC_DEFINE(HAVE_MMAP, [1], [Define to 1 if you have mmap])],
+ [have_mmap=no]
+ )],
+ [have_mmap=no]
+)
+
+PDNS_ENABLE_BOTAN
+PDNS_CHECK_LIBSODIUM
+PDNS_CHECK_LIBDECAF
+PDNS_CHECK_LIBCRYPTO([
+],[
+ AC_MSG_ERROR([OpenSSL/libcrypto not found])
+ ]
+)
+PDNS_CHECK_LIBCRYPTO_ECDSA
+
+PDNS_CHECK_RAGEL
+PDNS_CHECK_CLOCK_GETTIME
+
+BOOST_REQUIRE([1.35])
+# Boost accumulators, as used by dnsbulktest and dnstcpbench, need 1.48+
+# to be compatible with C++11
+AM_CONDITIONAL([HAVE_BOOST_GE_148], [test "$boost_major_version" -ge 148])
+
+BOOST_PROGRAM_OPTIONS([mt])
+AS_IF([test "$boost_cv_lib_program_options" = "no"], [
+ AC_MSG_ERROR([Boost Program Options library not found])
+])
+PDNS_ENABLE_UNIT_TESTS
+PDNS_ENABLE_REPRODUCIBLE
+
+PDNS_WITH_SQLITE3
+
+PDNS_CHECK_PANDOC
+PDNS_FROM_GIT
+
+dnl Checks for library functions.
+AC_CHECK_FUNCS_ONCE([strcasestr localtime_r recvmmsg])
+
+AM_CONDITIONAL([HAVE_RECVMMSG], [test "x$ac_cv_func_recvmmsg" = "xyes"])
+
+AS_IF([test "x$lt_cv_dlopen" = "xno"],
+ [AC_MSG_ERROR([Your system does not support dlopen])]
+)
+
+AC_SUBST([LIBDL], [$lt_cv_dlopen_libs])
+
+PDNS_ENABLE_VERBOSE_LOGGING
+PDNS_ENABLE_PKCS11
+PDNS_ENABLE_GSS_TSIG
+
+AC_SUBST([socketdir])
+socketdir="/var/run"
+AC_ARG_WITH([socketdir],
+ [AS_HELP_STRING([--with-socketdir], [where the controlsocket lives @<:@default=/var/run@:>@])],
+ [socketdir="$withval"]
+)
+
+modules="bind gmysql random"
+AC_ARG_WITH([modules],
+ [AS_HELP_STRING([--with-modules], [which backends to compile with @<:@default=bind gmysql random@:>@])],
+ [modules="$withval"]
+)
+
+dynmodules="pipe"
+AC_ARG_WITH([dynmodules],
+ [AS_HELP_STRING([--with-dynmodules], [which backends to build for dynamic loading @<:@default=pipe@:>@])],
+ [dynmodules="$withval"]
+)
+
+AC_SUBST([moduledirs])
+AC_SUBST([moduleobjects])
+AC_SUBST([modulelibs])
+AC_DEFINE_UNQUOTED([PDNS_MODULES], "$modules", [Built-in modules])
+
+AS_IF([test x"$modules" = "xno"], [modules=""])
+AS_IF([test x"$dynmodules" = "xno"], [dynmodules=""])
+
+for a in $modules $dynmodules; do
+ case "$a" in
+ oracle|goracle)
+ PDNS_WITH_ORACLE
+ needoracle=yes
+ ;;
+ godbc)
+ PDNS_WITH_UNIXODBC
+ ;;
+ mydns|gmysql|pdns)
+ PDNS_WITH_MYSQL
+ ;;
+ gpgsql)
+ PDNS_WITH_POSTGRESQL
+ ;;
+ gsqlite3)
+ needsqlite3=yes
+ ;;
+ ldap)
+ PDNS_CHECK_LDAP
+ needldap=yes
+ ;;
+ opendbx)
+ PDNS_CHECK_OPENDBX
+ ;;
+ remote)
+ AS_IF([test "x$enable_unit_tests" = "xyes"],
+ [PDNS_CHECK_CURL_PROGRAM]
+ )
+ have_remotebackend=yes
+ ;;
+ tinydns)
+ PDNS_CHECK_CDB
+ ;;
+ geoip)
+ PDNS_CHECK_GEOIP
+ ;;
+ lua)
+ AS_IF([test "x$with_lua" = "xno"],
+ AC_MSG_ERROR([Lua backend needs lua, run ./configure --with-lua])
+ )
+ AS_IF([test "x$LUAPC" = "x"],
+ AC_MSG_ERROR([Lua backend needs lua but we cannot find it])
+ )
+ ;;
+ esac
+done
+
+PDNS_ENABLE_REMOTEBACKEND_ZEROMQ
+
+AC_MSG_CHECKING([whether we will be building and installing the extra tools])
+AC_ARG_ENABLE([tools],
+ [AS_HELP_STRING([--enable-tools], [if we should build and install the tools @<:@default=no@:>@])],
+ [enable_tools=$enableval],
+ [enable_tools=no]
+)
+
+AC_MSG_RESULT([$enable_tools])
+AM_CONDITIONAL([TOOLS], [test "x$enable_tools" != "xno"])
+
+PDNS_WITH_PROTOBUF
+
+
+AM_CONDITIONAL([ORACLE], [test "x$needoracle" = "xyes"])
+
+AM_CONDITIONAL([LDAP], [test "x$needldap" = "xyes"])
+
+PDNS_CHECK_SQLITE3
+AM_CONDITIONAL([SQLITE3], [test "x$needsqlite3" = "xyes"])
+
+for a in $modules; do
+ AC_MSG_CHECKING([whether we can build module "${a}"])
+ if [[ -d "$srcdir/modules/${a}backend" ]]; then
+ AC_MSG_RESULT([yes])
+ moduledirs="$moduledirs ${a}backend"
+
+ for b in `cat $srcdir/modules/${a}backend/OBJECTFILES`; do
+ moduleobjects="$moduleobjects ../modules/${a}backend/$b"
+ done
+ modulelibs="$modulelibs `cat $srcdir/modules/${a}backend/OBJECTLIBS`"
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Do not know how to build module "$a", "$srcdir/modules/${a}backend" does not exist! Please review --with-modules parameter for supported values.])
+ fi
+done
+
+for a in $dynmodules; do
+ AC_MSG_CHECKING([whether we can build dynamic module "${a}"])
+ if [[ -d "$srcdir/modules/${a}backend" ]]; then
+ AC_MSG_RESULT([yes])
+ moduledirs="$moduledirs ${a}backend"
+ else
+ AC_MSG_RESULT([no])
+ AC_MSG_ERROR([Do not know how to build module "$a", "$srcdir/modules/${a}backend" does not exist! Please review --with-dynmodules parameter for supported values.])
+ fi
+done
+
+AX_AVAILABLE_SYSTEMD
+AM_CONDITIONAL([HAVE_SYSTEMD], [ test x"$systemd" = "xy" ])
+
+LDFLAGS="$RELRO_LDFLAGS $LDFLAGS"
+
+CFLAGS="$PIE_CFLAGS $CFLAGS"
+CXXFLAGS="$PIE_CFLAGS $CXXFLAGS"
+PROGRAM_LDFLAGS="$PIE_LDFLAGS $PROGRAM_LDFLAGS"
+AC_SUBST([PROGRAM_LDFLAGS])
+
+PDNS_ENABLE_COVERAGE
+PDNS_ENABLE_SANITIZERS
+PDNS_ENABLE_MALLOC_TRACE
+
+AC_SUBST(LIBS)
+
+AC_SUBST([AM_CPPFLAGS],
+ ["AS_ESCAPE([-I$(top_builddir) -I$(top_srcdir)]) $THREADFLAGS $BOOST_CPPFLAGS"]
+)
+
+AC_SUBST([YAHTTP_CFLAGS], ['-I$(top_srcdir)/ext/yahttp'])
+AC_SUBST([YAHTTP_LIBS], ['$(top_builddir)/ext/yahttp/yahttp/libyahttp.la'])
+
+CXXFLAGS="$SANITIZER_FLAGS $CXXFLAGS"
+
+AC_ARG_VAR(PACKAGEVERSION, [The version used in secpoll queries])
+AS_IF([test "x$PACKAGEVERSION" != "x"],
+ [AC_DEFINE_UNQUOTED([PACKAGEVERSION], "$PACKAGEVERSION", [Set to the package version used for secpoll])]
+)
+
+export moduledirs moduleobjects modulelibs
+
+AC_CONFIG_FILES([
+ Makefile
+ modules/Makefile
+ pdns/Makefile
+ codedocs/Makefile
+ docs/Makefile
+ pdns/pdns.init
+ ext/Makefile
+ ext/yahttp/Makefile
+ ext/yahttp/yahttp/Makefile
+ ext/json11/Makefile
+ modules/bindbackend/Makefile
+ modules/geoipbackend/Makefile
+ modules/gmysqlbackend/Makefile
+ modules/godbcbackend/Makefile
+ modules/goraclebackend/Makefile
+ modules/gpgsqlbackend/Makefile
+ modules/gsqlite3backend/Makefile
+ modules/ldapbackend/Makefile
+ modules/luabackend/Makefile
+ modules/mydnsbackend/Makefile
+ modules/opendbxbackend/Makefile
+ modules/oraclebackend/Makefile
+ modules/pipebackend/Makefile
+ modules/randombackend/Makefile
+ modules/remotebackend/Makefile
+ modules/tinydnsbackend/Makefile
+])
+AC_OUTPUT
+
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Configuration summary])
+AC_MSG_NOTICE([=====================])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Configured with: $pdns_configure_args])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([CC: $CC])
+AC_MSG_NOTICE([CXX: $CXX])
+AC_MSG_NOTICE([LD: $LD])
+AC_MSG_NOTICE([CFLAGS: $CFLAGS])
+AC_MSG_NOTICE([CPPFLAGS: $CPPFLAGS])
+AC_MSG_NOTICE([CXXFLAGS: $CXXFLAGS])
+AC_MSG_NOTICE([LDFLAGS: $LDFLAGS])
+AC_MSG_NOTICE([LIBS: $LIBS])
+AC_MSG_NOTICE([BOOST_CPPFLAGS: $BOOST_CPPFLAGS])
+AC_MSG_NOTICE([])
+AC_MSG_NOTICE([Features enabled])
+AC_MSG_NOTICE([----------------])
+AC_MSG_NOTICE([Built-in modules: $modules])
+AC_MSG_NOTICE([Dynamic modules: $dynmodules])
+AC_MSG_NOTICE([])
+AS_IF([test "x$libcrypto_ecdsa" = "xyes"],
+ [AC_MSG_NOTICE([OpenSSL ecdsa: yes])],
+ [AC_MSG_NOTICE([OpenSSL ecdsa: no])]
+)
+AS_IF([test "x$LIBSODIUM_LIBS" != "x" || test "x$LIBDECAF_LIBS" != "x"],
+ [AC_MSG_NOTICE([ed25519: yes])],
+ [AC_MSG_NOTICE([ed25519: no])]
+)
+AS_IF([test "x$LIBDECAF_LIBS" != "x"],
+ [AC_MSG_NOTICE([ed448: yes])],
+ [AC_MSG_NOTICE([ed448: no])]
+)
+AS_IF([test "x$needsqlite3" != "x"],
+ [AC_MSG_NOTICE([SQLite3: yes])],
+ [AC_MSG_NOTICE([SQLite3: no])]
+)
+AS_IF([test "x$LUAPC" != "x"],
+ [AC_MSG_NOTICE([Lua: $LUAPC])],
+ [AS_IF([test "x$LUAJITPC" != "x"],
+ [AC_MSG_NOTICE([LuaJit: $LUAJITPC])],
+ [AC_MSG_NOTICE([Lua/LuaJit: no])])
+])
+AS_IF([test "x$enable_experimental_gss_tsig" = "xyes"],
+ [AC_MSG_NOTICE([GSS-TSIG: yes])]
+)
+AS_IF([test "x$systemd" != "xn"],
+ [AC_MSG_NOTICE([systemd: yes])],
+ [AC_MSG_NOTICE([systemd: no])]
+)
+AS_IF([test "x$enable_remotebackend_zeromq" != "xno"],
+ [AC_MSG_NOTICE([ZeroMQ connector for remotebackend: yes])]
+)
+AC_MSG_NOTICE([])
--- /dev/null
+#!/bin/sh
+################################################################################
+# rc script for PowerDNS, Solaris-style | fernando@secret.org #
+################################################################################
+
+prefix=/usr/local
+exec_prefix=${prefix}
+BINARYPATH=${exec_prefix}/bin
+SBINARYPATH=${exec_prefix}/sbin
+SOCKETPATH=/var/run
+
+cd $SOCKETPATH
+
+suffix=`/bin/basename $0 | /bin/awk -F- '{print $2}'`
+
+if [ $suffix ]
+then
+ EXTRAOPTS=--config-name=$suffix
+ PROGNAME=pdns-$suffix
+else
+ PROGNAME=$0
+fi
+
+pdns_server="$SBINARYPATH/pdns_server $EXTRAOPTS"
+
+doPC()
+{
+ ret=`$BINARYPATH/pdns_control $EXTRAOPTS $1 $2 2> /dev/null`
+}
+
+doPC ping
+NOTRUNNING=$?
+
+case "$1" in
+ status)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC status
+ /bin/echo $ret
+ else
+ /bin/echo "not running"
+ fi
+ ;;
+
+ stop)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC quit
+ /bin/echo $ret
+ else
+ /bin/echo "not running"
+ fi
+ ;;
+
+ force-stop)
+ /bin/echo "$PROGNAME: \c"
+
+ /bin/pkill -v -9 pdns_server
+
+ /bin/echo "force-stopped"
+ ;;
+
+ start)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ /bin/echo "already running"
+ else
+ $pdns_server --daemon --guardian=yes
+ if test "$?" = "0"
+ then
+ /bin/echo "started"
+ fi
+ fi
+ ;;
+
+ force-reload | restart)
+ /bin/echo "$PROGNAME: \c"
+
+ /bin/echo "stopping and waiting\c"
+ doPC quit
+ sleep 3
+ /bin/echo
+ $0 start
+ ;;
+
+ reload)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC cycle
+ /bin/echo requested reload
+ else
+ /bin/echo not running yet
+ $0 start
+ fi
+ ;;
+
+ monitor)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ /bin/echo "already running"
+ else
+ $pdns_server --daemon=no --guardian=no --control-console --loglevel=9
+ fi
+ ;;
+
+ dump)
+ /bin/echo "$PROGNAME: \c"
+
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC list
+ /bin/echo $ret
+ else
+ /bin/echo "not running"
+ fi
+ ;;
+
+ show)
+ /bin/echo "$PROGNAME: \c"
+
+ if [ $# -lt 2 ]
+ then
+ /bin/echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ /bin/echo -n "$2="
+ doPC show $2 ; /bin/echo $ret
+ else
+ /bin/echo "not running"
+ fi
+ ;;
+
+ mrtg)
+ if [ $# -lt 2 ]
+ then
+ /bin/echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC show $2 ; /bin/echo $ret
+ if [ "$3x" != "x" ]
+ then
+ doPC show $3 ; /bin/echo $ret
+ else
+ /bin/echo 0
+ fi
+ doPC uptime ; /bin/echo $ret
+ /bin/echo PowerDNS daemon
+ else
+ /bin/echo "not running"
+ fi
+
+ ;;
+
+ cricket)
+ if [ $# -lt 2 ]
+ then
+ /bin/echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC show $2 ; /bin/echo $ret
+ else
+ /bin/echo "not running"
+ fi
+ ;;
+
+ *)
+ /bin/echo "Usage: $0 { start | stop | force-reload | restart | status | dump | show | mrtg | cricket | monitor }"
+ exit 1
+ ;;
+esac
+exit 0
--- /dev/null
+MANPAGES_TARGET_AUTH = pdns_server.1 \
+ pdns_control.1 \
+ pdnsutil.1 \
+ zone2json.1 \
+ zone2ldap.1 \
+ zone2sql.1
+
+MANPAGES_TARGET_TOOLS = calidns.1 \
+ dnsgram.1 \
+ dnsreplay.1 \
+ dnsscan.1 \
+ dnsscope.1 \
+ dnswasher.1 \
+ dumresp.1 \
+ ixplore.1 \
+ nproxy.1 \
+ nsec3dig.1 \
+ pdns_notify.1 \
+ saxfr.1 \
+ sdig.1
+
+if HAVE_BOOST_GE_148
+MANPAGES_TARGET_TOOLS += dnsbulktest.1 \
+ dnstcpbench.1
+endif
+
+
+if HAVE_PROTOBUF
+if HAVE_PROTOC
+MANPAGES_TARGET_TOOLS += dnspcap2protobuf.1
+endif
+endif
+
+MANPAGES_TARGET_DNSDIST = dnsdist.1
+
+MANPAGES_TARGET_RECURSOR = pdns_recursor.1 \
+ rec_control.1
+
+MANPAGES_TARGET_ALL=$(MANPAGES_TARGET_AUTH) \
+ $(MANPAGES_TARGET_RECURSOR) \
+ $(MANPAGES_TARGET_TOOLS) \
+ $(MANPAGES_TARGET_DNSDIST)
+
+# The manpages to distribute and install are only those for the
+# auth server and tools. For the recursor and dnsdist tarballs,
+# the respective dist- scripts will take care of this
+if HAVE_PANDOC
+dist_man_MANS = $(MANPAGES_TARGET_AUTH) $(MANPAGES_TARGET_TOOLS)
+endif
+if HAVE_MANPAGES
+dist_man_MANS = $(MANPAGES_TARGET_AUTH) $(MANPAGES_TARGET_TOOLS)
+endif
+
+EXTRA_DIST = manpages markdown/*.md markdown/appendix markdown/authoritative markdown/common markdown/httpapi markdown/recursor markdown/security markdown/tools
+
+
+.PHONY: html all-manpages
+
+html: html/index.html
+
+if FROM_GIT
+html/index.html: process-md.sh mkdocs.yml markdown/** markdown/*/** manpages/*
+ mkdir -p doc-build
+ rsync -a --delete markdown/. doc-build/.
+ cp -r manpages doc-build/
+ ./process-md.sh pre
+ mkdocs build --clean
+ ./process-md.sh post
+
+html.tar.bz2: html
+ tar cjf html.tar.bz2 html/
+
+check-links: html
+ ./checklinks.sh
+
+publish: html html.tar.bz2
+ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html/ web1.powerdns.com:/srv/www/doc.powerdns.com/md
+ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/html.tar.bz2
+else
+html/index.html:
+ @echo "Building the documentation HTML is only"
+ @echo "supported from a git checkout"
+endif
+
+all-manpages: $(MANPAGES_TARGET_ALL)
+
+if HAVE_PANDOC
+$(MANPAGES_TARGET_ALL): %: manpages/%.md
+ $(PANDOC) -s -t man $< -o $@
+else
+$(MANPAGES_TARGET_ALL):
+ echo "You need pandoc to generate the manpages"
+ exit 1
+endif
+
+clean:
+ rm -rf html html.tar.bz2 *.8 *.1
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@HAVE_BOOST_GE_148_TRUE@am__append_1 = dnsbulktest.1 \
+@HAVE_BOOST_GE_148_TRUE@ dnstcpbench.1
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_2 = dnspcap2protobuf.1
+subdir = docs
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(dist_man_MANS)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+man1dir = $(mandir)/man1
+am__installdirs = "$(DESTDIR)$(man1dir)"
+NROFF = nroff
+MANS = $(dist_man_MANS)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+MANPAGES_TARGET_AUTH = pdns_server.1 \
+ pdns_control.1 \
+ pdnsutil.1 \
+ zone2json.1 \
+ zone2ldap.1 \
+ zone2sql.1
+
+MANPAGES_TARGET_TOOLS = calidns.1 dnsgram.1 dnsreplay.1 dnsscan.1 \
+ dnsscope.1 dnswasher.1 dumresp.1 ixplore.1 nproxy.1 nsec3dig.1 \
+ pdns_notify.1 saxfr.1 sdig.1 $(am__append_1) $(am__append_2)
+MANPAGES_TARGET_DNSDIST = dnsdist.1
+MANPAGES_TARGET_RECURSOR = pdns_recursor.1 \
+ rec_control.1
+
+MANPAGES_TARGET_ALL = $(MANPAGES_TARGET_AUTH) \
+ $(MANPAGES_TARGET_RECURSOR) \
+ $(MANPAGES_TARGET_TOOLS) \
+ $(MANPAGES_TARGET_DNSDIST)
+
+@HAVE_MANPAGES_TRUE@dist_man_MANS = $(MANPAGES_TARGET_AUTH) $(MANPAGES_TARGET_TOOLS)
+
+# The manpages to distribute and install are only those for the
+# auth server and tools. For the recursor and dnsdist tarballs,
+# the respective dist- scripts will take care of this
+@HAVE_PANDOC_TRUE@dist_man_MANS = $(MANPAGES_TARGET_AUTH) $(MANPAGES_TARGET_TOOLS)
+EXTRA_DIST = manpages markdown/*.md markdown/appendix markdown/authoritative markdown/common markdown/httpapi markdown/recursor markdown/security markdown/tools
+all: all-am
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign docs/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-man1: $(dist_man_MANS)
+ @$(NORMAL_INSTALL)
+ @list1=''; \
+ list2='$(dist_man_MANS)'; \
+ test -n "$(man1dir)" \
+ && test -n "`echo $$list1$$list2`" \
+ || exit 0; \
+ echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+ { for i in $$list1; do echo "$$i"; done; \
+ if test -n "$$list2"; then \
+ for i in $$list2; do echo "$$i"; done \
+ | sed -n '/\.1[a-z]*$$/p'; \
+ fi; \
+ } | while read p; do \
+ if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; echo "$$p"; \
+ done | \
+ sed -e 'n;s,.*/,,;p;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,' | \
+ sed 'N;N;s,\n, ,g' | { \
+ list=; while read file base inst; do \
+ if test "$$base" = "$$inst"; then list="$$list $$file"; else \
+ echo " $(INSTALL_DATA) '$$file' '$(DESTDIR)$(man1dir)/$$inst'"; \
+ $(INSTALL_DATA) "$$file" "$(DESTDIR)$(man1dir)/$$inst" || exit $$?; \
+ fi; \
+ done; \
+ for i in $$list; do echo "$$i"; done | $(am__base_list) | \
+ while read files; do \
+ test -z "$$files" || { \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(man1dir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(man1dir)" || exit $$?; }; \
+ done; }
+
+uninstall-man1:
+ @$(NORMAL_UNINSTALL)
+ @list=''; test -n "$(man1dir)" || exit 0; \
+ files=`{ for i in $$list; do echo "$$i"; done; \
+ l2='$(dist_man_MANS)'; for i in $$l2; do echo "$$i"; done | \
+ sed -n '/\.1[a-z]*$$/p'; \
+ } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^1][0-9a-z]*$$,1,;x' \
+ -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
+ dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
+tags TAGS:
+
+ctags CTAGS:
+
+cscope cscopelist:
+
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(MANS)
+installdirs:
+ for dir in "$(DESTDIR)$(man1dir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-am
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic
+
+dvi: dvi-am
+
+dvi-am:
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-man
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man: install-man1
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-man
+
+uninstall-man: uninstall-man1
+
+.MAKE: install-am install-strip
+
+.PHONY: all all-am check check-am clean clean-generic clean-libtool \
+ cscopelist-am ctags-am distclean distclean-generic \
+ distclean-libtool distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-man1 install-pdf install-pdf-am install-ps \
+ install-ps-am install-strip installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags-am uninstall uninstall-am uninstall-man \
+ uninstall-man1
+
+
+.PHONY: html all-manpages
+
+html: html/index.html
+
+@FROM_GIT_TRUE@html/index.html: process-md.sh mkdocs.yml markdown/** markdown/*/** manpages/*
+@FROM_GIT_TRUE@ mkdir -p doc-build
+@FROM_GIT_TRUE@ rsync -a --delete markdown/. doc-build/.
+@FROM_GIT_TRUE@ cp -r manpages doc-build/
+@FROM_GIT_TRUE@ ./process-md.sh pre
+@FROM_GIT_TRUE@ mkdocs build --clean
+@FROM_GIT_TRUE@ ./process-md.sh post
+
+@FROM_GIT_TRUE@html.tar.bz2: html
+@FROM_GIT_TRUE@ tar cjf html.tar.bz2 html/
+
+@FROM_GIT_TRUE@check-links: html
+@FROM_GIT_TRUE@ ./checklinks.sh
+
+@FROM_GIT_TRUE@publish: html html.tar.bz2
+@FROM_GIT_TRUE@ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html/ web1.powerdns.com:/srv/www/doc.powerdns.com/md
+@FROM_GIT_TRUE@ rsync -crv --no-p --chmod=g=rwX --exclude '*~' ./html.tar.bz2 web1.powerdns.com:/srv/www/doc.powerdns.com/html.tar.bz2
+@FROM_GIT_FALSE@html/index.html:
+@FROM_GIT_FALSE@ @echo "Building the documentation HTML is only"
+@FROM_GIT_FALSE@ @echo "supported from a git checkout"
+
+all-manpages: $(MANPAGES_TARGET_ALL)
+
+@HAVE_PANDOC_TRUE@$(MANPAGES_TARGET_ALL): %: manpages/%.md
+@HAVE_PANDOC_TRUE@ $(PANDOC) -s -t man $< -o $@
+@HAVE_PANDOC_FALSE@$(MANPAGES_TARGET_ALL):
+@HAVE_PANDOC_FALSE@ echo "You need pandoc to generate the manpages"
+@HAVE_PANDOC_FALSE@ exit 1
+
+clean:
+ rm -rf html html.tar.bz2 *.8 *.1
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+.TH "CALIDNS" "1" "April 2016" "" ""
+.SH NAME
+.PP
+\f[B]calidns\f[] \- A DNS recursor testing tool
+.SH SYNOPSIS
+.PP
+\f[B]calidns\f[] \f[I]QUERY_FILE\f[] \f[I]DESTINATION\f[]
+\f[I]INITIAL_QPS\f[] \f[I]HITRATE\f[]
+.SH DESCRIPTION
+.PP
+\f[B]calidns\f[] reads queries from \f[I]QUERY_FILE\f[] and sends them
+as a recursive query to \f[I]DESTINATION\f[] (an IPv4 or IPv6 address,
+optionally with a port number), starting at INITIAL_QPS queries per
+second and aims to have a cache hitrate of \f[I]HITRATE\f[] percent.
+.PP
+It will then try to determine the maximum amount of queries per second
+the recursor can handle with the aforementioned \f[I]HITRATE\f[].
+.SH QUERY_FILE format
+.PP
+The format of the \f[I]QUERY_FILE\f[] is very simple, it should contain
+"QNAMEQTYPE" tuples, one per line.
+For example:
+.PP
+powerdns.com A powerdns.com AAAA google.com A
+.PP
+This is similar to Alexa top 1 million list.
+.SH OPTIONS
+.PP
+None
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "DNSBULKTEST" "1" "April 2015" "" ""
+.SH NAME
+.PP
+\f[B]dnsbulktest\f[] \- A debugging tool for intermittent resolver
+failures
+.SH SYNOPSIS
+.PP
+\f[B]dnsbulktest\f[] [\f[I]OPTION\f[]]...
+\f[I]IPADDRESS\f[] \f[I]PORT\f[] [\f[I]LIMIT\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]dnsbulktest\f[] sends a large amount of different queries (for up
+to \f[I]LIMIT\f[] different domains) to the nameserver at
+\f[I]IPADDRESS\f[] on port \f[I]PORT\f[].
+It reads the domain names from STDIN in the alexa topX format and
+outputs statistics on STDOUT.
+.SH OPTIONS
+.TP
+.B \-\-help, \-h
+Show a summary of options.
+.RS
+.RE
+.TP
+.B \-\-quiet, \-q
+Don\[aq]t show information on individual queries.
+.RS
+.RE
+.TP
+.B \-\-type, \-t \f[I]TYPE\f[]
+Query the nameserver for \f[I]TYPE\f[], A by default.
+.RS
+.RE
+.TP
+.B \-\-envoutput, \-e
+Write results on STDOUT as shell environment variables
+.RS
+.RE
+.TP
+.B \-\-version
+Display the version of dnsbulktest
+.RS
+.RE
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "DNSGRAM" "1" "April 2015" "" ""
+.SH NAME
+.PP
+\f[B]dnsgram\f[] \- A debugging tool for intermittent resolver failures
+.SH SYNOPSIS
+.PP
+\f[B]dnsgram\f[] \f[I]INFILE\f[]...
+.SH DESCRIPTION
+.PP
+\f[B]dnsgram\f[] takes one or more \f[I]INFILE\f[]s in PCAP format and
+generates statistics on 5 second segments allowing the study of
+intermittent resolver issues.
+.SH OPTIONS
+.PP
+None
+.SH SEE ALSO
+.PP
+pcap(3PCAP), tcpdump(8)
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "DNSPCAP2PROTOBUF" "1" "June 2016" "" ""
+.SH NAME
+.PP
+\f[B]dnspcap2protobuf\f[] \- A tool to convert PCAPs of DNS traffic to
+PowerDNS Protobuf
+.SH SYNOPSIS
+.PP
+\f[B]dnspcap2protobuf\f[] \f[I]PCAPFILE\f[] \f[I]OUTFILE\f[]
+.SH DESCRIPTION
+.PP
+\f[B]dnspcap2protobuf\f[] reads the PCAP file \f[I]PCAPFILE\f[] for DNS
+queries and responses and writes these in the PowerDNS protobuf format
+to \f[I]OUTFILE\f[].
+.SH OPTIONS
+.TP
+.B \-\-help
+Show a summary of options.
+.RS
+.RE
+.TP
+.B \-\-version
+Display the version of dnspcap2protobuf
+.RS
+.RE
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "DNSREPLAY" "1" "September 2012" "" ""
+.SH NAME
+.PP
+\f[B]dnsreplay\f[] \- A PowerDNS nameserver debugging tool
+.SH SYNOPSIS
+.PP
+\f[B]dnsreplay\f[] [\f[I]OPTION\f[]]...
+\f[I]FILENAME\f[] \f[I]ADDRESS\f[] [\f[I]PORT\f[]]
+.SH DESCRIPTION
+.PP
+This program takes recorded questions and answers and replays them to
+the specified nameserver and reporting afterwards which percentage of
+answers matched, were worse or better.
+.PP
+dnsreplay compares the answers and some other metrics with the actual
+ones with those found in the dumpfile.
+.PP
+By default it only replay queries with recursion\-desired flag set.
+.SH OPTIONS
+.TP
+.B FILENAME
+is expected to be an PCAP file.
+The queries are send to the DNS server specified as \f[I]ADDRESS\f[] and
+\f[I]PORT\f[].
+.RS
+.RE
+.TP
+.B ADDRESS
+IPv4 or IPv6 address of the nameserver to replay \f[I]FILENAME\f[] to.
+.RS
+.RE
+.TP
+.B PORT
+if omitted, 53 will be used.
+.RS
+.RE
+.TP
+.B \-\-help | \-h
+Show summary of options.
+.RS
+.RE
+.TP
+.B \-\-ecs\-mask \f[I]VAL\f[]
+When EDNS forwarding an IP address, mask out first octet with this value
+.RS
+.RE
+.TP
+.B \-\-ecs\-stamp \f[I]FLAG\f[]
+Add original IP address as EDNS Client Subnet Option when forwarding to
+reference server
+.RS
+.RE
+.TP
+.B \-\-packet\-limit \f[I]NUM\f[]
+Stop after replaying \f[I]NUM\f[] packets.
+Default for \f[I]NUM\f[] is 0, which means no limit.
+.RS
+.RE
+.TP
+.B \-\-quiet \f[I]FLAG\f[]
+If \f[I]FLAG\f[] is set to 1.
+dnsreplay will not be very noisy with its output.
+This is the default.
+.RS
+.RE
+.TP
+.B \-\-recursive \f[I]FLAG\f[]
+If \f[I]FLAG\f[] is set to 1.
+dnsreplay will only replay queries with recursion desired flag set.
+This is the default.
+.RS
+.RE
+.TP
+.B \-\-speedup \f[I]FACTOR\f[]
+Replay queries with this speedup \f[I]FACTOR\f[].
+Default is 1.
+.RS
+.RE
+.TP
+.B \-\-timeout\-msec \f[I]MSEC\f[]
+Wait at least \f[I]MSEC\f[] milliseconds for a reply.
+Default is 500.
+.RS
+.RE
+.SH BUGS
+.PP
+dnsreplay has no certain handling for timeouts.
+It handles around at most 65536 outstanding answers.
+.SH SEE ALSO
+.PP
+pcap(3PCAP), tcpdump(8), dnswasher(1)
+.SH AUTHORS
+Joerg Jungermann (jj+debian At borkum.net).
--- /dev/null
+.TH "DNSSCAN" "1" "April 2015" "" ""
+.SH NAME
+.PP
+\f[B]dnsscan\f[] \- List the amount of queries per qtype in a pcap
+.SH SYNOPSIS
+.PP
+\f[B]dnsscan\f[] \f[I]INFILE\f[]...
+.SH DESCRIPTION
+.PP
+\f[B]dnsscan\f[] takes one or more \f[I]INFILE\f[]s in PCAP format and
+generates a list of the number of queries per qtype.
+.SH OPTIONS
+.PP
+None
+.SH SEE ALSO
+.PP
+pcap(3PCAP), tcpdump(8)
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "DNSSCOPE" "1" "September 2012" "" ""
+.SH NAME
+.PP
+\f[B]dnsscope\f[] \- A PowerDNS nameserver debugging tool
+.SH SYNOPSIS
+.PP
+\f[B]dnsscope\f[] [\f[I]OPTION\f[]]...
+\f[I]INFILE\f[]
+.SH DESCRIPTION
+.PP
+\f[B]dnsscope\f[] takes an \f[I]INFILE\f[] in PCAP format.
+It generates some simple statistics outputs these to STDOUT.
+.SH OPTIONS
+.TP
+.B INFILE
+Path to a PCAP file.
+.RS
+.RE
+.TP
+.B \-h | \-\-help
+Show the help.
+.RS
+.RE
+.TP
+.B \-\-rd
+Only process packets in \f[I]INFILE\f[] with the RD (Recursion Desired)
+flag set.
+By default, we process all DNS packets in \f[I]INFILE\f[].
+.RS
+.RE
+.TP
+.B \-\-ipv4
+Process IPv4 packets.
+On by default, disable with \f[B]\-\-ipv4 false\f[].
+.RS
+.RE
+.TP
+.B \-\-ipv6
+Process IPv6 packets.
+On by default, disable with \f[B]\-\-ipv6 false\f[].
+.RS
+.RE
+.TP
+.B \-\-servfail\-tree
+Figure out subtrees that generate servfails.
+.RS
+.RE
+.TP
+.B \-l | \-\-load\-stats
+Emit per\-second load statistics (questions, answers, outstanding).
+.RS
+.RE
+.TP
+.B \-w | \-\-write\-failures \f[I]FILENAME\f[]
+Write weird packets to a PCAP file at \f[I]FILENAME\f[].
+.RS
+.RE
+.TP
+.B \-v | \-\-verbose
+Be more verbose.
+.RS
+.RE
+.SH SEE ALSO
+.PP
+pcap(3PCAP), tcpdump(8)
+.SH AUTHORS
+Joerg Jungermann (jj+debian At borkum.net).
--- /dev/null
+.TH "DNSTCPBENCH" "1" "July 2013" "" ""
+.SH NAME
+.PP
+\f[B]dnstcpbench\f[] \- tool to perform TCP benchmarking of nameservers
+.SH SYNOPSIS
+.PP
+\f[B]dnstcpbench\f[] [\f[I]OPTION\f[]]...
+\f[I]REMOTE\-ADDRESS\f[] [\f[I]REMOTE\-PORT\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]dnstcpbench\f[] reads DNS queries (by default from standard input)
+and sends them out in parallel to a remote nameserver.
+By default TCP/IP is used, but optionally, UDP is tried first, which
+allows for the benchmarking of TCP/IP fallback.
+.PP
+The program reports both mean and median numbers for queries per second
+and UDP and TCP latency.
+Each query only counts once, even if it is tried over UDP first.
+This effectively means that passing \[aq]\-u\[aq] can lower query rates
+if many queries get shunted to TCP.
+.PP
+The input format is one query per line: qname single\-space qtype.
+An example:
+.PP
+www.powerdns.com ANY
+.PP
+When benchmarking extended runs, it may be necessary to enable TIME_WAIT
+recycling, as TCP/IP port tuples may otherwise run out.
+On Linux this is performed by running:
+.PP
+echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
+.PP
+The equivalent for IPv6 is not known.
+.SH OPTIONS
+.TP
+.B \-f | \-\-file \f[I]FILENAME\f[]
+\f[I]FILENAME\f[] from which to read queries.
+Defaults to standard input if unspecified.
+.RS
+.RE
+.TP
+.B \-h | \-\-help
+Provide a helpful message.
+.RS
+.RE
+.TP
+.B \-\-timeout\-msec \f[I]MSEC\f[]
+\f[I]MSEC\f[] milliseconds to wait for an answer.
+.RS
+.RE
+.TP
+.B \-u | \-\-udp\-first
+Attempt resolution via UDP first, only do TCP if truncated answer is
+received.
+.RS
+.RE
+.TP
+.B \-v | \-\-verbose
+Be wordy on what the program is doing.
+.RS
+.RE
+.TP
+.B \-\-workers \f[I]NUM\f[]
+Use \f[I]NUM\f[] parallel worker threads.
+.RS
+.RE
+.TP
+.B REMOTE\-ADDRESS
+IPv4 or IPv6 to test against.
+.RS
+.RE
+.TP
+.B REMOTE\-PORT
+Port to test against, defaults to 53.
+.RS
+.RE
+.SH BUGS
+.PP
+Currently the timeout code does not actually perform non\-blocking
+connects or writes.
+So a slow connect or slow writes will still cause low performance and
+delays.
+.PP
+Median queries per second statistics are reported as 0 for sub\-second
+runs.
+.SH AUTHORS
+PowerDNS.COM BV.
--- /dev/null
+.TH "DNSWASHER" "1" "September 2012" "" ""
+.SH NAME
+.PP
+\f[B]dnswasher\f[] \- A PowerDNS nameserver debugging tool
+.SH SYNOPSIS
+.PP
+\f[B]dnswasher\f[] \f[I]INFILE\f[] [\f[I]INFILE\f[]] \f[I]OUTFILE\f[]
+.SH DESCRIPTION
+.PP
+dnswasher takes one or more \f[I]INFILE\f[]s in PCAP format and writes
+out \f[I]OUTFILE\f[] also in PCAP format, while obfuscating end\-user IP
+addresses.
+.PP
+This is useful to share data with third parties while attempting to
+protect the privacy of your users.
+.PP
+The INFILEs must be of identical PCAP type.
+.PP
+Please check the output of \f[B]dnswasher\f[] to make sure no customer
+IP addresses remain.
+Also realize that sufficient data could allow individuals to be
+re\-identified based on the domain names they care about.
+.SH OPTIONS
+.PP
+None
+.SH SEE ALSO
+.PP
+pcap(3PCAP), tcpdump(8)
+.SH AUTHORS
+Joerg Jungermann (jj+debian At borkum.net).
--- /dev/null
+.TH "DUMRESP" "1" "April 2016" "" ""
+.SH NAME
+.PP
+\f[B]dumresp\f[] \- A dumb DNS responder
+.SH SYNOPSIS
+.PP
+\f[B]dumresp\f[] \f[I]LOCAL\-ADDRESS\f[] \f[I]LOCAL\-PORT\f[]
+\f[I]NUMBER\-OF\-PROCESSES\f[]
+.SH DESCRIPTION
+.PP
+\f[B]dumresp\f[] accepts DNS packets on
+\f[I]LOCAL\-ADDRESS\f[]:\f[I]LOCAL\-PORT\f[] and simply replies with the
+same query, with the QR bit set.
+When \f[I]NUMBER\-OF\-PROCESSES\f[] is set to anything but 1,
+\f[B]dumresp\f[] will spawn \f[I]NUMBER\-OF\-PROCESSES\f[] forks and use
+the SO_REUSEPORT option to bind to the port.
+.SH OPTIONS
+.PP
+None
+.SH SEE ALSO
+.PP
+socket(7)
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "IXPLORE" "1" "October 2015" "" ""
+.SH NAME
+.PP
+\f[B]ixplore\f[] \- A tool that provides insights into IXFRs
+.SH SYNOPSIS
+.PP
+\f[B]ixplore\f[] \f[I]COMMAND\f[] \f[I]COMMAND_OPT\f[]...
+.PP
+\f[B]ixplore\f[] diff \f[I]ZONE\f[] \f[I]BEFORE\f[] \f[I]AFTER\f[]
+.PP
+\f[B]ixplore\f[] track \f[I]IP ADDRESS\f[] \f[I]PORT\f[] \f[I]ZONE\f[]
+\f[I]DIRECTORY\f[]
+.SH DESCRIPTION
+.PP
+\f[B]ixplore\f[] is a tool to work with IXFR (incremental zonetransfers)
+in two modes (specified by \f[I]COMMAND\f[]): diff or track.
+.PP
+In the \[aq]diff\[aq] mode, it will show a diff(1)\-like output between
+\f[I]BEFORE\f[] and \f[I]AFTER\f[].
+.PP
+In the \[aq]track\[aq] mode, \f[B]ixplore\f[] consumes IXFRs from
+\f[I]IP ADDRESS\f[] and writes the resulting zonefiles out to
+\f[I]DIRECTORY\f[]/\f[I]ZONE\f[]\-serial.
+If no initial zonefiles exist, an initial AXFR will be done first.
+\f[B]ixplore\f[] will then check the SOA serial on \f[I]IP ADDRESS\f[]
+for \f[I]ZONE\f[] every SOA Refresh seconds and perform an IXFR if the
+serial has increased.
+.SH OPTIONS
+.SS diff\-mode
+.TP
+.B ZONE
+The name of the zone the IXFRs are consumed from.
+.RS
+.RE
+.TP
+.B BEFORE
+Path to the \[aq]before\[aq] zonefile.
+.RS
+.RE
+.TP
+.B AFYER
+Path to the \[aq]after\[aq] zonefile.
+.RS
+.RE
+.SS track\-mode
+.TP
+.B IP ADDRESS
+The IP address to consume IXFRs from.
+.RS
+.RE
+.TP
+.B PORT
+The port to use on \f[I]IP ADDRESS\f[].
+.RS
+.RE
+.TP
+.B ZONE
+Name of the zone to track changes of.
+.RS
+.RE
+.TP
+.B DIRECTORY
+Directory where the zonefiles will be stored.
+.RS
+.RE
+.SH SEE ALSO
+.PP
+diff(1)
+.SH AUTHORS
+Pieter Lexis (pieter.lexis\@powerdns.com).
--- /dev/null
+% CALIDNS(1)
+% PowerDNS.com BV
+% April 2016
+
+# NAME
+**calidns** - A DNS recursor testing tool
+
+# SYNOPSIS
+**calidns** *QUERY_FILE* *DESTINATION* *INITIAL_QPS* *HITRATE*
+
+# DESCRIPTION
+**calidns** reads queries from *QUERY_FILE* and sends them as a recursive query to
+*DESTINATION* (an IPv4 or IPv6 address, optionally with a port number), starting
+at INITIAL_QPS queries per second and aims to have a cache hitrate of *HITRATE*
+percent.
+
+It will then try to determine the maximum amount of queries per second the recursor
+can handle with the aforementioned *HITRATE*.
+
+# QUERY_FILE format
+The format of the *QUERY_FILE* is very simple, it should contain "QNAME<space>QTYPE"
+tuples, one per line. For example:
+
+powerdns.com A
+powerdns.com AAAA
+google.com A
+
+This is similar to Alexa top 1 million list.
+
+# OPTIONS
+None
--- /dev/null
+% DNSBULKTEST(1)
+% PowerDNS.com BV
+% April 2015
+
+# NAME
+**dnsbulktest** - A debugging tool for intermittent resolver failures
+
+# SYNOPSIS
+**dnsbulktest** [*OPTION*]... *IPADDRESS* *PORT* [*LIMIT*]
+
+# DESCRIPTION
+**dnsbulktest** sends a large amount of different queries (for up to *LIMIT*
+different domains) to the nameserver at *IPADDRESS* on port *PORT*. It reads the
+domain names from STDIN in the alexa topX format and outputs statistics on STDOUT.
+
+# OPTIONS
+--help, -h
+: Show a summary of options.
+
+--quiet, -q
+: Don't show information on individual queries.
+
+--type, -t *TYPE*
+: Query the nameserver for *TYPE*, A by default.
+
+--envoutput, -e
+: Write results on STDOUT as shell environment variables
+
+--version
+: Display the version of dnsbulktest
--- /dev/null
+% DNSDIST(1)
+% PowerDNS.com BV
+% 2013
+
+# NAME
+**dnsdist** - tool to balance DNS queries over downstream servers
+
+# SYNOPSIS
+dnsdist [*OPTION*]... *ADDRESS*...
+
+# DESCRIPTION
+**dnsdist** receives DNS queries and relays them to one or more downstream
+servers. It subsequently sends back responses to the original requestor.
+
+dnsdist operates over TCP and UDP, and strives to deliver very high
+performance over both.
+
+Currently, queries are sent to the downstream server with the least
+outstanding queries. This effectively implies load balancing, making sure
+that slower servers get less queries.
+
+If a reply has not come in after a few seconds, it is removed from the
+queue, but in the short term, timeouts do cause a server to get less
+traffic.
+
+IPv4 and IPv6 operation can be mixed and matched, in other words, queries
+coming in over IPv6 could be forwarded to IPv4 and vice versa.
+
+**dnsdist** is scriptable in Lua, see the dnsdist documentation for more
+information on this.
+
+# SCOPE
+dnsdist does not 'think' about DNS, and does not perform any kind of
+caching, nor is it aware of the quality of the answers it is relaying.
+
+dnsdist assumes that each query leads to exactly one response, which is true
+for all DNS except for AXFR, which is therefore not supported.
+
+The goal for dnsdist is to remain simple. If more powerful loadbalancing is
+required, dedicated hardware or software is recommended. Linux Virtual
+Server for example is often mentioned.
+
+# OPTIONS
+-a,--acl *NETMASK*
+: Add *NETMASK* to the ACL.
+
+-C,--config *FILE*
+: Load configuration from *FILE*.
+
+--check-config
+: Test the configuration file (which may be set with **--config** or **-C**)
+ for errors. dnsdist will show the errors and exit with a non-zero exit-code
+ when errors are found.
+
+-c,--client [*ADDRESS*[:*PORT*]]
+: Operate as a client, connect to dnsdist. This will read the dnsdist configuration
+ for the **controlSocket** statement and connect to it. When *ADDRESS* (with
+ optional *PORT*) is set, dnsdist will connect to that instead.
+
+-k,--setkey *KEY*
+: When operating as a client(**-c**, **--client**), use *KEY* as shared secret
+ to connect to dnsdist. This should be the same key that is used on the
+ server (set with **setKey()**). Note that this will leak the key into your
+ shell's history. Only available when dnsdist is compiled with libsodium support.
+
+-d,--daemon
+: Operate as a daemon.
+
+-e,--execute *CMD*
+: Connect to dnsdist and execute *CMD*.
+
+-h,--help
+: Display a helpful message and exit.
+
+-l,--local *ADDRESS*
+: Bind to *ADDRESS*, Supply as many addresses (using multiple **--local**
+ statements) to listen on as required. Specify IPv4 as 0.0.0.0:53 and IPv6
+ as [::]:53.
+
+--supervised
+: Run in foreground, but do not spawn a console. Use this switch to run
+ dnsdist inside a supervisor (use with e.g. systemd and daemontools).
+
+--disable-syslog
+: Disable logging to syslog. Use this when running inside a supervisor that
+ handles logging (like systemd). Do not use in combination with **--daemon**.
+
+-p,--pidfile *FILE*
+: Write a pidfile to *FILE*, works only with **--daemon**.
+
+-u,--uid *UID*
+: Change the process user to *UID* after binding sockets. *UID* can be a name
+ or number.
+
+-g,--gid *GID*
+: Change the process group to *GID* after binding sockets. *GID* Can be a
+ name or number.
+
+-V,--version
+: Show the dnsdist version and exit.
+
+ADDRESS
+: Any number of downstream DNS servers, in the same syntax as used with
+ **--local**. If the port is not specified, 53 is used.
+
+# BUGS
+Right now, the TCP support has some rather arbitrary limits.
+
+# RESOURCES
+Website: http://dnsdist.org
--- /dev/null
+% DNSGRAM(1)
+% PowerDNS.com BV
+% April 2015
+
+# NAME
+**dnsgram** - A debugging tool for intermittent resolver failures
+
+# SYNOPSIS
+**dnsgram** *INFILE*...
+
+# DESCRIPTION
+**dnsgram** takes one or more *INFILE*s in PCAP format and generates statistics
+on 5 second segments allowing the study of intermittent resolver issues.
+
+# OPTIONS
+None
+
+# SEE ALSO
+pcap(3PCAP), tcpdump(8)
--- /dev/null
+% DNSPCAP2PROTOBUF(1)
+% PowerDNS.com BV
+% June 2016
+
+# NAME
+**dnspcap2protobuf** - A tool to convert PCAPs of DNS traffic to PowerDNS Protobuf
+
+# SYNOPSIS
+**dnspcap2protobuf** *PCAPFILE* *OUTFILE*
+
+# DESCRIPTION
+**dnspcap2protobuf** reads the PCAP file *PCAPFILE* for DNS queries and responses
+and writes these in the PowerDNS protobuf format to *OUTFILE*.
+
+# OPTIONS
+--help
+: Show a summary of options.
+
+--version
+: Display the version of dnspcap2protobuf
--- /dev/null
+% DNSREPLAY(1)
+% Joerg Jungermann (jj+debian At borkum.net)
+% September 2012
+
+# NAME
+**dnsreplay** - A PowerDNS nameserver debugging tool
+
+# SYNOPSIS
+**dnsreplay** [*OPTION*]... *FILENAME* *ADDRESS* [*PORT*]
+
+# DESCRIPTION
+This program takes recorded questions and answers and replays them to the
+specified nameserver and reporting afterwards which percentage of answers
+matched, were worse or better.
+
+dnsreplay compares the answers and some other metrics with the actual ones with
+those found in the dumpfile.
+
+By default it only replay queries with recursion-desired flag set.
+
+# OPTIONS
+FILENAME
+: is expected to be an PCAP file.
+ The queries are send to the DNS server specified as *ADDRESS* and
+ *PORT*.
+
+ADDRESS
+: IPv4 or IPv6 address of the nameserver to replay *FILENAME* to.
+
+PORT
+: if omitted, 53 will be used.
+
+--help | -h
+: Show summary of options.
+
+--ecs-mask *VAL*
+: When EDNS forwarding an IP address, mask out first octet with this value
+
+--ecs-stamp *FLAG*
+: Add original IP address as EDNS Client Subnet Option when forwarding to
+ reference server
+
+--packet-limit *NUM*
+: Stop after replaying *NUM* packets. Default for *NUM* is 0, which means no
+ limit.
+
+--quiet *FLAG*
+: If *FLAG* is set to 1. dnsreplay will not be very noisy with its output.
+ This is the default.
+
+--recursive *FLAG*
+: If *FLAG* is set to 1. dnsreplay will only replay queries with recursion
+ desired flag set. This is the default.
+
+--speedup *FACTOR*
+: Replay queries with this speedup *FACTOR*. Default is 1.
+
+--timeout-msec *MSEC*
+: Wait at least *MSEC* milliseconds for a reply. Default is 500.
+
+# BUGS
+dnsreplay has no certain handling for timeouts. It handles around at most 65536
+outstanding answers.
+
+# SEE ALSO
+pcap(3PCAP), tcpdump(8), dnswasher(1)
--- /dev/null
+% DNSSCAN(1)
+% PowerDNS.com BV
+% April 2015
+
+# NAME
+**dnsscan** - List the amount of queries per qtype in a pcap
+
+# SYNOPSIS
+**dnsscan** *INFILE*...
+
+# DESCRIPTION
+**dnsscan** takes one or more *INFILE*s in PCAP format and generates a list of
+the number of queries per qtype.
+
+# OPTIONS
+None
+
+# SEE ALSO
+pcap(3PCAP), tcpdump(8)
+
--- /dev/null
+% DNSSCOPE(1)
+% Joerg Jungermann (jj+debian At borkum.net)
+% September 2012
+
+# NAME
+**dnsscope** - A PowerDNS nameserver debugging tool
+
+# SYNOPSIS
+**dnsscope** [*OPTION*]... *INFILE*
+
+# DESCRIPTION
+**dnsscope** takes an *INFILE* in PCAP format. It generates some simple
+statistics outputs these to STDOUT.
+
+# OPTIONS
+INFILE
+: Path to a PCAP file.
+
+-h | --help
+: Show the help.
+
+--rd
+: Only process packets in *INFILE* with the RD (Recursion Desired) flag set.
+ By default, we process all DNS packets in *INFILE*.
+
+--ipv4
+: Process IPv4 packets. On by default, disable with **--ipv4 false**.
+
+--ipv6
+: Process IPv6 packets. On by default, disable with **--ipv6 false**.
+
+--servfail-tree
+: Figure out subtrees that generate servfails.
+
+-l | --load-stats
+: Emit per-second load statistics (questions, answers, outstanding).
+
+-w | --write-failures *FILENAME*
+: Write weird packets to a PCAP file at *FILENAME*.
+
+-v | --verbose
+: Be more verbose.
+
+# SEE ALSO
+pcap(3PCAP), tcpdump(8)
--- /dev/null
+% DNSTCPBENCH(1)
+% PowerDNS.COM BV
+% July 2013
+
+# NAME
+**dnstcpbench** - tool to perform TCP benchmarking of nameservers
+
+# SYNOPSIS
+**dnstcpbench** [*OPTION*]... *REMOTE-ADDRESS* [*REMOTE-PORT*]
+
+# DESCRIPTION
+**dnstcpbench** reads DNS queries (by default from standard input) and sends
+them out in parallel to a remote nameserver. By default TCP/IP is used, but
+optionally, UDP is tried first, which allows for the benchmarking of TCP/IP
+fallback.
+
+The program reports both mean and median numbers for queries per second and
+UDP and TCP latency. Each query only counts once, even if it is tried over
+UDP first. This effectively means that passing '-u' can lower query rates if
+many queries get shunted to TCP.
+
+The input format is one query per line: qname single-space qtype. An
+example:
+
+www.powerdns.com ANY
+
+When benchmarking extended runs, it may be necessary to enable TIME_WAIT
+recycling, as TCP/IP port tuples may otherwise run out. On Linux this is
+performed by running:
+
+echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
+
+The equivalent for IPv6 is not known.
+
+# OPTIONS
+-f | --file *FILENAME*
+: *FILENAME* from which to read queries. Defaults to standard input if
+ unspecified.
+
+-h | --help
+: Provide a helpful message.
+
+--timeout-msec *MSEC*
+: *MSEC* milliseconds to wait for an answer.
+
+-u | --udp-first
+: Attempt resolution via UDP first, only do TCP if truncated answer is
+ received.
+
+-v | --verbose
+: Be wordy on what the program is doing.
+
+--workers *NUM*
+: Use *NUM* parallel worker threads.
+
+
+REMOTE-ADDRESS
+: IPv4 or IPv6 to test against.
+
+REMOTE-PORT
+: Port to test against, defaults to 53.
+
+# BUGS
+Currently the timeout code does not actually perform non-blocking connects
+or writes. So a slow connect or slow writes will still cause low
+performance and delays.
+
+Median queries per second statistics are reported as 0 for sub-second runs.
--- /dev/null
+% DNSWASHER(1)
+% Joerg Jungermann (jj+debian At borkum.net)
+% September 2012
+
+# NAME
+**dnswasher** - A PowerDNS nameserver debugging tool
+
+# SYNOPSIS
+**dnswasher** *INFILE* [*INFILE*] *OUTFILE*
+
+# DESCRIPTION
+dnswasher takes one or more *INFILE*s in PCAP format and writes out
+*OUTFILE* also in PCAP format, while obfuscating end-user IP addresses.
+
+This is useful to share data with third parties while attempting to protect
+the privacy of your users.
+
+The INFILEs must be of identical PCAP type.
+
+Please check the output of **dnswasher** to make sure no customer IP
+addresses remain. Also realize that sufficient data could allow
+individuals to be re-identified based on the domain names they care about.
+
+# OPTIONS
+None
+
+# SEE ALSO
+pcap(3PCAP), tcpdump(8)
--- /dev/null
+% DUMRESP(1)
+% PowerDNS.com BV
+% April 2016
+
+# NAME
+**dumresp** - A dumb DNS responder
+
+# SYNOPSIS
+ **dumresp** *LOCAL-ADDRESS* *LOCAL-PORT* *NUMBER-OF-PROCESSES*
+
+# DESCRIPTION
+**dumresp** accepts DNS packets on *LOCAL-ADDRESS*:*LOCAL-PORT* and simply replies
+with the same query, with the QR bit set. When *NUMBER-OF-PROCESSES* is set to
+anything but 1, **dumresp** will spawn *NUMBER-OF-PROCESSES* forks and use the
+SO_REUSEPORT option to bind to the port.
+
+# OPTIONS
+None
+
+# SEE ALSO
+socket(7)
--- /dev/null
+% IXPLORE(1)
+% Pieter Lexis (pieter.lexis@powerdns.com)
+% October 2015
+
+# NAME
+**ixplore** - A tool that provides insights into IXFRs
+
+# SYNOPSIS
+**ixplore** *COMMAND* *COMMAND_OPT*...
+
+**ixplore** diff *ZONE* *BEFORE* *AFTER*
+
+**ixplore** track *IP ADDRESS* *PORT* *ZONE* *DIRECTORY*
+
+# DESCRIPTION
+**ixplore** is a tool to work with IXFR (incremental zonetransfers) in two modes
+(specified by *COMMAND*): diff or track.
+
+In the 'diff' mode, it will show a diff(1)-like output between *BEFORE* and *AFTER*.
+
+In the 'track' mode, **ixplore** consumes IXFRs from *IP ADDRESS* and writes the
+resulting zonefiles out to *DIRECTORY*/*ZONE*-serial. If no initial zonefiles
+exist, an initial AXFR will be done first. **ixplore** will then check the SOA
+serial on *IP ADDRESS* for *ZONE* every SOA Refresh seconds and perform an IXFR
+if the serial has increased.
+
+# OPTIONS
+## diff-mode
+ZONE
+: The name of the zone the IXFRs are consumed from.
+
+BEFORE
+: Path to the 'before' zonefile.
+
+AFYER
+: Path to the 'after' zonefile.
+
+
+## track-mode
+IP ADDRESS
+: The IP address to consume IXFRs from.
+
+PORT
+: The port to use on *IP ADDRESS*.
+
+ZONE
+: Name of the zone to track changes of.
+
+DIRECTORY
+: Directory where the zonefiles will be stored.
+
+# SEE ALSO
+diff(1)
--- /dev/null
+% NPROXY(1)
+% PowerDNS.com BV
+% April 2016
+
+# NAME
+**nproxy** - DNS notification proxy
+
+# SYNOPSIS
+nproxy --powerdns-address *ADDRESS* [*OPTION*]... *ADDRESS*...
+
+# DESCRIPTION
+**nproxy** is a simple daemon that reads DNS NOTIFY queries on one address and
+forwards them to an 'inner' nameserver that will process the notification.
+
+Its usecase is e.g. a private authoritative server inside a NAT or firewalled LAN
+where **nproxy** is deployed in the DMZ.
+
+The PowerDNS Authoritative Server has the trusted-notification-proxy option that
+should be set to the address set with *--origin-address* to accept these proxied
+notifications.
+
+**nproxy** also has a health-check option built in. A query for 'pdns.nproxy.'
+with QType 'TXT' will be responded to with an answer of "OK" (inside the TXT record.
+When the query is for an A-record, '1.2.3.4.' is returned.
+
+# OPTIONS
+--powerdns-address *ADDRESS*
+: IP address of the PowerDNS server to forward the notifications to.
+
+--chroot *PATH*
+: chroot to *PATH* for additional security.
+
+--setuid *UID*
+: setuid to this numerical *UID*.
+
+--setgid *GID*
+: setgid to this numerical *GID*.
+
+--origin-address *ADDRESS*
+: Set the source of the notifications sent to PowerDNS to *ADDRESS*. By default,
+ the best matching address (kernel's choice) is used.
+
+--listen-address *ADDRESS*
+: IP addresses to listen on.
+
+--listen-port *PORT*
+: Source port to listen on, 53 by default.
+
+-d,--daemon *ARG*
+: Set *ARG* to 0 to disable running in the background.
+
+-v,--verbose
+: Be verbose
+
--- /dev/null
+% NSEC3DIG(1)
+% PowerDNS.com BV
+% April 2015
+
+# NAME
+**nsec3dig** - Show and validate NSEC3 proofs
+
+# SYNOPSIS
+**nsec3dig** *IPADDRESS* *PORT* *QNAME* *QTYPE* [recurse]
+
+# DESCRIPTION
+**nsec3dig** sends a query for *QNAME* and *QTYPE* to the nameserver at *IPADDRESS*
+on port *PORT* and prints whether and why the NSEC3 proofs are correct. Using the
+'recurse' option sets the Recursion Desired (RD) bit in the query.
+
+# EXAMPLE
+`nsec3dig 8.8.8.8 53 doesntexist.isoc.nl TXT recurse`
--- /dev/null
+% PDNS_CONTROL(1)
+% PowerDNS.com BV
+% December 2002
+
+# NAME
+**pdns_control** - Control the PowerDNS nameserver
+
+# SYNOPSIS
+**pdns_control** [*OPTION*]... *COMMAND*
+
+# DESCRIPTION
+**pdns_control** is used to send commands to a running PowerDNS nameserver.
+
+# OPTIONS
+--help
+: Show summary of options.
+
+--chroot=*DIR*
+: Directory where PowerDNS is chrooted.
+
+--config-dir=*DIR*
+: Location of configuration directory (pdns.conf).
+
+--config-name=*NAME*
+: Name of this virtual configuration - will rename the binary image.
+
+--remote-address=*ADDRESS*
+: Remote address to query.
+
+--remote-port=*PORT*
+: Remote port to query.
+
+--secret=*SECRET*
+: Secret needed to connect to remote PowerDNS.
+
+--socket-dir=*DIR*
+: Where the controlsocket lives.
+
+
+# COMMANDS
+bind-add-zone *DOMAIN* *FILENAME*
+: When using the bindbackend, add a zone. This zone is added in-memory and served
+ immediately. Note that this does not add the zone to the bind-config file.
+ *FILENAME* must be an absolute path.
+
+bind-domain-status [*DOMAIN*...]
+: When using the bindbackend, list status of all domains. Optionally, append
+ *DOMAIN*s to get the status of specific zones.
+
+bind-list-rejects
+: When using the bindbackend, get a list of all rejected domains.
+
+bind-reload-now *DOMAIN* [*DOMAIN*...]
+: When using the bindbackend, immediately reload *DOMAIN* from disk.
+
+ccounts
+: Show the content of the cache.
+
+current-config
+: Show the currently running configuration. The output has the same format as
+ `pdns_server --config`. You'll notice that all the are uncommented. This is
+ because PowerDNS simply has values, and the default isn't known at runtime.
+
+cycle
+: Restart the nameserver so it reloads its configuration. Only works when the
+ server is running in guardian mode.
+
+list
+: Dump all variables and their values in a comma separated list, equivalent
+ to **show \***.
+
+list-zones [master,slave,native]
+: Show a list of zones, optionally filter on the type of zones to show.
+
+notify *DOMAIN*
+: Adds *DOMAIN* to the notification list, causing PowerDNS to send out
+ notifications to the nameservers of a domain. Can be used if a slave missed
+ previous notifications or is generally hard of hearing.
+
+notify-host *DOMAIN* *ADDRESS*
+: Same as above but with operator specified IP *ADDRESS* as destination, to be
+ used if you know better than PowerDNS.
+
+ping, rping
+: Check if the server is still alive. Will return 'PONG' when it is.
+ **ping** works when running inside a guardian, whereas **rping** works when
+ running without a guardian.
+
+purge [*RECORD*]
+: Purge entries from the cache. If *RECORD* ends with a dollar ($)
+ all entries that end with that name are removed. If no record is specified
+ the entire cache is purged.
+
+qtypes
+: Get a count of queries per qtype on standard out.
+
+quit
+: Tell a running pdns_server to quit.
+
+rediscover
+: Instructs backends that new domains may have appeared in the database, or,
+ in the case of the Bind backend, in named.conf.
+
+reload
+: Instruct the server to reload all its zones, this will not add new zones.
+
+remotes
+: Get the top number of remote addresses (clients).
+
+respsizes
+: Get a histogram of the response sizes.
+
+retrieve *DOMAIN*
+: Retrieve slave *DOMAIN* from its master. Done nearly immediately.
+
+set *VARIABLE* *VALUE*
+: Set the configuration parameter *VARIABLE* to *VALUE*. Currently only the
+ query-logging can be set.
+
+show *VARIABLE*
+: Show a single statistic, as present in the output of the list command.
+
+status
+: Show usage statistics. This only works if the server is running in guardian
+ mode.
+
+token-login *MODULE* *SLOT* *PIN*
+: Log on to a PKCS#11 slot. You only need to login once per slot, even if you
+ have multiple keys on single slot. Only available if PowerDNS was compiled
+ with PKCS#11 support.
+
+uptime
+: Show the uptime of the running server.
+
+version
+: Print the version of the running pdns daemon.
+
+# SEE ALSO
+pdns_server(1)
--- /dev/null
+% PDNS_NOTIFY(1)
+% PowerDNS.com BV
+% April 2016
+
+# NAME
+**pdns_notify** - A simple DNS NOTIFY sender
+
+# SYNOPSIS
+**pdns_notify** *IP_ADDRESS*[:*PORT*] *DOMAIN*
+
+# DESCRIPTION
+**pdns_notify** sends a DNS NOTIFY message to *IP_ADDRESS*, by default on port 53, for
+*DOMAIN* and prints the remote nameserver's response.
+
+# OPTIONS
+None
--- /dev/null
+% PDNS_RECURSOR(1)
+% PowerDNS.COM BV
+% March 2008
+
+# NAME
+**pdns_recursor** - high-performance, simple and secure recursing nameserver
+
+# SYNOPSIS
+**pdns_recursor** [*OPTION*]...
+
+# DESCRIPTION
+pdns_recursor(1) is a high performance, simple and secure recursing
+nameserver. It currently powers over two million internet connections.
+
+The recursor is configured via a configuration file, but each item in
+that file can be overridden on the command line.
+
+This manpage lists the core set of features needed to get the PowerDNS
+recursor working, for full and up to date details head to
+http://doc.powerdns.com/built-in-recursor.html
+
+# EXAMPLES
+To listen on 192.0.2.53 and allow the 192.0.2.0/24 subnet to recurse, and run
+as a daemon, execute:
+
+`# pdns_recursor --local-address=192.0.2.53 --allow-from=192.0.2.0/24 --daemon`
+
+To stop the recursor by hand, run:
+
+`# rec_control quit`
+
+However, the recommended way of starting and stopping the recursor is to use
+the init.d script provided.
+
+# OPTIONS
+For authoritative listing of options, consult the online documentation at
+http://doc.powerdns.com/md/recursor/settings/
+
+--allow-from=*NETWORK*[,*NETWORK*]...
+: If set, only allow these comma separated *NETWORK*s, with network mask to
+ recurse. For example: 192.0.2.0/24,203.0.113.128/25.
+
+--auth-zones=*ZONENAME*=*FILENAME*[,*ZONENAME*=*FILENAME*]...
+: Serve *ZONENAME* from *FILENAME* authoritatively. For example:
+ ds9a.nl=/var/zones/ds9a.nl,powerdns.com=/var/zones/powerdns.com.
+
+--chroot=*DIRECTORY*
+: chroot the process to *DIRECTORY*.
+
+--client-tcp-timeout=*NUM*
+: Timeout in seconds when talking to TCP clients.
+
+--config-dir=*DIRECTORY*
+: Location of configuration directory (recursor.conf), the default depends on
+ the SYSCONFDIR option at build-time, which is usually /etc/powerdns. The
+ default can be found with `pdns_recursor --config | grep ' config-dir='`.
+
+--daemon
+: Operate as a daemon.
+
+--delegation-only
+: Which domains we only accept delegations from (a Verisign special).
+
+--entropy-source=*FILE*
+: Read new entropy from *FILE*, defaults to /dev/urandom.
+
+--export-etc-hosts
+: If set, this flag will export the hostnames and IP addresses mentioned in
+ /etc/hosts.
+
+--forward-zones=*ZONENAME*=*ADDRESS*[,*ZONENAME*=*ADDRESS*]...
+: Queries for *ZONENAME* will be forwarded to *ADDRESS*. *ADDRESS*
+ should be an IP address, not a hostname (to prevent chicken and egg
+ problems). Example:
+ forward-zones= ds9a.nl=213.244.168.210, powerdns.com=127.0.0.1.
+
+--forward-zones-file=*FILENAME*
+: Similar to *--forward-zones*, but read the options from *FILENAME*.
+ *FILENAME* should contain one zone per line, like: ds9a.nl=213.244.168.210.
+
+--help
+: Show a summary of options.
+
+--hint-file=*FILENAME*
+: Load root hints from this *FILENAME*
+
+--local-address=*ADDRESS*[,*ADDRESS*]...
+: Listen on *ADDRESS*, separated by spaces or commas.
+
+--local-port=*PORT*
+: Listen on *PORT*.
+
+--log-common-errors
+: If we should log rather common errors.
+
+--max-cache-entries=*NUM*
+: Maximum number of entries in the main cache.
+
+--max-negative-ttl=*NUM*
+: maximum number of seconds to keep a negative cached entry in memory.
+
+--max-tcp-clients=*NUM*
+: Maximum number of simultaneous TCP clients.
+
+--max-tcp-per-client
+: If set, maximum number of TCP sessions per client (IP address).
+
+--query-local-address=*ADDRESS*
+: Use *ADDRESS* as Source IP address when sending queries.
+
+--query-local-address6=*ADDRESS*
+: Send out local IPv6 queries from *ADDRESS*. Disabled by default,
+ which also disables outgoing IPv6 support. A useful setting is
+ '::0'.
+
+--quiet
+: Suppress logging of questions and answers.
+
+--server-id=*TEXT*
+: Return *TEXT* when queried for 'server.id' TXT, defaults to hostname.
+
+--serve-rfc1918
+: On by default, this makes the server authoritatively aware of:
+ 10.in-addr.arpa, 168.192.in-addr.arpa and 16-31.172.in-addr.arpa, which
+ saves load on the AS112 servers. Individual parts of these zones can still
+ be loaded or forwarded.
+
+--setgid=*GID*
+: If set, change group id to *GID* for more security.
+
+--setuid=*UID*
+: If set, change user id to *UID* for more security.
+
+--single-socket
+: If set, only use a single socket for outgoing queries.
+
+--socket-dir=*DIRECTORY*
+: The controlsocket will live in *DIRECTORY*.
+
+--spoof-nearmiss-max=*NUM*
+: If non-zero, assume spoofing after this many near misses.
+
+--trace
+: if we should output heaps of logging.
+
+--version-string=*TEXT*
+: *TEXT* will be reported on version.pdns or version.bind queries.
+
+# BUGS
+None known. File new ones at https://github.com/PowerDNS/pdns/issues.
+
+# RESOURCES
+Website: http://www.powerdns.com, https://github.com/PowerDNS/pdns
+
+# SEE ALSO
+rec_control(1)
--- /dev/null
+% PDNS_SERVER(1)
+% PowerDNS.COM BV
+% December 2012
+
+# NAME
+**pdns_server** - The PowerDNS Authoritative Namserver
+
+# SYNOPSIS
+**pdns_server** [*OPTION*]
+
+# DESCRIPTION
+The PowerDNS Authoritative Server is a versatile nameserver which supports a
+large number of backends. These backends can either be plain zone files or be
+more dynamic in nature. Please see the online documentation for more
+information.
+
+# OPTIONS
+See the online documentation for all options
+
+--daemon={**yes**,**no**}
+: Indicate if the server should run in the background as a real daemon,
+ or in the foreground.
+
+--guardian={**yes**,**no**}
+: Run **pdns_server** inside a guardian. This guardian monitors the performance
+ of the inner **pdns_server** instance. It is also this guardian that
+ **pdns_control**(8) talks to.
+
+--control-console
+: Run the server in a special monitor mode. This enables detailed logging
+ and exposes the raw control socket.
+
+--loglevel=*LEVEL*
+: Set the logging level.
+
+--help
+To view more options that are available use this program.
+
+# SEE ALSO
+pdns_control(1), pdnsutil(1), http://doc.powerdns.com/md/authoritative/
--- /dev/null
+% PDNSUTIL(1) PowerDNS DNSSEC command and control
+% Matthijs Möhlmann <matthijs@cacholong.nl>
+% November 2011
+
+# NAME
+pdnsutil - PowerDNS dnssec command and control
+
+# SYNOPSIS
+pdnsutil [OPTION]... *COMMAND*
+
+# DESCRIPTION
+**pdnsutil** (formerly pdnssec) is a powerful command that is the operator-friendly
+gateway into DNSSEC and zone management for PowerDNS. Behind the scenes, **pdnsutil**
+manipulates a PowerDNS backend database, which also means that for many databases,
+**pdnsutil** can be run remotely, and can configure key material on different servers.
+
+# OPTIONS
+-h | -help
+: Show summary of options
+
+-v | --verbose
+: Be more verbose.
+
+--force
+: force an action
+
+--config-name *NAME*
+: Virtual configuration name
+
+--config-dir *DIR*
+: Location of pdns.conf. Default is /etc/powerdns.
+
+# COMMANDS
+There are many available commands, this section splits them up into their
+respective uses
+
+## DNSSEC RELATED COMMANDS
+Several commands manipulate the DNSSEC keys and options for zones. Some of these
+commands require an *ALGORITHM* to be set. The following algorithms are
+supported:
+
+ * rsasha1
+ * rsasha256
+ * rsasha512
+ * gost
+ * ecdsa256
+ * ecdsa384
+
+activate-zone-key *ZONE* *KEY-ID*
+: Activate a key with id *KEY-ID* within a zone called *ZONE*.
+
+add-zone-key *ZONE* {**KSK**,**ZSK**} [**active**,**inactive**] *KEYBITS* *ALGORITHM*
+: Create a new key for zone *ZONE*, and make it a KSK or a ZSK, with the
+ specified algorithm. The key is inactive by default, set it to **active** to
+ immediately use it to sign *ZONE*.
+
+create-bind-db *FILE*
+: Create DNSSEC database (sqlite3) at *FILE* for the BIND backend.
+ Remember to set `bind-dnssec-db=*FILE*` in your `pdns.conf`.
+
+deactivate-zone-key *ZONE* *KEY-ID*
+: Deactivate a key with id KEY-ID within a zone called *ZONE*.
+
+disable-dnssec *ZONE*
+: Deactivate all keys and unset PRESIGNED in *ZONE*.
+
+export-zone-dnskey *ZONE* *KEY-ID*
+: Export to standard output DNSKEY and DS of key with key id *KEY-ID* within
+ zone called *ZONE*.
+
+export-zone-key *ZONE* *KEY-ID*
+: Export to standard output full (private) key with key id *KEY-ID* within
+ zone called *ZONE*. The format used is compatible with BIND and NSD/LDNS.
+
+generate-zone-key {**KSK**,**ZSK**} [*ALGORITHM*] [*KEYBITS*]
+: Generate a ZSK or KSK to stdout with specified algorithm and bits and print
+ it on STDOUT. If *ALGORITHM* is not set, RSASHA512 is used. If *KEYBITS* is
+ not set, an appropriate keysize is selected for *ALGORITHM*.
+
+import-zone-key *ZONE* *FILE* {**KSK**,**ZSK**}
+: Import from *FILE* a full (private) key for zone called *ZONE*. The format
+ used is compatible with BIND and NSD/LDNS. **KSK** or **ZSK** specifies the
+ flags this key should have on import.
+
+remove-zone-key *ZONE* *KEY-ID*
+: Remove a key with id *KEY-ID* from a zone called *ZONE*.
+
+set-nsec3 *ZONE* '*HASH-ALGORITHM* *FLAGS* *ITERATIONS* *SALT*' [**narrow**]
+: Sets NSEC3 parameters for this zone. The quoted parameters are 4 values
+ that are used for the the NSEC3PARAM record and decide how NSEC3 records
+ are created. The NSEC3 parameters must be quoted on the command line.<br><br>
+ *HASH-ALGORITHM* must be 1 (SHA-1).<br><br>
+ Setting *FLAGS* to 1 enables NSEC3 opt-out operation. Only do this if you
+ know you need it.<br><br>
+ For *ITERATIONS*, please consult RFC 5155, section 10.3. And be aware
+ that a high number might overload validating resolvers.<br><br>
+ The *SALT* is a hexadecimal string encoding the bits for the salt.<br><br>
+ Setting **narrow** will make PowerDNS send out "white lies" about the next
+ secure record. Instead of looking it up in the database, it will send out
+ the hash + 1 as the next secure record. <br><br>
+ A sample commandline is: "pdnsutil set-nsec3 powerdnssec.org '1 1 1 ab' narrow".<br><br>
+ **WARNING**: If running in RSASHA1 mode (algorithm 5 or 7), switching from
+ NSEC to NSEC3 will require a DS update in the parent zone.
+
+unset-nsec3 *ZONE*
+: Converts *ZONE* to NSEC operations. **WARNING**: If running in RSASHA1 mode
+ (algorithm 5 or 7), switching from NSEC to NSEC3 will require a DS update
+ at the parent zone!
+
+set-publish-cds *ZONE* [*DIGESTALGOS*]
+: Set *ZONE* to respond to queries for its CDS records. the optional argument
+ *DIGESTALGOS* should be a comma-separated list of DS algorithms to use. By
+ default, this is 1,2 (SHA1 and SHA2-256).
+
+set-publish-cdnskey *ZONE*
+: Set *ZONE* to publish CDNSKEY records.
+
+unset-publish-cds *ZONE*
+: Set *ZONE* to stop responding to queries for its CDS records.
+
+unset-publish-cdnskey *ZONE*
+: Set *ZONE* to stop publishing CDNSKEY records.
+
+## TSIG RELATED COMMANDS
+These commands manipulate TSIG key information in the database. Some commands
+require an *ALGORITHM*, the following are available:
+
+ * hmac-md5
+ * hmac-sha1
+ * hmac-sha224
+ * hmac-sha256
+ * hmac-sha384
+ * hmac-sha512
+
+activate-tsig-key *ZONE* *NAME* {**master**,**slave**}
+: Enable TSIG authenticated AXFR using the key *NAME* for zone *ZONE*.
+ This sets the `TSIG-ALLOW-AXFR` (master) or `AXFR-MASTER-TSIG` (slave)
+ zone metadata.
+
+deactivate-tsig-key *ZONE* *NAME* {**master**,**slave**}
+: Disable TSIG authenticated AXFR using the key *NAME* for zone *ZONE*.
+
+delete-tsig-key *NAME*
+: Delete the TSIG key *NAME*. Warning, this does not deactivate said key.
+
+generate-tsig-key *NAME* *ALGORITHM*
+: Generate new TSIG key with name *NAME* and the specified algorithm.
+
+## ZONE MANIPULATION COMMANDS
+create-zone *ZONE*
+: Create an empty zone named *ZONE*.
+
+check-all-zones
+: Check all zones for correctness.
+
+check-zone *ZONE*
+: Check zone *ZONE* for correctness.
+
+clear-zone *ZONE*
+: Clear the records in zone *ZONE*, but leave actual domain and settings unchanged
+
+delete-zone *ZONE*:
+: Delete the zone named *ZONE*.
+
+edit-zone *ZONE*
+: Opens *ZONE* in zonefile format (regardless of backend it was loaded from)
+ in the editor set in the environment variable **EDITOR**. if **EDITOR** is
+ empty, *pdnsutil* falls back to using *editor*.
+
+get-meta *ZONE* [*ATTRIBUTE*]...
+: Get zone metadata. If no *ATTRIBUTE* given, lists all known.
+
+hash-zone-record *ZONE* *RNAME*
+: This convenience command hashes the name *RNAME* according to the NSEC3
+ settings of *ZONE*. Refuses to hash for zones with no NSEC3 settings.
+
+list-keys [*ZONE*]
+: List DNSSEC information for all keys or for *ZONE*.
+
+list-all-zones:
+: List all zone names.
+
+list-zone *ZONE*
+: Show all records for *ZONE*.
+
+load-zone *ZONE* *FILE*
+: Load records for *ZONE* from *FILE*. If *ZONE* already exists, all records
+ are overwritten, this operation is atomic. If *ZONE* doesn't exist, it is
+ created.
+
+rectify-zone *ZONE*
+: Calculates the 'ordername' and 'auth' fields for a zone called *ZONE* so
+ they comply with DNSSEC settings. Can be used to fix up migrated data. Can
+ always safely be run, it does no harm.
+
+secure-zone *ZONE*
+: Configures a zone called *ZONE* with reasonable DNSSEC settings. You should
+ manually run 'pdnsutil rectify-zone' afterwards.
+
+set-meta *ZONE* *ATTRIBUTE* [*VALUE*]
+: Set domainmetadata *ATTRIBUTE* for *ZONE* to *VALUE*. An empty value clears it.
+
+set-presigned *ZONE*
+: Switches *ZONE* to presigned operation, utilizing in-zone RRSIGs.
+
+show-zone *ZONE*
+: Shows all DNSSEC related settings of a zone called *ZONE*.
+
+test-schema *ZONE*
+: Test database schema, this creates the zone *ZONE*
+
+unset-presigned *ZONE*
+: Disables presigned operation for *ZONE*.
+
+## DEBUGGING TOOLS
+
+backend-cmd *BACKEND* *CMD* [*CMD..*]
+: Send a text command to a backend for execution. GSQL backends will take SQL
+ commands, other backends may take different things. Be careful!
+
+# SEE ALSO
+pdns_server (1), pdns_control (1)
--- /dev/null
+% REC_CONTROL(1)
+% PowerDNS.COM BV
+% April 2006
+
+# NAME
+rec_control - control pdns_recursor
+
+# SYNOPSIS
+**rec_control** [*OPTION*]... *COMMAND* [*COMMAND-OPTION*]...
+
+DESCRIPTION
+-----------
+**rec_control** allows the operator to control a running instance
+of the pdns_recursor.
+
+The commands that can be passed to the recursor are described on
+http://doc.powerdns.com/md/recursor/running/\#rec_control-commands
+
+# EXAMPLES
+To stop the recursor by hand, run:
+
+`# rec_control quit`
+
+To dump the cache to disk, execute:
+
+`# rec_control dump-cache /tmp/the-cache`
+
+# OPTIONS
+--help
+: provide this helpful message.
+
+--config-dir=*PATH*
+: Directory where the recursor.conf lives.
+
+--socket-dir=*PATH*
+: Where the controlsocket will live, please use **--config-dir** instead.
+
+--socket-pid=*PID*
+: When running in SMP mode, pid of **pdns_recursor** to control.
+
+--timeout=*NUM*
+: Number of seconds to wait for the remote PowerDNS Recursor to
+ respond. Set to 0 for infinite.
+
+# COMMANDS
+add-nta *DOMAIN* [*REASON*]
+: Add a Negative Trust Anchor for *DOMAIN*, suffixed optionally with *REASON*.
+
+add-ta *DOMAIN* *DSRECORD*
+: Add a Trust Anchor for *DOMAIN* with DS record data *DSRECORD*. This adds the
+ new Trust Anchor to the existing set of Trust Anchors for *DOMAIN*.
+
+current-queries
+: Shows the currently active queries.
+
+clear-nta *DOMAIN*...
+: Remove Negative Trust Anchor for one or more *DOMAIN*s. Set domain to `'*'`
+ to remove all NTA's.
+
+clear-ta [*DOMAIN*]...
+: Remove Trust Anchor for one or more *DOMAIN*s. Note that removing the root
+ trust anchor is not possible.
+
+dump-cache *FILENAME*
+: Dumps the entire cache to *FILENAME*. This file should
+ not exist already, PowerDNS will refuse to overwrite it. While
+ dumping, the recursor will not answer questions.
+
+dump-edns *FILENAME*
+: Dumps the EDNS status to the filename mentioned. This file should
+ not exist already, PowerDNS will refuse to overwrite it. While
+ dumping, the recursor will not answer questions.
+
+dump-nsspeeds *FILENAME*
+: Dumps the nameserver speed statistics to the *FILENAME* mentioned.
+ This file should not exist already, PowerDNS will refuse to
+ overwrite it. While dumping, the recursor will not answer questions.
+
+get *STATISTIC* [*STATISTIC*]...
+: Retrieve a statistic. For items that can be queried, see
+ http://doc.powerdns.com/md/recursor/stats/
+
+get-all
+: Retrieve all known statistics.
+
+get-ntas
+: Get a list of the currently configured Negative Trust Anchors.
+
+get-tas
+: Get a list of the currently configured Trust Anchors.
+
+get-parameter *KEY* [*KEY*]...
+: Retrieves the specified configuration parameter(s).
+
+get-qtypelist
+: Retrieves QType statistics. Queries from cache aren't being counted yet.
+
+help
+: Shows a list of supported commands.
+
+ping
+: Check if server is alive.
+
+quit
+: Request shutdown of the recursor.
+
+quit-nicely
+: Request nice shutdown of the recursor.
+
+reload-acls
+: Reloads ACLs.
+
+reload-lua-script [*FILENAME*]
+: (Re)loads Lua script *FILENAME*. If *FILENAME* is empty, attempt to reload
+ the currently loaded script. This replaces the script currently loaded.
+
+reload-lua-config [*FILENAME*]
+: (Re)loads Lua configuration *FILENAME*. If *FILENAME* is empty, attempt to
+ reload the currently loaded file. Note that *FILENAME* will be fully executed,
+ any settings changed at runtime that are not modified in this file, will
+ still be active. Reloading RPZ, especially by AXFR, can take some time; during
+ which the recursor will not answer questions.
+
+reload-zones
+: Reload authoritative and forward zones. Retains current configuration
+ in case of errors.
+
+set-carbon-server *CARBON SERVER* [*CARBON OURNAME*]
+: Set the carbon-server setting to *CARBON SERVER*. If *CARBON OURNAME* is not
+ empty, also set the carbon-ourname setting to *CARBON OURNAME*.
+
+set-dnssec-log-bogus *SETTING*
+: Set dnssec-log-bogus setting to *SETTING*. Set to 'on' or 'yes' to log DNSSEC
+ validation failures and to 'no' or 'off' to disable logging these failures.
+
+set-minimum-ttl *NUM*
+: Set minimum-ttl-override to *NUM*.
+
+top-queries
+: Shows the top-20 queries. Statistics are over the last
+ 'stats-ringbuffer-entries' queries.
+
+top-largeanswer-remotes
+: Shows the top-20 remote hosts causing large answers. Statistics are over the
+ last 'stats-ringbuffer-entries' queries.
+
+top-remotes
+: Shows the top-20 most active remote hosts. Statistics are over the
+ last 'stats-ringbuffer-entries' queries.
+
+top-servfail-queries
+: Shows the top-20 queries causing servfail responses. Statistics are
+ over the last 'stats-ringbuffer-entries' queries.
+
+top-servfail-remotes
+: Shows the top-20 most active remote hosts causing servfail responses.
+ Statistics are over the last 'stats-ringbuffer-entries' queries.
+
+trace-regex *REGEX*
+: Emit resolution trace for matching queries. Empty regex to disable trace.
+
+unload-lua-script
+: Unloads Lua script.
+
+version
+: Report running version.
+
+wipe-cache *DOMAIN* [*DOMAIN*] [...]
+: Wipe entries for *DOMAIN* (exact name match) from the cache. This is useful
+ if, for example, an important server has a new IP address, but the TTL has
+ not yet expired. Multiple domain names can be passed. *DOMAIN* can be
+ suffixed with a '$' to delete the whole tree from the cache. i.e. 'powerdns.com$'
+ will remove all cached entries under and including the powerdns.com name.
+
+# BUGS
+None known. File new ones at https://github.com/PowerDNS/pdns/issues.
+
+# RESOURCES
+Website: https://docs.powerdns.com, https://www.powerdns.com
+
+# SEE ALSO
+pdns_recursor(1)
--- /dev/null
+% SAXFR(1)
+% PowerDNS.com BV
+% April 2015
+
+# NAME
+**saxfr** - Perform AXFRs and show information about it
+
+# SYNOPSIS
+**saxfr** *IPADDRESS* *PORT* *ZONE* [*OPTIONS*]
+
+# DESCRIPTION
+**saxfr** does a zone-transfer (AXFR) of *ZONE* from the nameserver at *IPADDRESS*
+on port *PORT* and displays the transferred zone with NSEC3 information truncated.
+See below how to show this information.
+
+# OPTIONS
+showdetails
+: Show all the data in the NSEC3 and DNSKEY RDATA.
+
+showflags
+: Show the NSEC3 flags in the RDATA.
+
+unhash
+: Unhash the NSEC3 names to the normal names.
--- /dev/null
+% SDIG(1)
+% PowerDNS.com BV
+% September 2015
+
+# NAME
+**sdig** - Perform a DNS query and show the results
+
+# SYNOPSIS
+**sdig** *IPADDRESS* *PORT* *QNAME* *QTYPE* [*OPTIONS*]
+
+# DESCRIPTION
+**sdig** sends a DNS query to *IPADDRESS* on port *PORT* and displays the answer
+in a formatted way.
+
+# OPTIONS
+These options can be added to the commandline in any order.
+dnssec
+: Set the DO bit to request DNSSEC information.
+
+hidesoadetails
+: Don't show the SOA serial in the response.
+
+recurse
+: Set the RD bit in the question.
+
+showflags
+: Show the NSEC3 flags in the response.
+
+tcp
+: Use TCP instead of UDP to send the query.
+
+ednssubnet *SUBNET*
+: Send *SUBNET* in the edns-client-subnet option. If this option is not set,
+ no edns-client-subnet option is set in the query.
--- /dev/null
+% ZONE2JSON(1)
+% PowerDNS
+% January 2016
+
+# NAME
+**zone2json** - convert BIND zones to JSON
+
+# SYNOPSIS
+**zone2json** {**--named-conf=***PATH*,**--zone-file=***PATH* [**--zone-name=***NAME*]} [*OPTIONS*]
+
+# DESCRIPTION
+**zone2json** parses Bind named.conf files and zonefiles and outputs JSON
+on standard out, which can then be fed to the PowerDNS API.
+
+**zone2json** understands the Bind master file extension `$GENERATE` and will
+also honour `$ORIGIN` and `$TTL`.
+
+# OPTIONS
+## INPUT OPTIONS
+--named-conf=*PATH*
+: Read *PATH* to get the bind configuration
+
+--zone=*PATH*
+: Parse only the zone file at *PATH* Conflicts with **--named-conf** parameter.
+
+--zone-name=*NAME*
+: When parsing a single zone without $ORIGIN statement, set *ZONE* as the zone
+ name.
+
+## OTHER OPTIONS
+--help
+: List all options
+
+--on-error-resume-next
+: Ignore missing zone files during parsing. Dangerous.
+
+--verbose
+: Be verbose during conversion.
+
+# SEE ALSO
+pdns_server(1)
--- /dev/null
+% ZONE2LDAP(1)
+% Matthijs Möhlmann <matthijs@cacholong.nl>
+% November 2004
+
+# NAME
+**zone2ldap** - convert zonefiles to ldif
+
+# SYNOPSIS
+**zone2ldap** {**--named-conf=***PATH*,**--zone-file=***PATH*
+**--zone-name=***NAME*} [*OPTION*]...
+
+# DESCRIPTION
+**zone2ldap** is a program that converts bind zonefiles to ldif format which can
+inserted to an LDAP server.
+
+# OPTIONS
+--help
+: Show summary of options.
+
+--basedn=*DN*
+: Base DN to store objects below
+
+--dnsttl
+: Add dnsttl attribute to every entry
+
+--layout={**simple,tree**}
+: How to arrange entries in the directory (simple or as tree)
+
+--named-conf=*PATH*
+: Path to a Bind 8 named.conf to parse
+
+--resume
+: Continue after errors
+
+--verbose
+: verbose comments on operation
+
+--zone-file=*PATH*
+: Zone file to parse
+
+--zone-name=*NAME*
+: Specify a zone name if zone is set
+
+# SEE ALSO
+pdns_server(1)
--- /dev/null
+% ZONE2SQL(1)
+% PowerDNS
+% December 2002
+
+# NAME
+**zone2sql** - convert BIND zones to SQL
+
+# SYNOPSIS
+**zone2sql** {**--named-conf=***PATH*,**--zone-file=***PATH* [**--zone-name=***NAME*]} [*OPTIONS*]
+
+# DESCRIPTION
+**zone2sql** parses Bind named.conf files and zonefiles and outputs SQL
+on standard out, which can then be fed to your database.
+
+**zone2sql** understands the Bind master file extension `$GENERATE` and will
+also honour `$ORIGIN` and `$TTL`.
+
+For backends supporting slave operation there is also an option to keep slave
+zones as slaves, and not convert them to native operation.
+
+**zone2sql** can generate SQL for the Generic MySQL, Generic PostgreSQL, Generic
+SQLite3 and Generic Oracle backends.
+
+# OPTIONS
+## INPUT OPTIONS
+--named-conf=*PATH*
+: Read *PATH* to get the bind configuration
+
+--zone=*PATH*
+: Parse only the zone file at *PATH* Conflicts with **--named-conf** parameter.
+
+--zone-name=*NAME*
+: When parsing a single zone without $ORIGIN statement, set *ZONE* as the zone
+ name.
+
+## BACKENDS
+--gmysql
+: Output in format suitable for the default configuration of the Generic MySQL
+ backend.
+
+--gpgsql
+: Output in format suitable for the default configuration of the Generic
+ PostgreSQL backend.
+
+--gsqlite
+: Output in format suitable for the default configuration of the Generic
+ SQLite3 backend.
+
+--goracle
+: Output in format suitable for the default configuration of the Generic Oracle
+ backend.
+
+--mydns
+: Output in a format suitable for the MyDNS backend.
+
+--oracle
+: Output in format suitable for the default configuration of the Oracle backend.
+
+## OUTPUT OPTIONS
+--json-comments
+: Parse JSON in zonefile comments to set the 'disabled' and 'comment' fields
+ in the database. See *JSON COMMENTS* for more information.
+
+--transactions
+: If the target SQL backend supports transactions, wrap every domain into
+ a transaction for integrity and possibly higher speed.
+
+## OTHER OPTIONS
+--filter-duplicate-soa
+: If there's more than one SOA record in the zone (possibly because it was
+ AXFR'd), ignore it. If this option is not set, all SOA records in the zone
+ are emitted.
+
+--help
+: List all options
+
+--on-error-resume-next
+: Ignore missing zone files during parsing. Dangerous.
+
+--slave
+: Maintain slave status of zones listed in named.conf as being slaves. The
+ default behaviour is to convert all zones to native operation.
+
+--verbose
+: Be verbose during conversion.
+
+# JSON COMMENTS
+The Generic SQL backends have the 'comment' and 'disabled' fields in the 'records'
+table. The 'comment' field contains a comment for this record (if any) and the
+'disabled' field tells PowerDNS if the record can be served to clients.
+
+When a zonefile contains a comment like `; json={"comment": "Something", "disabled": true}`
+and **--json-comments** is provided, the 'comment' field will contain "Something"
+and the 'disabled' field will be set to the database's native true value.
+
+WARNING: Using JSON comments to disable records means that the zone in PowerDNS
+is different from the one served by BIND, as BIND does not handle the disabled
+status in the comment.
+
+# SEE ALSO
+pdns_server(1)
--- /dev/null
+# Backend writers' guide
+PowerDNS backends are implemented via a simple yet powerful C++ interface.
+If your needs are not met by the PipeBackend, you may want to write your
+own. Before doing any PowerDNS development, please visit [the
+wiki](http://wiki.powerdns.com). Also please read [this blog
+post](http://blog.powerdns.com/2015/06/23/what-is-a-powerdns-backend-and-how-do-i-make-it-send-an-nxdomain/)
+which has a FAQ and several pictures that help explain what a backend is.
+
+A backend contains zero DNS logic. It need not look for CNAMEs, it need not return NS records unless explicitly asked for, etcetera. All DNS logic is contained within PowerDNS itself - backends should simply return records matching the description asked for.
+
+**Warning**: However, please note that your backend can get queries in aNy CAsE! If your database is case sensitive, like most are (with the notable exception of MySQL), you must make sure that you do find answers which differ only in case.
+
+**Warning**: PowerDNS may instantiate multiple instances of your backend, or destroy existing copies and instantiate new ones. Backend code should therefore be thread-safe with respect to its static data. Additionally, it is wise if instantiation is a fast operation, with the possible exception of the first construction.
+
+## Notes
+Besides regular query types, the DNS also knows the 'ANY' query type. When a server receives a question for this ANY type, it should reply with all record types available.
+
+Backends should therefore implement being able to answer 'ANY' queries in this way, and supply all record types they have when they receive such an 'ANY' query. This is reflected in the sample script above, which for every qtype answers if the type matches, or if the query is for 'ANY'.
+
+However, since backends need to implement the ANY query anyhow, PowerDNS makes use of this. Since almost all DNS queries internally need to be translated first into a CNAME query and then into the actual query, possibly followed by a SOA or NS query (this is how DNS works internally), it makes sense for PowerDNS to speed this up, and just ask the ANY query of a backend.
+
+When it has done so, it gets the data about SOA, CNAME and NS records in one go. This speeds things up tremendously.
+
+The upshot of the above is that for any backend, including the PIPE backend, implementing the ANY query is NOT optional. And in fact, a backend may see almost exclusively ANY queries. This is not a bug.
+
+## Simple read-only native backends
+Implementing a backend consists of inheriting from the DNSBackend class. For read-only backends, which do not support slave operation, only the following methods are relevant:
+
+```
+ class DNSBackend
+ {
+ public:
+
+ virtual void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0;
+ virtual bool list(const string &target, int domain_id)=0;
+ virtual bool get(DNSResourceRecord &r)=0;
+ virtual bool getSOA(const string &name, SOAData &soadata, DNSPacket *p=0);
+ };
+```
+
+Note that the first three methods must be implemented. `getSOA()` has a useful default implementation.
+
+The semantics are simple. Each instance of your class only handles one (1) query at a time. There is no need for locking as PowerDNS guarantees that your backend will never be called reentrantly.
+
+**Note**: Queries for wildcard names should be answered literally, without expansion. So, if a backend gets a question for "*.powerdns.com", it should only answer with data if there is an actual "*.powerdns.com" name
+
+Some examples, a more formal specification is down below. A normal lookup starts like this:
+
+```
+ YourBackend yb;
+ yb.lookup(QType::CNAME,"www.powerdns.com");
+```
+
+Your class should now do everything to start this query. Perform as much preparation as possible - handling errors at this stage is better for PowerDNS than doing so later on. A real error should be reported by throwing an exception.
+
+PowerDNS will then call the `get()` method to get `DNSResourceRecord`s back. The following code illustrates a typical query:
+
+```
+ yb.lookup(QType::CNAME,"www.powerdns.com");
+
+ DNSResourceRecord rr;
+ while(yb.get(rr))
+ cout<<"Found cname pointing to '"+rr.content+"'"<<endl;
+ }
+```
+
+Each zone starts with a Start of Authority (SOA) record. This record is special so many backends will choose to implement it specially. The default `getSOA()` method performs a regular lookup on your backend to figure out the SOA, so if you have no special treatment for SOA records, where is no need to implement your own `getSOA()`.
+
+Besides direct queries, PowerDNS also needs to be able to list a zone, to do zone transfers for example. Each zone has an id which should be unique within the backend. To list all records belonging to a zone id, the `list()` method is used. Conveniently, the domain\_id is also available in the `SOAData` structure.
+
+The following lists the contents of a zone called "powerdns.com".
+
+```
+ SOAData sd;
+ if(!yb.getSOA("powerdns.com",sd)) // are we authoritative over powerdns.com?
+ return RCode::NotAuth; // no
+
+ yb.list(sd.domain_id);
+ while(yb.get(rr))
+ cout<<rr.qname<<"\t IN "<<rr.qtype.getName()<<"\t"<<rr.content<<endl;
+```
+
+## A sample minimal backend
+
+This backend only knows about the host "random.powerdns.com", and furthermore, only about its A record:
+
+```
+/* FIRST PART */
+class RandomBackend : public DNSBackend
+{
+public:
+ bool list(const string &target, int id)
+ {
+ return false; // we don't support AXFR
+ }
+
+ void lookup(const QType &type, const string &qdomain, DNSPacket *p, int zoneId)
+ {
+ if(type.getCode()!=QType::A || qdomain!="random.powerdns.com") // we only know about random.powerdns.com A
+ d_answer=""; // no answer
+ else {
+ ostringstream os;
+ os<<random()%256<<"."<<random()%256<<"."<<random()%256<<"."<<random()%256;
+ d_answer=os.str(); // our random ip address
+ }
+ }
+
+ bool get(DNSResourceRecord &rr)
+ {
+ if(!d_answer.empty()) {
+ rr.qname="random.powerdns.com"; // fill in details
+ rr.qtype=QType::A; // A record
+ rr.ttl=86400; // 1 day
+ rr.content=d_answer;
+
+ d_answer=""; // this was the last answer
+
+ return true;
+ }
+ return false; // no more data
+ }
+
+private:
+ string d_answer;
+};
+
+/* SECOND PART */
+
+class RandomFactory : public BackendFactory
+{
+public:
+ RandomFactory() : BackendFactory("random") {}
+
+ DNSBackend *make(const string &suffix)
+ {
+ return new RandomBackend();
+ }
+};
+
+/* THIRD PART */
+
+class RandomLoader
+{
+public:
+ RandomLoader()
+ {
+ BackendMakers().report(new RandomFactory);
+ L << Logger::Info << "[randombackend] This is the random backend version " VERSION " reporting" << endl;
+ }
+};
+
+static RandomLoader randomloader;
+```
+
+This simple backend can be used as an 'overlay'. In other words, it only knows about a single record, another loaded backend would have to know about the SOA and NS records and such. But nothing prevents us from loading it without another backend.
+
+The first part of the code contains the actual logic and should be pretty straightforward. The second part is a boilerplate 'factory' class which PowerDNS calls to create randombackend instances. Note that a 'suffix' parameter is passed. Real life backends also declare parameters for the configuration file; these get the 'suffix' appended to them. Note that the "random" in the constructor denotes the name by which the backend will be known.
+
+The third part registers the RandomFactory with PowerDNS. This is a simple C++ trick which makes sure that this function is called on execution of the binary or when loading the dynamic module.
+
+Please note that a RandomBackend is actually in most PowerDNS releases. By default it lives on random.example.com, but you can change that by setting [`random-hostname`](../authoritative/backend-random.md#random-hostname).
+
+**Note**: this simple backend neglects to handle case properly!
+
+## Interface definition
+
+### Classes
+
+#### DNSResourceRecord
+| | |
+|:--|:--|
+|QType qtype|QType of this record|
+|string qname|name of this record|
+|string content|ASCII representation of right hand side|
+|uint32\_t ttl|Time To Live of this record|
+|int domain\_id| ID of the domain this record belongs to|
+|time\_t last\_modified| If unzero, last time\_t this record was changed|
+|bool auth| Used for DNSSEC operations. See [DNSSEC](../authoritative/dnssec.md) and more specifically the [Migration](../authoritative/dnssec.md#migration) section. It is also useful to check out the `rectifyZone()` in pdnsutil.cc|
+|bool disabled|If set, this record is not to be served to DNS clients. Backends should not make these records available to PowerDNS unless indicated otherwise.|
+
+#### SOAData
+| | |
+|:--|:--|
+|string nameserver|Name of the master nameserver of this zone|
+|string hostmaster|Hostmaster of this domain. May contain an @|
+|u\_int32\_t serial|Serial number of this zone|
+|u\_int32\_t refresh|How often this zone should be refreshed|
+|u\_int32\_t retry|How often a failed zone pull should be retried.|
+|u\_int32\_t expire|If zone pulls failed for this long, retire records|
+|u\_int32\_t default\_ttl|Difficult|
+|int domain\_id|The ID of the domain within this backend. Must be filled!|
+|DNSBackend *db|Pointer to the backend that feels authoritative for a domain and can act as a slave|
+
+### Methods
+#### `void lookup(const QType &qtype, const string &qdomain, DNSPacket *pkt=0, int zoneId=-1)`
+This function is used to initiate a straight lookup for a record of name 'qdomain' and type 'qtype'. A QType can be converted into an integer by invoking its `getCode()` method and into a string with the `getCode()`.
+
+The original question may or may not be passed in the pointer pkt. If it is, you can retrieve information about who asked the question with the `pkt->getRemote()` method.
+
+Note that **qdomain** can be of any case and that your backend should make sure it is in effect case insensitive. Furthermore, the case of the original question should be retained in answers returned by `get()`!
+
+Finally, the domain\_id might also be passed indicating that only answers from the indicated zone need apply. This can both be used as a restriction or as a possible speedup, hinting your backend where the answer might be found.
+
+If initiated successfully, as indicated by returning **true**, answers should be made available over the `get()` method.
+
+Should throw an PDNSException if an error occurred accessing the database. Returning otherwise indicates that the query was started successfully. If it is known that no data is available, no exception should be thrown! An exception indicates that the backend considers itself broken - not that no answers are available for a question.
+
+It is legal to return here, and have the first call to `get()` return false. This is interpreted as 'no data'.
+
+#### `bool list(int domain_id, bool include_disabled=false)`
+Initiates a list of the indicated domain. Records should then be made available via the `get()` method. Need not include the SOA record. If it is, PowerDNS will not get confused. If include\_disabled is given as true, records that are configured but should not be served to DNS clients must also be made available.
+
+Should return false if the backend does not consider itself authoritative for this zone. Should throw an PDNSException if an error occurred accessing the database. Returning true indicates that data is or should be available.
+
+#### `bool get(DNSResourceRecord &rr)`
+Request a DNSResourceRecord from a query started by `get()` of `list()`. If this functions returns **true**, **rr** has been filled with data. When it returns false, no more data is available, and **rr** does not contain new data. A backend should make sure that it either fills out all fields of the DNSResourceRecord or resets them to their default values.
+
+The qname field of the DNSResourceRecord should be filled out with the exact `qdomain` passed to lookup, preserving its case. So if a query for 'CaSe.yourdomain.com' comes in and your database contains data for 'case.yourdomain.com', the qname field of rr should contain 'CaSe.yourdomain.com'!
+
+Should throw an PDNSException in case a database error occurred.
+
+#### `bool getSOA(const string &name, SOAData &soadata)`
+If the backend considers itself authoritative over domain `name`, this method should fill out the passed **SOAData** structure and return a positive number. If the backend is functioning correctly, but does not consider itself authoritative, it should return 0. In case of errors, an PDNSException should be thrown.
+
+## Reporting errors
+To report errors, the Logger class is available which works mostly like an iostream. Example usage is as shown above in the RandomBackend. Note that it is very important that each line is ended with **endl** as your message won't be visible otherwise.
+
+To indicate the importance of an error, the standard syslog errorlevels are available. They can be set by outputting `Logger::Critical`, `Logger::Error`, `Logger::Warning`, `Logger::Notice`, `Logger::Info` or `Logger::Debug` to `L`, in descending order of graveness.
+
+## Declaring and reading configuration details
+It is highly likely that a backend needs configuration details. On launch, these parameters need to be declared with PowerDNS so it knows it should accept them in the configuration file and on the command line. Furthermore, they will be listed in the output of `--help`.
+
+Declaring arguments is done by implementing the member function `declareArguments()` in the factory class of your backend. PowerDNS will call this method after launching the backend.
+
+In the `declareArguments()` method, the function `declare()` is available. The exact definitions:
+
+### `void declareArguments(const string &suffix="")`
+This method is called to allow a backend to register configurable parameters. The suffix is the sub-name of this module. There is no need to touch this suffix, just pass it on to the declare method.
+
+### `void declare(const string &suffix, const string ¶m, const string &explanation, const string &value)`
+The suffix is passed to your method, and can be passed on to declare. **param** is the name of your parameter. **explanation** is what will appear in the output of --help. Furthermore, a default value can be supplied in the **value** parameter.
+
+A sample implementation:
+
+```
+ void declareArguments(const string &suffix)
+ {
+ declare(suffix,"dbname","Pdns backend database name to connect to","powerdns");
+ declare(suffix,"user","Pdns backend user to connect as","powerdns");
+ declare(suffix,"host","Pdns backend host to connect to","");
+ declare(suffix,"password","Pdns backend password to connect with","");
+ }
+```
+
+After the arguments have been declared, they can be accessed from your backend using the `mustDo()`, `getArg()` and `getArgAsNum()` methods. The are defined as follows in the DNSBackend class:
+
+### `void setArgPrefix(const string &prefix)`
+Must be called before any of the other accessing functions are used. Typical usage is '`setArgPrefix("mybackend"+suffix)`' in the constructor of a backend.
+
+### `bool mustDo(const string &key)`
+Returns true if the variable `key` is set to anything but 'no'.
+
+### `const string& getArg(const string &key)`
+Returns the exact value of a parameter.
+
+### `int getArgAsNum(const string &key)`
+Returns the numerical value of a parameter. Uses `atoi()` internally
+
+Sample usage from the BindBackend: getting the 'check-interval' setting:
+
+```
+if(!safeGetBBDomainInfo(i->name, &bbd)) {
+ bbd.d_id=domain_id++;
+ bbd.setCheckInterval(getArgAsNum("check-interval"));
+ bbd.d_lastnotified=0;
+ bbd.d_loaded=false;
+}
+```
+
+## Read/write slave-capable backends
+The backends above are 'natively capable' in that they contain all data relevant for a domain and do not pull in data from other nameservers. To enable storage of information, a backend must be able to do more.
+
+Before diving into the details of the implementation some theory is in order. Slave domains are pulled from the master. PowerDNS needs to know for which domains it is to be a slave, and for each slave domain, what the IP address of the master is.
+
+A slave zone is pulled from a master, after which it is 'fresh', but this is only temporary. In the SOA record of a zone there is a field which specifies the 'refresh' interval. After that interval has elapsed, the slave nameserver needs to check at the master ff the serial number there is higher than what is stored in the backend locally.
+
+If this is the case, PowerDNS dubs the domain 'stale', and schedules a transfer of data from the remote. This transfer remains scheduled until the serial numbers remote and locally are identical again.
+
+This theory is implemented by the `getUnfreshSlaveInfos` method, which is called on all backends periodically. This method fills a vector of **SlaveDomain**s with domains that are unfresh and possibly stale.
+
+PowerDNS then retrieves the SOA of those domains remotely and locally and creates a list of stale domains. For each of these domains, PowerDNS starts a zone transfer to resynchronise. Because zone transfers can fail, it is important that the interface to the backend allows for transaction semantics because a zone might otherwise be left in a halfway updated situation.
+
+The following excerpt from the DNSBackend shows the relevant functions:
+
+```
+ class DNSBackend {
+ public:
+ /* ... */
+ virtual bool getDomainInfo(const string &domain, DomainInfo &di);
+ virtual bool isMaster(const string &name, const string &ip);
+ virtual bool startTransaction(const string &qname, int id);
+ virtual bool commitTransaction();
+ virtual bool abortTransaction();
+ virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername=0);
+ virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+ virtual void setFresh(uint32_t id);
+ /* ... */
+ }
+```
+
+The mentioned DomainInfo struct looks like this:
+
+### DomainInfo struct
+| | |
+|:--|:--|
+|uint32\_t id|ID of this zone within this backend|
+|string master|IP address of the master of this domain, if any|
+|uint32\_t serial|Serial number of this zone|
+|uint32\_t notified\_serial|Last serial number of this zone that slaves have seen|
+|time\_t last\_check|Last time this zone was checked over at the master for changes|
+|enum {Master,Slave,Native} kind|Type of zone|
+|DNSBackend *backend|Pointer to the backend that feels authoritative for a domain and can act as a slave|
+
+These functions all have a default implementation that returns false - which explains that these methods can be omitted in simple backends. Furthermore, unlike with simple backends, a slave capable backend must make sure that the 'DNSBackend *db' field of the SOAData record is filled out correctly - it is used to determine which backend will house this zone.
+
+### `bool isMaster(const string &name, const string &ip)`
+If a backend considers itself a slave for the domain **name** and if the IP address in **ip** is indeed a master, it should return true. False otherwise. This is a first line of checks to guard against reloading a domain unnecessarily.
+
+### `void getUnfreshSlaveInfos(vector\<DomainInfo\>* domains)`
+When called, the backend should examine its list of slave domains and add any unfresh ones to the domains vector.
+
+### `bool getDomainInfo(const string &name, DomainInfo & di)`
+This is like `getUnfreshSlaveInfos`, but for a specific domain. If the backend considers itself authoritative for the named zone, `di` should be filled out, and 'true' be returned. Otherwise return false.
+
+### `bool startTransaction(const string &qname, int id)`
+When called, the backend should start a transaction that can be committed or rolled back atomically later on. In SQL terms, this function should **BEGIN** a transaction and **DELETE** all records.
+
+### `bool feedRecord(const DNSResourceRecord &rr, string *ordername)`
+Insert this record.
+
+### `bool commitTransaction()`
+Make the changes effective. In SQL terms, execute **COMMIT**.
+
+### `bool abortTransaction()`
+Abort changes. In SQL terms, execute **ABORT**.
+
+### `bool setFresh()`
+Indicate that a domain has either been updated or refreshed without the need for a retransfer. This causes the domain to vanish from the vector modified by `getUnfreshSlaveInfos()`.
+
+PowerDNS will always call `startTransaction()` before making calls to `feedRecord()`. Although it is likely that `abortTransaction()` will be called in case of problems, backends should also be prepared to abort from their destructor.
+
+The actual code in PowerDNS is currently (1.99.9):
+
+```
+ Resolver resolver;
+ resolver.axfr(remote,domain.c_str());
+
+ db->startTransaction(domain, domain_id);
+ L<<Logger::Error<<"AXFR started for '"<<domain<<"'"<<endl;
+ Resolver::res_t recs;
+
+ while(resolver.axfrChunk(recs)) {
+ for(Resolver::res_t::const_iterator i=recs.begin();i!=recs.end();++i) {
+ db->feedRecord(*i);
+ }
+ }
+ db->commitTransaction();
+ db->setFresh(domain_id);
+ L<<Logger::Error<<"AXFR done for '"<<domain<<"'"<<endl;
+```
+
+## Supermaster/Superslave capability
+
+A backend that wants to act as a 'superslave' for a master should implement the following method:
+
+```
+ class DNSBackend
+ {
+ virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *account, DNSBackend **db)
+ };
+```
+
+This function gets called with the IP address of the potential supermaster, the domain it is sending a notification for and the set of NS records for this domain at that IP address.
+
+Using the supplied data, the backend needs to determine if this is a bonafide 'supernotification' which should be honoured. If it decides that it should, the supplied pointer to 'account' needs to be filled with the configured name of the supermaster (if accounting is desired), and the db needs to be filled with a pointer to your backend.
+
+Supermaster/superslave is a complicated concept, if this is all unclear see the [Supermaster and Superslave](../authoritative/modes-of-operation.md#supermaster-automatic-provisioning-of-slaves) documentation.
+
+## Read/write master-capable backends
+In order to be a useful master for a domain, notifies must be sent out whenever a domain is changed. Periodically, PowerDNS queries backends for domains that may have changed, and sends out notifications for slave nameservers.
+
+In order to do so, PowerDNS calls the `getUpdatedMasters()` method. Like the `getUnfreshSlaveInfos()` function mentioned above, this should add changed domain names to the vector passed.
+
+The following excerpt from the DNSBackend shows the relevant functions:
+
+```
+ class DNSBackend {
+ public:
+ /* ... */
+ virtual void getUpdatedMasters(vector<DomainInfo>* domains);
+ virtual void setNotified(uint32_t id, uint32_t serial);
+ /* ... */
+ }
+```
+
+These functions all have a default implementation that returns false - which explains that these methods can be omitted in simple backends. Furthermore, unlike with simple backends, a slave capable backend must make sure that the 'DNSBackend *db' field of the SOAData record is filled out correctly - it is used to determine which backend will house this zone.
+
+### `void getUpdatedMasters(vector<DomainInfo>* domains)`
+When called, the backend should examine its list of master domains and add any changed ones to the DomainInfo vector
+
+### `bool setNotified(uint32_t domain_id, uint32_t serial)`
+Indicate that notifications have been queued for this domain and that it need not be considered 'updated' anymore
+
+## DNS update support
+To make your backend DNS update compatible, it needs to implement a number of new functions and functions already used for slave-operation. The new functions are not DNS update specific and might be used for other update/remove functionality at a later stage.
+
+```
+class DNSBackend {
+public:
+ /* ... */
+ virtual bool startTransaction(const string &qname, int id);
+ virtual bool commitTransaction();
+ virtual bool abortTransaction();
+ virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername);
+ virtual bool replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
+ virtual bool listSubZone(const string &zone, int domain_id);
+ /* ... */
+}
+```
+
+### `virtual bool startTransaction(const string &qname, int id)`
+See [above](#bool-starttransactionconst-string-qname-int-id). Please note that this function now receives a negative number (-1), which indicates that the current zone data should NOT be deleted.
+
+### `virtual bool commitTransaction()`
+See [above](#bool-committransaction)
+
+### `virtual bool abortTransaction()`
+See [above](#bool-aborttransaction). Method is called when an exception is received.
+
+### `virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername)`
+See [above](#bool-feedrecordconst-dnsresourcerecord-rr-string-ordername). Please keep in mind that the zone is not empty because `startTransaction()` was called different.
+
+### `virtual bool listSubZone(const string &name, int domain\_id)`
+This method is needed for rectification of a zone after NS-records have been added. For DNSSEC, we need to know which records are below the currently added record. `listSubZone()` is used like `list()` which means PowerDNS will call `get()` after this method. The default SQL query looks something like this:
+
+```
+// First %s is 'sub.zone.com', second %s is '*.sub.zone.com'
+select content,ttl,prio,type,domain_id,name from records where (name='%s' OR name like '%s') and domain_id=%d
+```
+
+The method is not only used when adding records, but also to correct ENT-records in powerdns. Make sure it returns every record in the tree below the given record.
+
+### `virtual bool replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)`
+This method should remove all the records with `qname` of type `qt`. `qt` might also be ANY, which means all the records with that `qname` need to be removed. After removal, the records in `rrset` must be added to the zone. `rrset` can be empty in which case the method is used to remove a RRset.
+
+# DNS update support
+To make your backend DNS update compatible, it needs to implement a number of new functions and functions already used for slave-operation. The new functions are not DNS update specific and might be used for other update/remove functionality at a later stage.
+
+```
+class DNSBackend {
+public:
+ /* ... */
+ virtual bool startTransaction(const string &qname, int id);
+ virtual bool commitTransaction();
+ virtual bool abortTransaction();
+ virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername);
+ virtual bool replaceRRSet(uint32_t domain_id, const string& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
+ virtual bool listSubZone(const string &zone, int domain_id);
+ /* ... */
+}
+```
+
+## `virtual bool startTransaction(const string &qname, int id);`
+See [Read/write slave-capable backends](#read-write-slave-capable-backends). Please note that this function now receives a negative number (-1), which indicates that the current zone data should NOT be deleted.
+
+## `virtual bool commitTransaction();`
+See [Read/write slave-capable backends](#read-write-slave-capable-backends).
+
+## `virtual bool abortTransaction();`
+See [Read/write slave-capable backends](#read-write-slave-capable-backends). Method is called when an exception is received.
+
+## `virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername);`
+See [Read/write slave-capable backends](#read-write-slave-capable-backends). Please keep in mind that the zone is not empty because `startTransaction()` was called different.
+
+virtual bool listSubZone(const string &name, int domain\_id);
+This method is needed for rectification of a zone after NS-records have been added. For DNSSEC, we need to know which records are below the currently added record. `listSubZone()` is used like `list()` which means PowerDNS will call `get()` after this method. The default SQL query looks something like this:
+
+```
+// First %s is 'sub.zone.com', second %s is '*.sub.zone.com'
+select content,ttl,prio,type,domain_id,name from records where (name='%s' OR name like '%s') and domain_id=%d
+```
+
+The method is not only used when adding records, but also to correct ENT-records in powerdns. Make sure it returns every record in the tree below the given record.
+
+## virtual bool replaceRRSet(uint32\_t domain\_id, const string& qname, const QType& qt, const vector\<DNSResourceRecord\>& rrset);
+
+This method should remove all the records with `qname` of type `qt`. `qt` might also be ANY, which means all the records with that `qname` need to be removed. After removal, the records in `rrset` must be added to the zone. `rrset` can be empty in which case the method is used to remove a RRset.
--- /dev/null
+# Compiling PowerDNS
+PowerDNS can be compiled with modules built in, or with modules designed to be
+loaded at runtime. All that is configured before compiling using the well known
+autoconf/automake system.
+
+PowerDNS requires 'Boost' to compile, it is available for most operating
+systems. Otherwise, see [the Boost website](http://www.boost.org).
+
+To compile in modules, specify them as `--with-modules='mod1 mod2 mod3'`,
+substituting the desired module names. Each backend has a module name that you
+look up in this [table](../authoritative/index.md#backend-capibilities).
+
+To compile a module for inclusion at runtime, which is great if you are a unix
+vendor, use `--with-dynmodules='mod1 mod2 mod3'`. These modules then end up as
+.so files in the compiled libdir.
+
+By default, the [bind](../authoritative/backend-bind.md), [mysql](../authoritative/backend-generic-mysql.md)
+and [random](../authoritative/backend-random.md) are compiled into the binary.
+The [pipe](../authoritative/backend-pipe.md) is, by default, compiled as a runtime
+loadable module.
+
+## Getting the sources
+There are 3 ways of getting the source. If you want the bleeding edge, you can
+clone the repository at [GitHub](https://github.com/PowerDNS/pdns) and run
+`./bootstrap` in the clone.
+
+You can also download snapshot tarballs generated by Jenkins and can be found
+[here](https://autotest.powerdns.com/).
+
+You can also download releases on the [website](https://downloads.powerdns.com/releases/).
+These releases are PGP-signed with key-id [FBAE 0323 821C 7706 A5CA 151B DCF5
+13FA 7EED 19F3](https://pgp.mit.edu/pks/lookup?op=get&search=0xDCF513FA7EED19F3),
+[1628 90D0 689D D12D D33E 4696 1C5E
+E990 D2E7 1575](https://pgp.mit.edu/pks/lookup?op=get&search=0x1C5EE990D2E71575)
+or [B76C D467 1C09 68BA A87D E61C 5E50 715B F2FF E1A7](https://pgp.mit.edu/pks/lookup?op=get&search=0x5E50715BF2FFE1A7).
+
+## OS specific gotcha's
+### AIX
+It is unknown if PowerDNS compiles on AIX.
+
+### FreeBSD
+Works fine, but use gmake.
+
+The FreeBSD Boost include files are installed in `/usr/local/include`, so prefix
+`CXXFLAGS=-I/usr/local/include` to your `./configure` invocation.
+
+### Linux
+Linux is probably the best supported platform as most of the main coders are
+Linux users.
+
+### Mac OS X
+The [installation from Homebrew](../authoritative/installation.md#mac-os-x)
+for the authoritative server should work, event though not all commits are
+tested on OS X.
+
+The recursor has been reported to crash for some OS X users.
+
+### OpenBSD 5.8
+Compiles, but use gmake and g++-4.9.3 or higher.
+
+### Solaris
+Solaris 8 and 9 work fine. The 'Sunpro' compiler has not been tried but is
+reported to be lacking large parts of the Standard Template Library, which
+PowerDNS relies on heavily. Use gcc and gmake (if available). Regular Solaris
+make has some issues with some PowerDNS Makefile constructs.
+
+When compiling, make sure that you have `/usr/ccs/bin` in your path.
+Furthermore, with some versions of MySQL, you may have to add `LDFLAGS=-lz`
+before `./configure`.
+
+### OpenIndiana
+Compiles on OpenIndiana Hipster with `developer/gcc-49`. Other required packages
+are:
+
+ * bison
+ * boost
+ * developer/gcc-49
+ * flex
+ * libtool
+ * pkg-config
+ * system/header
--- /dev/null
+# Cryptographic software and export control
+In certain legal climates, PowerDNS might potentially require an export control status, particularly since PowerDNS software contains cryptographic primitives.
+
+PowerDNS does not itself implement any cryptographic algorithms but relies on third party implementations of AES, RSA, ECDSA, GOST, MD5 and various SHA-based hashing algorithms.
+
+Furthermore, RSA, MD5 and the SHA-based algorithms are supplied as a copy of [mbed TLS](https://tls.mbed.org/).
+
+Starting with 4.0.0, PowerDNS will link in hash and cryptographic primitives from
+the open source [OpenSSL](https://openssl.org/) library.
+
+Optionally, PowerDNS can link in a copy of the open source [Botan](http://botan.randombits.org/) cryptographic library.
+
+Optionally, PowerDNS can link in a copy of the open source [Sodium](https://libsodium.org/) library.
+
+## Specific United States Export Control Notes
+
+PowerDNS is not "US Origin" software. For re-export, like most open source,
+publicly available "mass market" projects, PowerDNS is considered to be
+governed by section 740.13(e) of the US EAR, "Unrestricted encryption source
+code", under which PowerDNS source code would be considered re-exportable
+from the US without an export license under License Exception TSU
+(Technology and Software - Unrestricted).
+
+Like most open source projects containing some encryption, the ECCN that
+best fits PowerDNS software is 5D002.
+
+The official link to the publicly available source code is
+<http://downloads.powerdns.com/releases>.
+
+If absolute certainty is required, we recommend consulting an expert in US
+Export Control, or asking the BIS for confirmation.
--- /dev/null
+# Documentation details
+The PowerDNS documentation started life as SGML DocBook, and was later converted (with great pain) to XML DocBook. Late 2014,
+Pieter Lexis contributed a Markdown conversion, which is the basis of the current documentation.
+
+If you note an issue with the new documentation, please open a ticket on
+[GitHub](https://github.com/powerdns/pdns/issues) and tell us about it. Or, even
+better, fork our repo, and edit the files in docs/markdown to improve things.
+
+If your change is simple (say, a typo or a new paragraph), you can do all this
+entirely from GitHub. Simply fork PowerDNS, find the Markdown file you want to change,
+edit in place, commit, and create a pull request.
+
+## Building and testing
+It's recommended to use a [virtualenv](https://virtualenv.pypa.io/en/latest/)
+with the required packages to build the documentation.
+[Virtualenvwrapper](http://virtualenvwrapper.readthedocs.org/en/latest/) can be
+used to easily create and use a virtualenv.
+
+Once you're in a virtualenv, `pip install mkdocs==0.14 pandocfilters==1.2.3 click==5.1 LinkChecker==9.3`.
+
+To test-build the documentation, `make html/index.html` in the docs
+directory will build the documentation into `html/`.
+
+To test your changes live, use `cd docs/html && mkdocs serve && python -m SimpleHTTPServer`,
+and the new version of your documentation will appear on port 8000 of your machine.
--- /dev/null
+# Bind zone file backend
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Experimental|
+|Autoserial|No|
+|DNSSEC|Yes|
+|Disabled data|No|
+|Comments|No|
+|Module name|bind|
+|Launch|bind|
+
+The BindBackend started life as a demonstration of the versatility of PowerDNS but quickly gained in importance when there appeared to be demand for a Bind 'work-alike'.
+
+The BindBackend parses a Bind-style `named.conf` and extracts information about zones from it. It makes no attempt to honour other configuration flags, which you should configure (when available) using the PowerDNS native configuration.
+
+## Configuration Parameters
+### `bind-config`
+Location of the Bind configuration file to parse.
+
+### `bind-check-interval`
+How often to check for zone changes. See ['Operation'](#operation) section.
+
+### `bind-dnssec-db`
+Filename to store and access our DNSSEC metadatabase, empty for none.
+To slave DNSSEC-enabled domains (where the RRSIGS are in the AXFR), a
+`bind-dnssec-db` is required. This is because the [PRESIGNED](domainmetadata.md#presigned)
+domain metadata is set during the zonetransfer.
+
+### `bind-hybrid`
+Store DNSSEC keys and metadata storage in an other backend. See the
+[hybrid BIND-mode operation](dnssec.md#hybrid-bind-mode-operation)
+
+### `bind-ignore-broken-records`
+Setting this option to `yes` makes PowerDNS ignore out of zone records when
+loading zone files.
+
+## Operation
+On launch, the BindBackend first parses the `named.conf` to determine which zones
+need to be loaded. These will then be parsed and made available for serving, as
+they are parsed. So a `named.conf` with 100.000 zones may take 20 seconds to load,
+but after 10 seconds, 50.000 zones will already be available. While a domain is
+being loaded, it is not yet available, to prevent incomplete answers.
+
+Reloading is currently done only when a request for a zone comes in, and then
+only after [`bind-check-interval`](#bind-check-interval) seconds have passed after
+the last check. If a change occurred, access to the zone is disabled, the file
+is reloaded, access is restored, and the question is answered. For regular zones,
+reloading is fast enough to answer the question which lead to the reload within
+the DNS timeout.
+
+If [`bind-check-interval`](#bind-check-interval) is specified as zero, no checks
+will be performed until the `pdns_control reload` is given.
+
+## pdns\_control commands
+### `bind-add-zone <domain> <filename>`
+Add zone `domain` from `filename` to PowerDNS's bind backend. Zone will be loaded at
+first request. **Note**: this does not add the zone to the [`bind-config`](#bind-config)
+file.
+
+### `bind-domain-status <domain> [domain]`
+Output status of domain or domains. Can be one of `seen in named.conf, not parsed`,
+`parsed successfully at <time>` or `error parsing at line ... at <time>`.
+
+### `bind-list-rejects`
+Lists all zones that have problems, and what those problems are.
+
+### `bind-reload-now <domain>`
+Reloads a zone from disk NOW, reporting back results.
+
+### `rediscover`
+Reread the bind configuration file (`named.conf`). If parsing fails, the old
+configuration remains in force and `pdns_control` reports the error. Any newly
+discovered domains are read, discarded domains are removed from memory.
+
+### `reload`
+All zones with a changed timestamp are reloaded at the next incoming query for them.
+
+## Performance
+The BindBackend does not benefit from the packet cache as it is fast enough on
+its own. Furthermore, on most systems, there will be no benefit in using multiple
+CPUs for the packetcache, so a noticeable speedup can be attained by specifying
+[`distributor-threads`](settings.md#distributor-threads)`=1` in `pdns.conf`.
+
+## Master/slave configuration
+
+### Master
+Works as expected. At startup, no notification storm is performed as this is
+generally not useful. Perhaps in the future the Bind Backend will attempt to
+store zone metadata in the zone, allowing it to determine if a zone has changed
+its serial since the last time notifications were sent out.
+
+Changes which are discovered when reloading zones do lead to notifications however.
+
+### Slave
+Also works as expected. The Bind backend expects to be able to write to a
+directory where a slave domain lives. The incoming zone is stored as
+'zonename.RANDOM' and atomically renamed if it is retrieved successfully, and
+parsed only then.
+
+In the future, this may be improved so the old zone remains available should
+parsing fail.
--- /dev/null
+This page contains some information about deprecated backends.
+
+# LMDB (high performance) backend
+**Note**: This backend was removed in version 4.0.0.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|DNSSEC|No|
+|Module name|lmdb|
+|Launch|lmdb|
+
+Based on the [LMDB key-value database](http://symas.com/mdb/), the LMDB backend turns powerdns into a very high performance and DDOS-resilient authoritative DNS server. Testing on a 32-core server shows the ability to answer up to 400,000 queries per second with instant startup and real-time updates independent of database size.
+
+## Configuration Parameters
+### `lmdb-datapath`
+Location of the database to load
+
+## Operation
+Unlike other backends, LMDB does not require any special configuration. New or updated zones are available the next query after the update transaction is committed. If the underlying database is removed or recreated then the reload command should be sent through to powerdns to get it to close and reopen the database.
+
+## Database Format
+A full example script for generating a database can be found in pdns/modules/lmdbbackend/lmdb-example.pl. Basically the database environment is comprised of three databases to store the data:
+
+### Zone Database
+Each key in the zone database is the reversed lower-cased name of the zone without leading or trailing dots (ie for example.com the key would be moc.elpmaxe).
+
+Each value in the database must contain the following data (tab-separated):
+
+* Zone ID: The Zone's unique integer ID in ASCII (32-bit)
+* TTL: The TTL for the zone's SOA record
+* SOA data: space-separated SOA data eg
+```
+ns.foo.com. hostmaster.foo.com. <serial> <refresh> <retry> <expire> <minimum>
+```
+
+If refresh, retry, expire or minimum are not specified then the powerdns defaults will be used
+
+### Data Database
+This database is required to have been created with the MDB\_DUPSORT flag enabled. It stores the records for each domain. Each key must contain the following data (tab-separated):
+
+* Record name: The reversed lower-cased name of the record and zone without leading or trailing dots
+* Record type: The type of record A, NS, PTR etc. SOA is not allowed as it is automatically created from the zone database records.
+
+The value for each entry must contain the following data (tab-separated). If the length of this record is greater than the LMDB limit of 510 bytes (for DUPSORT databases) an entry of "REF" followed by the tab character and a unique 32-bit ASCII integer which contains a reference into [the section called “extended\_data database”](#extended-data-database).
+
+* Zone ID: The Zone's unique integer ID in ASCII (32-bit)
+* TTL: The TTL for the SOA record
+* Record data: The record's data entry. For MX/SRV records the priority is the first field and space-separated from the rest of the data. Care must be taken to escape the data appropriately for PowerDNS. As in the Pipe backend " and \\ characters are not allowed and any it is advised that any characters outside of ASCII 32-126 are escaped using the \\ character.
+
+### extended\_data database
+If the length of the value that you wish to insert into [the section called “data database”](#data-database) is longer than 510 bytes you need to create the REF entry as described above linked in to this table. The value is a unique 32-bit integer value formatted in ASCII and the value is the exact same format as it would have been in [the section called “data database”](#data-database) but can be however long you require.
+
+### Example database structure
+(as output by the pdns/modules/lmdbbackend/lmdb-example.pl example script and shown by pdns/modules/lmdbbackend/dumpdb.pl)
+
+```
+# perl dumpdb.pl /var/tmp/lmdb zone
+key: moc.elpmaxe; value: 1 300 ns.example.com. hostmaster.example.com. 2012021101 86400 7200 604800 86400
+# perl dumpdb.pl /var/tmp/lmdb data
+key: moc.elpmaxe MX; value: 1 300 10 mail.example.com
+key: moc.elpmaxe NS; value: 1 300 ns.example.com
+key: moc.elpmaxe.tset A; value: 1 300 192.0.2.66
+key: moc.elpmaxe.txet TXT; value: 1 300 test\010123
+key: moc.elpmaxe.txetgnol TXT; value: REF 1
+# perl dumpdb.pl /var/tmp/lmdb extended_data
+key: 1; value: 1 300 AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA
+```
+
+# DB2 Backend
+**Note**: This backend was removed in version 3.5.0.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|Yes|
+|DNSSEC|No|
+|Disabled data|No|
+|Comments|No|
+|Module name|db2
+|Launch name|db2|
+
+PowerDNS is currently ascertaining if this backend can be distributed in binary form without violating IBM DB2 licensing.
+
+## Queries
+The DB2 backend executes the following queries:
+
+### Forward Query
+select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ? and type = ?
+
+### Forward By Zone Query
+select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ? and Type = ? and ZoneId = ?
+
+### Forward Any Query
+select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where Name = ?
+
+### List Query
+select Content, TimeToLive, Priority, Type, ZoneId, 0 as ChangeDate, Name from Records where ZoneId = ?
+
+## Configuration Parameters
+
+### `db2-server`
+Server name to connect to. Defaults to 'powerdns'. Make sure that your nameserver is not needed to resolve an IP address needed to connect as this might lead
+
+### `db2-user`
+Username to connect as. Defaults to 'powerdns'.
+
+### `db2-password`
+Password to connect with. Defaults to 'powerdns'.
+
+# ODBC backend
+**Note**: This backend was removed in version 3.1.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes (experimental)|
+|Slave|Yes (experimental)|
+|Superslave|No|
+|Autoserial|Yes|
+
+The ODBC backend can retrieve zone information from any source that has a ODBC driver available.
+
+**Note** This backend is only available on PowerDNS for Windows.
+
+The ODBC backend needs data in a fixed schema which is the same as the data needed by the MySQL backend. The create statement will resemble this:
+
+```
+ CREATE TABLE records (
+ id int(11) NOT NULL auto_increment,
+ domain_id int(11) default NULL,
+ name varchar(255) default NULL,
+ type varchar(10) default NULL,
+ content varchar(255) default NULL,
+ ttl int(11) default NULL,
+ prio int(11) default NULL,
+ change_date int(11) default NULL,
+ PRIMARY KEY (id),
+ KEY name_index(name),
+ KEY nametype_index(name,type),
+ KEY domainid_index(domain_id)
+ );
+```
+
+To use the ODBC backend an ODBC source has to be created, to do this see the section Installing PowerDNS on Microsoft Windows, not included in the documentation as installation on Windows is not supported.
+
+## Configuration Parameters
+### `odbc-datasource`
+Specifies the name of the data source to use.
+
+### `odbc-user`
+Specifies the username that has to be used to log into the data source.
+
+### `odbc-pass`
+Specifies the user's password.
+
+### `odbc-table`
+Specifies the name of the table containing the zone information.
+
+The ODBC backend has been tested with Microsoft Access, MySQL (via MyODBC) and Microsoft SQLServer. As the SQL statements used are very basic, it is expected to work with many ODBC drivers.
+
+# XDB Backend
+No longer part of PowerDNS.
--- /dev/null
+# Generic MySQL backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes (v3.1 and up)|
+|Case|All lower|
+|DNSSEC|Yes (set `gmysql-dnssec`)|
+|Disabled data|Yes (v3.4.0 and up)|
+|Comments|Yes (v3.4.0 and up)|
+|Module name | gmysql|
+|Launch name| gmysql|
+
+**warning**: If using MySQL with 'slave' support enabled in PowerDNS you **must**
+run MySQL with a table engine that supports transactions.
+In practice, great results are achieved with the 'InnoDB' tables. PowerDNS will
+silently function with non-transaction aware MySQLs but at one point this is
+going to harm your database, for example when an incoming zone transfer fails.
+
+The default schema is included at the bottom of this page. [`zone2sql`](migration.md#zone2sql)
+with the `--gmysql` flag also assumes this layout is in place. For full migration
+notes, please see [Migration](migration.md). This schema contains all elements
+needed for master, slave and superslave operation.
+
+When using the InnoDB storage engine, we suggest adding the following lines to
+the 'create table records' command above:
+
+```
+CONSTRAINT `records_ibfk_1` FOREIGN KEY (`domain_id`) REFERENCES `domains`
+(`id`) ON DELETE CASCADE
+```
+
+Or, if you have already created the tables, execute:
+
+```
+ALTER TABLE `records` ADD CONSTRAINT `records_ibfk_1` FOREIGN KEY (`domain_id`)
+REFERENCES `domains` (`id`) ON DELETE CASCADE;
+```
+
+This automates deletion of records on deletion of a domain from the domains table.
+
+# Using MySQL replication
+To support `NATIVE` domains, the `binlog_format` for the MySQL replication **must**
+be set to `MIXED` or `ROW` to prevent differences in data between replicated
+servers. See ["5.2.4.2, Setting The Binary Log Format"](http://dev.mysql.com/doc/refman/5.7/en/binary-log-setting.html)
+for more information.
+
+# Settings
+## `gmysql-host`
+Host (ip address) to connect to. Mutually exclusive with [`gmysql-socket`](#gmysql-socket).
+
+**WARNING:** When specified as a hostname a chicken/egg situation might arise
+where the database is needed to resolve the IP address of the database. It is
+best to supply an IP address of the database here.
+
+## `gmysql-port`
+The port to connect to on [`gmysql-host`](#gmysql-host). Default: 3306
+
+## `gmysql-socket`
+Connect to the UNIX socket at this path. Mutually exclusive with [`gmysql-host`](#gmysql-host).
+
+## `gmysql-dbname`
+Name of the database to connect to. Default: "pdns".
+
+## `gmysql-user`
+User to connect as. Default: "powerdns".
+
+## `gmysql-group`
+Group to connect as. Default: "client".
+
+## `gmysql-password`
+The password to for [`gmysql-user`](#gmysql-user).
+
+## `gmysql-dnssec`
+Enable DNSSEC processing for this backend. Default=no.
+
+## `gmysql-innodb-read-committed`
+Use the InnoDB READ-COMMITTED transaction isolation level. Default=yes.
+
+## `gmysql-timeout`
+The timeout in seconds for each attempt to read from, or write to the server. A value of 0 will disable the timeout. Default: 10
+
+# Default Schema
+```
+!!include=../modules/gmysqlbackend/schema.mysql.sql
+```
--- /dev/null
+# Generic ODBC Backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes|
+|Case|All lower|
+|DNSSEC|Yes|
+|Disabled data|Yes|
+|Comments|Yes|
+|Module name|godbc|
+|Launch name|godbc|
+
+The Generic ODBC Backend (godbc) is a child of the Generic SQL (gsql) backend,
+similar to the gmysql and gpgsql backends. It uses [UnixODBC](http://www.unixodbc.org/)
+and installed drivers to connect to the databases supported by said drivers.
+
+**Warning**: When there is a more specific generic sql backend (like goracle or
+gmysql), it is highly recommended to use that backend instead!
+
+# Enabling the backend
+When building PowerDNS yourself, append `godbc` to `--with-modules` or
+`--with-dynmodules`. It is expected that most pre-built packages contain this
+backend or be separately installable.
+
+# Configuration Parameters
+This section only details the configuration of PowerDNS for use with ODBC. For
+ODBC related configuration, please see UnixODBC website/documentation and the
+documentation for the driver you intend to use.
+
+## `godbc-datasource`
+
+* String
+* Default: PowerDNS
+
+The datasource (DSN) to use. This must be configured in the `odbc.ini` file,
+usually found in `/etc/`, but this depends your local setup.
+
+## `godbc-username`
+
+* String
+* Default: powerdns
+
+The user to connect to the datasource.
+
+## `godbc-password`
+
+* String
+* Default is empty
+
+The password to connect with the datasource.
+
+# Connecting to Microsoft SQL Server
+**note**: In order to connect to Microsoft SQL Server, you will need at least
+version 3.2.0 of UnixODBC. FreeDTS has been tested with versions 0.91 and 0.95.
+
+Install the [FreeTDS](http://www.freetds.org/) driver for UnixODBC, either by
+compiling or getting it from our distribution's repository and configure your
+`/etc/odbcinst.ini` with the driver, e.g.:
+
+```
+[FreeTDS]
+Description=v0.95.8 with protocol v7.1
+Driver=/usr/local/lib/libtdsodbc.so
+UsageCount=1
+```
+
+And add the datasource to your `/etc/odbc.ini`, e.g:
+```
+[pdns1]
+Driver=FreeTDS
+Trace=No
+Server=server.example.net
+Port=1433
+Database=pdns-1
+TDS_Version=7.1
+```
+
+(For our tests, we add `ClientCharset=UTF-8` as well. YMMV.)
+
+You can now test the connection with `isql pdns1 USERNAME PASSWORD`.
+
+## Loading the schema into the database
+For convenience, a schema for MS SQL Server has been created:
+(Note: This schema can also be found in the PowerDNS source as
+ `modules/godbcbackend/schema.mssql.sql`).
+
+```
+!!include=../modules/godbcbackend/schema.mssql.sql
+```
+
+Load this into the database as follows:
+`cat schema.mssql.sql | tr '\n' ' ' | isql pdns1 USERNAME PASSWORD -b`.
+
+## Loading records into the database
+Loading records is the same as with any SQL backend, just add them
+using SQL-queries. Should you want to use [`zone2sql`](migration.md#zone2sql),
+use the `--sqlite` option for correctly formatted SQL.
+
+## Configuring PowerDNS
+Add the options required to your `pdns.conf`:
+
+```
+launch=godbc
+godbc-datasource=pdns1
+godbc-username=USERNAME
+godbc-password=PASSWORD
+```
+
+Now restart PowerDNS and you're done. Just don't forget to add zones and
+records to the database.
+
+## Possible issues
+It might be that you need to compile FreeTDS with the `--tds-version=7.1` to
+connect to SQL Server.
+
+When connecting to a database hosted with Microsoft Azure, FreeTDS must be
+compiled with OpenSSL, use the `--with-openssl` configure flag.
--- /dev/null
+# Generic Oracle backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes (v3.1 and up)|
+|Case|All lower|
+|DNSSEC|Yes (set `goracle-dnssec`)|
+|Disabled data|Yes (v3.4.0 and up)|
+|Comments|Yes (v3.4.0 and up)|
+|Module name | goracle|
+|Launch name| goracle|
+
+The Generic Oracle Backend is a [Generic SQL backend](backend-generic-sql.md).
+The default setup conforms to the following schema, which you should add to an
+Oracle database. You may need or want to add `namespace` statements.
+
+```
+!!include=../modules/goraclebackend/schema.goracle.sql
+```
+
+This schema contains all elements needed for master, slave and superslave operation.
+
+Inserting records is a bit different compared to MySQL and PostgreSQL, you should use:
+
+```
+INSERT INTO domains (id,name,type) VALUES (domains_id_sequence.nextval, 'example.net', 'NATIVE');
+```
+
+# Settings
+## `goracle-tnsname`
+Which TNSNAME the Generic Oracle Backend should be connecting to. There are no
+`goracle-dbname`, `goracle-host` or `goracle-port` settings, their equivalent is
+in `/etc/tnsnames.ora`.
+
+## `goracle-dnssec`
+Enable DNSSEC processing for this backend. Default=no.
+
+# Caveats
+## Password Expiry
+When your password is about to expire, and logging into oracle warns about this,
+the Generic Oracle backend can no longer login, and will a OCILogin2 warning.
+
+To work around this, either update the password in time or remove expiration
+from the account used.
--- /dev/null
+# Generic PostgreSQL backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes (v3.1 and up)|
+|Case|All lower|
+|DNSSEC|Yes (set `gpgsql-dnssec`)|
+|Disabled data|Yes (v3.4.0 and up)|
+|Comments|Yes (v3.4.0 and up)|
+|Module name | pgsql|
+|Launch name| pgsql|
+
+This PostgreSQL backend is based on the [generic SQL backend](backend-generic-sql.md).
+The default setup conforms to the schema at the bottom of this page, note that
+[`zone2sql`](migration.md#zone2sql) with the `--gpgsql` flag also assumes this layout is in place.
+
+This schema contains all elements needed for master, slave and superslave operation.
+For full migration notes, please see [Migration](migration.md).
+
+With PostgreSQL, you may have to run `createdb pdns` first and then connect
+to that database with `psql pdns`, and feed it the schema above.
+
+# Settings
+## `gpgsql-host`
+Host (ip address) to connect to. If `pgsql-host` begins with a slash, it
+specifies Unix-domain communication rather than TCP/IP communication; the value
+is the name of the directory in which the socket file is stored.
+
+**WARNING:** When specified as a hostname a chicken/egg situation might arise
+where the database is needed to resolve the IP address of the database. It is
+best to supply an IP address of the database here.
+
+## `gpgsql-port`
+The port to connect to on [`gpgsql-host`](#gpgsql-host). Default: 5432
+
+## `gpgsql-dbname`
+Name of the database to connect to. Default: "pdns".
+
+## `gpgsql-user`
+User to connect as. Default: "powerdns".
+
+## `gpgsql-password`
+The password to for [`gpgsql-user`](#gpgsql-user).
+
+## `gpgsql-dnssec`
+Enable DNSSEC processing for this backend. Default=no.
+
+# Default schema
+```
+!!include=../modules/gpgsqlbackend/schema.pgsql.sql
+```
+
--- /dev/null
+# Generic SQL Backends
+The generic SQL backends (like gmysql, gpgsql and godbc) are backends with easily
+configurable SQL statements, allowing you to graft PowerDNS on any SQL database
+of your choosing. Because all database schemas will be different, a generic
+backend is needed to cover all needs.
+
+**Warning**: Host names and the MNAME of a SOA records are NEVER terminated with
+a '.' in PowerDNS storage! If a trailing '.' is present it will inevitably cause
+problems, problems that may be hard to debug.
+
+**Note**: Since 4.0.0, a root zone or record should have a name of '.' (no quotes).
+This is the only exception to the 'no terminating dot in SQL storage' rule.
+
+# Basic functionality
+All domains in the generic SQL backends have a 'type' field that describes the
+[mode of operation](modes-of-operation.md).
+
+## Native operation
+To add a domain, issue the following:
+
+```
+INSERT INTO domains (name, type) VALUES ('powerdns.com', 'NATIVE');
+```
+
+The records table can now be filled by with the domain\_id set to the id of the domains table row just inserted.
+
+## Slave operation
+These backends are fully slave capable. To become a slave of the 'example.com' domain, execute this:
+
+```
+INSERT INTO domains (name, master, type) VALUES ('example.com', '198.51.100.6', 'SLAVE');
+```
+
+And wait a while for PowerDNS to pick up the addition - which happens within one
+minute (this is determined by the [`slave-cycle-interval`](settings.md#slave-cycle-interval)
+setting). There is no need to inform PowerDNS that a new domain was added.
+Typical output is:
+
+```
+Apr 09 13:34:29 All slave domains are fresh
+Apr 09 13:35:29 1 slave domain needs checking
+Apr 09 13:35:29 Domain powerdns.com is stale, master serial 1, our serial 0
+Apr 09 13:35:30 [gPgSQLBackend] Connected to database
+Apr 09 13:35:30 AXFR started for 'powerdns.com'
+Apr 09 13:35:30 AXFR done for 'powerdns.com'
+Apr 09 13:35:30 [gPgSQLBackend] Closing connection
+```
+
+From now on, PowerDNS is authoritative for the 'powerdns.com' zone and will
+respond accordingly for queries within that zone.
+
+Periodically, PowerDNS schedules checks to see if domains are still fresh.
+The default [`slave-cycle-interval`](settings.md#slave-cycle-interval) is 60 seconds,
+large installations may need to raise this value. Once a domain has been checked,
+it will not be checked before its SOA refresh timer has expired. Domains whose
+status is unknown get checked every 60 seconds by default.
+
+PowerDNS has support for multiple masters per zone, separate master IP addresses
+by commas:
+
+```
+INSERT INTO domains (name, master, type) VALUES ('example.com', '198.51.100.6, 2001:0DB8:15:4AF::4', 'SLAVE');
+```
+
+## Superslave operation
+To configure a supermaster with IP address 203.0.113.53 which lists this
+installation as 'autoslave.example.com', issue the following:
+
+```
+INSERT INTO supermasters VALUES ('203.0.113.53', 'autoslave.example.com', 'internal');
+```
+
+From now on, valid notifies from 203.0.113.53 that list a NS record containing
+'autoslave.example.com' will lead to the provisioning of a slave domain under
+the account 'internal'. See [Supermaster](modes-of-operation.md#supermaster-automatic-provisioning-of-slaves)
+for details.
+
+## Master operation
+The generic SQL backend is fully master capable with automatic discovery of serial
+changes. Raising the serial number of a domain suffices to trigger PowerDNS to
+send out notifications. To configure a domain for master operation instead of
+the default native replication, issue:
+
+```
+INSERT INTO domains (name, type) VALUES ('powerdns.com', 'MASTER');
+```
+
+Make sure that the assigned id in the domains table matches the domain\_id field
+in the records table!
+
+## Disabled data
+PowerDNS understands the notion of disabled records. They are marked by setting
+"disabled" to `1` (for PostgreSQL: `true`). By extension, when the SOA record for
+a domain is disabled, the entire domain is considered to be disabled.
+
+Effects: the record (or domain, respectively) will not be visible to DNS clients.
+The REST API will still see the record (or domain). Even if a domain is disabled,
+slaving still works. Slaving considers a disabled domain to have a serial of 0;
+this implies that a slaved domain will not stay disabled.
+
+## Autoserial
+The autoserial functionality makes PowerDNS generate the SOA serial when the SOA
+serial set to `0` in the database. The serial in SOA responses is set to the
+highest value of the `change_date` field in the "records" table.
+
+
+# Handling DNSSEC signed zones
+To enable DNSSEC processing, the `backend-dnssec` option must be set to 'yes'.
+
+## Rules for filling out DNSSEC fields
+Two additional fields in the 'records' table are important: 'auth' and 'ordername'.
+These fields are set correctly on an incoming zone transfer, and also by running
+`pdnsutil rectify-zone`.
+
+The 'auth' field should be set to '1' for data for which the zone itself is
+authoritative, which includes the SOA record and its own NS records.
+
+The 'auth' field should be 0 however for NS records which are used for delegation,
+and also for any glue (A, AAAA) records present for this purpose. Do note that
+the DS record for a secure delegation should be authoritative!
+
+The 'ordername' field needs to be filled out depending on the NSEC/NSEC3 mode.
+When running in NSEC3 'Narrow' mode, the ordername field is ignored and best
+left empty. In NSEC/NSEC3 mode, the ordername field should be NULL for any glue
+but filled in for all delegation NS records and all authoritative records. In
+NSEC3 opt-out mode, ordername is NULL for any glue and insecure delegation NS
+records, but filled in for secure delegation NS records and all authoritative records.
+
+In 'NSEC' mode, it should contain the *relative* part of a domain name, in reverse
+order, with dots replaced by spaces. So 'www.uk.powerdnssec.org' in the
+'powerdnssec.org' zone should have 'uk www' as its ordername.
+
+In 'NSEC3' non-narrow mode, the ordername should contain a lowercase base32hex
+encoded representation of the salted & iterated hash of the full record name.
+`pdnsutil hash-zone-record zone record` can be used to calculate this hash.
+
+In addition, PowerDNS fully supports empty non-terminals. If you have a zone
+example.com, and a host a.b.c.example.com in it, rectify-zone (and the AXFR
+client code) will insert b.c.example.com and c.example.com in the records table
+with type NULL (SQL NULL, not 'NULL'). Having these entries provides several benefits.
+We no longer reply NXDOMAIN for these shorter names (this was an RFC violation
+but not one that caused trouble). But more importantly, to do NSEC3 correctly,
+we need to be able to prove existence of these shorter names. The type=NULL
+records entry gives us a place to store the NSEC3 hash of these names.
+
+If your frontend does not add empty non-terminal names to records, you will get
+DNSSEC replies of 3.1-quality, which has served many people well, but might lead
+to issues in the future.
+
+# Queries
+From version 4.0.0 onward, the generic SQL backends use prepared statements for
+their queries. Before 4.0.0, queries were expanded using the C function 'snprintf'
+which implies that substitutions are performed on the basis of %-placeholders.
+
+To see the default queries for a backend, run
+`pdns_server --no-config --launch=BACKEND --config`.
+
+## Regular Queries
+For regular operation, several queries are used for record-lookup. These queries
+must return the following fields in order:
+
+- content: This is the 'right hand side' of a DNS record. For an A record, this is the IP address for example.
+- ttl: TTL of this record, in seconds. Must be a positive integer, no checking is performed.
+- prio: For MX and SRV records, this should be the priority of the record specified.
+- qtype: The ASCII representation of the qtype of this record. Examples are 'A', 'MX', 'SOA', 'AAAA'. Make sure that this field returns an exact answer - PowerDNS won't recognise 'A ' as 'A'. This can be achieved by using a VARCHAR instead of a CHAR.
+- domain\_id: Unique identifier for this domain. This id must be unique across all backends. Must be a positive integer.
+- name: Actual name of a record. Must not end in a '.' and be fully qualified - it is not relative to the name of the domain!
+- disabled: Boolean, if set to true, this record is hidden from DNS clients, but can still be modified from the REST API. See [Disabled data](#disabled-data). (Available since version 3.4.0.)
+- auth: A boolean describing if PowerDNS is authoritative for this record (DNSSEC)
+
+Please note that the names of the fields are not relevant, but the order is!
+
+- `basic-query`: This is the most used query, needed for doing 1:1 lookups of qtype/name values.
+- `id-query`: Used for doing lookups within a domain.
+- `any-query`: For doing ANY queries. Also used internally.
+- `any-id-query`: For doing ANY queries within a domain. Also used internally.
+- `list-query`: For doing AXFRs, lists all records in the zone. Also used internally.
+- `list-subzone-query`: For doing RFC 2136 DNS Updates, lists all records below a zone.
+- `search-records-query`: To search for records on name and content.
+
+## DNSSEC queries
+These queries are used by e.g. `pdnsutil rectify-zone`. Make sure to read
+[Rules for filling out fields in database backends](dnssec.md#rules-for-filling-out-fields-in-database-backends)
+if you wish to calculate ordername and auth without using pdns-rectify.
+
+- `insert-empty-non-terminal-order--query`: Insert empty non-terminal in zone.
+- `delete-empty-non-terminal-query`: Delete an empty non-terminal in a zone.
+- `remove-empty-non-terminals-from-zone-query`: remove all empty non-terminals from zone.
+
+- `get-order-first-query`: DNSSEC Ordering Query, first.
+- `get-order-before-query`: DNSSEC Ordering Query, before.
+- `get-order-after-query`: DNSSEC Ordering Query, after.
+- `get-order-last-query`: DNSSEC Ordering Query, last.
+- `update-ordername-and-auth-query`: DNSSEC update ordername and auth for a qname query.
+- `update-ordername-and-auth-type-query`: DNSSEC update ordername and auth for a rrset query.
+- `nullify-ordername-and-update-auth-query`: DNSSEC nullify ordername and update auth for a qname query.
+- `nullify-ordername-and-update-auth-type-query`: DNSSEC nullify ordername and update auth for a rrset query.
+
+## Domain and zone manipulation
+
+- `is-our-domain-query`: Checks if the domain (either id or name) is in the 'domains' table. This query is run before any other (possibly heavy) query.
+
+- `insert-zone-query`: Add a new domain. This query also requires the type, masters and account fields
+- `update-kind-query`: Called to update the type of domain.
+- `delete-zone-query` Called to delete all records of a zone. Used before an incoming AXFR.
+- `delete-domain-query`: Called to delete a domain from the domains-table.
+
+- `get-all-domains-query`: Used to get information on all active domains.
+- `info-zone-query`: Called to retrieve (nearly) all information for a domain.
+
+- `insert-record-query`: Called during incoming AXFR.
+- `update-account-query`: Set the account for a domain.
+- `delete-names-query`: Called to delete all records of a certain name.
+- `delete-rrset-query`: Called to delete an RRset based on domain\_id, name and type.
+
+- `get-all-domain-metadata-query`: Get all [`domain metadata`](domainmetadata.md) for a domain.
+- `get-domain-metadata-query`: Get a single piece of [`domain metadata`](domainmetadata.md).
+- `clear-domain-metadata-query`: Delete a single entry of domain metadata.
+- `clear-domain-all-metadata-query`: Remove all domain metadata for a domain.
+- `set-domain-metadata-query`: Add domain metadata for a zone.
+
+- `add-domain-key-query`: Called to a cryptokey to a domain.
+- `list-domain-keys-query`: Called to get all cryptokeys for a domain.
+- `activate-domain-key-query`: Called to set a cryptokey to active.
+- `deactivate-domain-key-query`: Called to set a cryptokey to inactive.
+- `clear-domain-all-keys-query`: Called to remove all DNSSEC keys for a zone.
+- `remove-domain-key-query`: Called to remove a crypto key.
+
+## Master/slave queries
+These queries are used to manipulate the master/slave information in the database.
+Most installations will have zero need to change the following queries.
+
+### On masters
+- `info-all-master-query`: Called to get data on all domains for which the server is master.
+- `update-serial-query` Called to update the last notified serial of a master domain.
+- `zone-lastchange-query`: Called to determine the last change to a zone, used for autoserial.
+
+### On slaves
+- `info-all-slaves-query`: Called to retrieve all slave domains.
+- `master-zone-query`: Called to determine the master of a zone.
+- `update-lastcheck-query`: Called to update the last time a slave domain was successfully checked for freshness.
+- `update-master-query`: Called to update the master address of a domain.
+
+### On superslaves
+- `supermaster-query`: Called to determine if a certain host is a supermaster for a certain domain name.
+- `supermaster-name-to-ips`: Called to the IP and account for a supermaster.
+
+## TSIG
+- `get-tsig-key-query`: Called to get the algorithm and secret from a named TSIG key.
+- `get-tsig-keys-query`: Called to get all TSIG keys.
+- `set-tsig-key-query`: Called to set the algorithm and secret for a named TSIG key.
+- `delete-tsig-key-query`: Called to delete a named TSIG key.
+
+## Comment queries
+For listing/modifying comments.
+
+- `list-comments-query`: Called to get all comments in a zone. Returns fields: domain\_id, name, type, modified\_at, account, comment.
+- `insert-comment-query` Called to create a single comment for a specific RRSet. Given fields: domain\_id, name, type, modified\_at, account, comment
+- `delete-comment-rrset-query`: Called to delete all comments for a specific RRset. Given fields: domain\_id, name, type
+- `delete-comments-query`: Called to delete all comments for a zone. Usually called before deleting the entire zone. Given fields: domain\_id
+- `search-comments-query`: Called to search for comment by name or content.
+
+## Specifying queries
+The queries above are specified in pdns.conf. For example, the basic-query for
+the Generic MySQL backend would appear as:
+
+```
+gmysql-basic-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE disabled=0 and type=? and name=?
+```
+
+Queries can span multiple lines, like this:
+
+```
+gmysql-basic-query=SELECT content,ttl,prio,type,domain_id,disabled,name,auth \
+FROM records WHERE disabled=0 and type=? and name=?
+```
--- /dev/null
+# Generic SQLite backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|DNSSEC|Yes|
+|Disabled data|Yes|
+|Comments|Yes|
+|Module name|gsqlite3|
+|Launch name|gsqlite3|
+
+**Warning**: When importing large amounts of data, be sure to run 'analyze;'
+afterwards as SQLite3 has a tendency to use sub-optimal indexes otherwise.
+
+This backend retrieves all data from a SQLite database, which is an RDBMS that's
+embedded into the application itself, so you won't need to be running a separate
+server process. It also reduces overhead, and simplifies installation. At
+[www.sqlite.org](http://www.sqlite.org) you can find more information about SQLite.
+
+As this is a generic backend, built on top of the gSql framework, you can
+specify all queries as documented in
+[Generic SQL Backends](backend-generic-sql.md#queries).
+
+SQLite exists in two incompatible versions, PowerDNS only supports version 3. To
+launch the backend, put `launch=gsqlite3` in the configuration.
+
+## Setting up the database
+Before you can use this backend you first have to set it up and fill it with
+data. The default setup conforms to the following schema:
+
+```
+!!include=../modules/gsqlite3backend/schema.sqlite3.sql
+```
+
+This schema contains all elements needed for master, slave and superslave operation.
+
+After you have created the database you probably want to fill it with data. If
+you have a BIND zone file it's as easy as:
+`zone2sql --named-conf=/path/to/named.conf --gsqlite | sqlite3 powerdns.sqlite3`, but you can
+also use AXFR (or insert data manually).
+
+To communicate with a SQLite database, use the `sqlite3` program, and feed it SQL.
+
+## Configuration Parameters
+These are the configuration file parameters that are available for the gsqlite3 backend.
+
+### `gsqlite3-database`
+Path to the SQLite3 database.
+
+### `gsqlite3-pragma-synchronous`
+Set this to 0 for blazing speed.
+
+### `gsqlite3-pragma-foreign-keys`
+Enable foreign key constraints.
+
+### `gsqlite3-dnssec`
+Enable DNSSEC processing.
+
+## Using the SQLite backend
+The last thing you need to do is telling PowerDNS to use the SQLite backend.
+
+```
+# in pdns.conf
+launch=gsqlite3
+gsqlite3-database=<path to your SQLite database>
+```
+
+Then you can start PowerDNS and it should notify you that a connection to the
+database was made.
+
+## Compiling the SQLite backend
+Before you can begin compiling PowerDNS with the SQLite backend you need to have
+the SQLite utility and library installed on your system. You can download these
+from <http://www.sqlite.org/download.html>, or you can use packages
+(if your distribution provides those).
+
+When you've installed the library you can use:
+`./configure --with-modules="gsqlite3"` to configure PowerDNS to use the SQLite
+backend. Compilation can then proceed as usual.
+
+SQLite is included in most PowerDNS binary releases.
+
--- /dev/null
+# GeoIP backend
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|DNSSEC|Yes|
+
+This backend allows visitors to be sent to a server closer to them, with no appreciable delay, as would otherwise be incurred with a protocol level redirect. Additionally, the Geo Backend can be used to provide service over several clusters, any of which can be taken out of use easily, for example for maintenance purposes. This backend can utilize EDNS Client Subnet extension for decision making, if provided in query and you have turned on (edns-subnet-processing)[settings.md#edns-subnet-processing].
+
+## Prerequisites
+To compile the backend, you need libyaml-cpp 0.5 or later and libgeoip.
+
+You must have geoip database available. As of writing, on debian/ubuntu systems, you can use apt-get install geoip-database to get one, and the backend is configured to use the location where these files are installed as source. On other systems you might need to alter the database-file and database-file6 attribute. If you don't need ipv4 or ipv6 support, set the respective setting to "". Leaving it unset leaves it pointing to default location, preventing the software from starting up.
+
+## Configuration Parameters
+These are the configuration file parameters that are available for the GeoIP backend. geoip-zones-files is the only thing you must set, if the defaults suite you.
+
+### `geoip-database-file`
+Before 4.0.0. Specifies the full path of the data file for IPv4 to use.
+
+### `geoip-database-file6`
+Before 4.0.0. Specifies the full path of the data file for IPv6 to use.
+
+### `geoip-database-files`
+After 4.0.0. Comma, tab or space separated list of files to open. You can use [geoip-cvs-to-dat](https://github.com/dankamongmen/sprezzos-world/blob/master/packaging/geoip/debian/src/geoip-csv-to-dat.cpp) to generate your own.
+
+### `geoip-database-cache`
+Specifies the kind of caching that is done on the database. This is one of
+"standard", "memory", "index" or "mmap". These options map to the caching
+options described [here](https://github.com/maxmind/geoip-api-c/blob/master/README.md#memory-caching-and-other-options)
+
+### `geoip-zones-file`
+Specifies the full path of the zone configuration file to use.
+
+### `geoip-dnssec-keydir`
+Specifies the full path of a directory that will contain DNSSEC keys. This option enables DNSSEC on the backend. Keys can be created/managed with `pdnsutil`, and the backend stores these keys in files with key flags and active/disabled state encoded in the key filenames.
+
+## Zonefile format
+Zone configuration file uses YAML syntax. Here is simple example. Note that the ‐ before certain keys is part of the syntax.
+
+Before 4.0.0:
+
+```
+domains:
+- domain: geo.example.com
+ ttl: 30
+ records:
+ geo.example.com:
+ - soa: ns1.example.com hostmaster.example.com 2014090125 7200 3600 1209600 3600
+ - ns: ns1.example.com
+ - ns: ns2.example.com
+ - mx: 10 mx.example.com
+ fin.eu.service.geo.example.com:
+ - a: 192.0.2.1
+ - txt: hello world
+ - aaaa: 2001:DB8::12:34DE:3
+ services:
+ service.geo.example.com: '%co.%cn.service.geo.example.com'
+```
+
+From 4.0.0:
+
+```
+domains:
+- domain: geo.example.com
+ ttl: 30
+ records:
+ geo.example.com:
+ - soa: ns1.example.com hostmaster.example.com 2014090125 7200 3600 1209600 3600
+ - ns:
+ content: ns1.example.com
+ ttl: 600
+ - ns: ns2.example.com
+ - mx: 10 mx.example.com
+ fin.eu.service.geo.example.com:
+ - a: 192.0.2.2
+ - txt: hello world
+ - aaaa: 2001:DB8::12:34DE:3
+# this will result first record being handed out 30% of time
+ swe.eu.service.geo.example.com:
+ - a:
+ content: 192.0.2.3
+ weight: 50
+ - a: 192.0.2.4
+ services:
+# syntax 1
+ service.geo.example.com: '%co.%cn.service.geo.example.com'
+# syntax 2
+ service.geo.example.com: [ '%co.%cn.service.geo.example.com', '%cn.service.geo.example.com']
+# alternative syntax
+ services:
+ service.geo.example.com:
+ default: [ '%co.%cn.service.geo.example.com', '%cn.service.geo.example.com' ]
+ 10.0.0.0/8: 'internal.service.geo.example.com'
+```
+
+### Keys explained
+* **domains**: Mandatory root key. All configuration is below this
+* **domain**: Defines a domain. You need ttl, records, services under this.
+* **ttl**: TTL value for all records
+* **records**: Put fully qualified name as subkey, under which you must define at least soa: key. Note that this is an array of records, so ‐ is needed for the values.
+* **services**: Defines one or more services for querying. The format supports following placeholders, %% = %, %co = 3-letter country, %cn = continent, %af = v4 or v6. There are also other specifiers that will only work with suitable database and currently are untested. These are %re = region, %na = Name (such as, organisation), %ci = City.
+* From 4.0.0, you can also use %as = ASn, %ip = Remote IP
+* From 4.0.0, you can also use additional specifiers. These are %hh = hour, %dd = day, %mo = month, %mos = month as short string, %wd = weekday (as number), %wds weekday as short string.
+* From 4.0.0, scopeMask is set to most specific value, in case of date/time modifiers it will be 32 or 128, but with the others it is set to what geoip says it used for matching.
+* From 4.0.0, You can add per-network overrides for format, they will be formatted with the same placeholders as default. Default is short-hand for adding 0.0.0.0/0 and ::/0. Default is default when only string is given for service name.
+* From 4.0.0, You can use array to specify return values, works only if you have those records specified. It matches the format results to your records, and if it finds match that is used. Otherwise the last is returned.
+* From 4.0.0, You can apply all the attributes for the content of static records too.
+* From 4.0.0, You can use record attributes to set TTL.
+* From 4.0.0, You can use record attributes to define weight. If this is given, only one record is chosen randomly based on the weight. **DO NOT** mix record types for these. It will not work. PROBABILITY is calculated by summing up the weights and dividing each weight with the sum.
+**WARNING**: If you use ip or time/date specifiers, caching will be disabled for that RR completely. That means, if you have a
+
+ something.example.com:
+ - a: 1.2.3.4
+ - txt: "your ip is %ip"
+
+then caching will not happen for any records of something.example.com. If you need to use TXT for debugging, make sure you use dedicated name for it.
--- /dev/null
+# LDAP backend
+
+As of PowerDNS Authoritative Server 4.0.0, the LDAP backend is fully supported.
+
+**Warning**: Grégory Oestreicher has forked the LDAP backend shortly before our 3.2 release, after which a lot of development happened in a short time. We are working to upstream this work.
+
+The original author for this module is Norbert Sendetzky. This page is based on the content from his [LDAPbackend wiki section](http://wiki.linuxnetworks.de/index.php/PowerDNS_ldapbackend) as copied in February 2016, and edited from there.
+
+**Warning**: Host names and the MNAME of a SOA records are NEVER terminated with a '.' in PowerDNS storage! If a trailing '.' is present it will inevitably cause problems, problems that may be hard to debug.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|DNSSEC|No|
+
+
+
+
+# Introduction
+
+Rationale
+---------
+
+This HOWTO documents the steps necessary to build and use the LDAP DNS
+backend I've written for PowerDNS, an extremely versatile name server.
+This backend enables PowerDNS to retrieve DNS information from any
+standard compliant LDAP server. This is extremely handy if you have
+already stored information about your hosts in your LDAP tree.
+
+Schemas
+-------
+
+The schema is based on the 'uninett' dnszone schema, with a few types
+added by number as designed in that schema.
+
+```
+!!include=../modules/ldapbackend/dnsdomain2.schema
+```
+
+The LDAP dnsdomain2 schema contains the additional object descriptions
+which are required by the LDAP server to check the validity of entries
+when they are added. Please consult the documentation of your LDAP
+server to find out how to add this schema to the server.
+
+
+# Installation
+
+Configuration options
+---------------------
+
+There are a few options through the LDAP DNS backend can be configured
+for your environment. Add them to the pdns.conf file located in
+/etc/powerdns or /usr/local/etc/ (depends on your configuration while
+compiling):
+
+`launch=ldap`
+
+You'll have to add the LDAP DNS backend to the PowerDNS backends first
+by altering the `launch` declaration in the pdns.conf file. Otherwise the
+options below won't have any effect.
+
+ldap-host (default "ldap://127.0.0.1:389/") : The values assigned to this parameter can be LDAP URIs (e.g. <ldap://127.0.0.1/> or <ldaps://127.0.0.1/>) describing the connection to the LDAP server. There can be multiple LDAP URIs specified for load balancing and high availability if they are separated by spaces. In case the used LDAP client library doesn't support LDAP URIs as connection parameter, use plain host names or IP addresses instead (both may optionally be followed by a colon and the port).
+
+## `ldap-starttls`
+(default "no") : Use TLS encrypted connections to the LDAP server. This is only allowed if ldap-host is a <ldap://> URI or a host name / IP address.
+
+
+## `ldap-basedn`
+(default "") : The PowerDNS LDAP DNS backend searches below this path for objects containing the specified DNS information. The retrieval of attributes is limited to this subtree. This option must be set to the path according to the layout of your LDAP tree, e.g. ou=hosts,o=linuxnetworks,c=de is the DN to my objects containing the DNS information.
+
+## `ldap-binddn`
+(default "") : Path to the object to authenticate against. Should only be used, if the LDAP server doesn't support anonymous binds.
+
+## `ldap-secret`
+(default "") : Password for authentication against the object specified by ldap-binddn
+
+## `ldap-method`
+(default "simple") :
+
+- `simple`: Search the requested domain by comparing the associatedDomain
+ attributes with the domain string in the question.
+
+- `tree`: Search entires by translating the domain string into a LDAP dn. Your
+ LDAP tree must be designed in the same way as your DNS LDAP tree.
+ The question for "myhost.linuxnetworks.de" would translate into
+ "dc=myhost,dc=linuxnetworks,dc=de,ou=hosts=..." and the entry where
+ this dn points to would be evaluated for dns records.
+
+- `strict`: Like simple, but generates PTR records from aRecords or aAAARecords.
+ Using "strict", you won't be able to do zone transfers for
+ reverse zones.
+
+## `ldap-filter-axfr`
+(default "(:target:)" ) : LDAP filter for limiting AXFR results (zone transfers), e.g. (&(:target:)(active=yes)) for returning only entries whose attribute "active" is set to "yes".
+
+<!-- -->
+
+## `ldap-filter-lookup`
+(default "(:target:)" ) : LDAP filter for limiting IP or name lookups, e.g. (&(:target:)(active=yes)) for returning only entries whose attribute "active" is set to "yes".
+
+# Example
+
+Tree design
+-----------
+
+The DNS LDAP tree should be designed carefully to prevent mistakes,
+which are hard to correct afterwards. The best solution is to create a
+subtree for all host entries which will contain the DNS records. You can
+do this the simple way or in a tree style.
+
+DN of a simple style example record (e.g. myhost.linuxnetworks.de):
+
+`dn: dc=myhost,dc=linuxnetworks,ou=hosts,...`
+
+DN of a tree style example record (e.g. myhost.test.linuxnetworks.de):
+
+`dn: dc=myhost,dc=test,dc=linuxnetworks,dc=de,ou=hosts,...`
+
+Basic objects
+-------------
+
+Each domain (or zone for BIND users) must include one object containing
+a SOA (Start Of Authority) record. This object can also contain the
+attribute for a MX (Mail eXchange) and a NS (Name Server) record. These
+attributes allow one or more values, e.g. for a backup mail or name
+server:
+
+```
+dn: dc=linuxnetworks,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dcobject
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: linuxnetworks
+soarecord: ns.linuxnetworks.de me@linuxnetworks.de 1 1800 3600 86400 7200
+nsrecord: ns.linuxnetworks.de
+mxrecord: 10 mail.linuxnetworks.de
+mxrecord: 20 mail2.linuxnetworks.de
+associateddomain: linuxnetworks.de
+```
+
+A simple mapping between name and IP address can be specified by an
+object containing an arecord and an associateddomain. You don't have to
+bother about a reverse mapping (ip address to name) if you don't want
+to, because this can be done automagically by the LDAP DNS backend if
+you set ldap-method=strict in pdns.conf.
+
+```
+dn: dc=server,dc=linuxnetworks,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: server
+arecord: 10.1.0.1
+arecord: 192.168.0.1
+associateddomain: server.linuxnetworks.de
+```
+
+Be aware of the fact that these examples work if ldap-method is simple
+or strict. For tree mode you have to modify all DNs according to the
+algorithm described in the section above.
+
+Wildcards
+---------
+
+Wild-card domains are possible by using the asterisk in the
+associatedDomain value like it is used in the bind zone files. The "dc"
+attribute can be set to any value in simple or strict mode - this
+doesn't matter.
+
+dn: dc=any,dc=linuxnetworks,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: any
+arecord: 192.168.0.1
+associateddomain: *.linuxnetworks.de
+
+In tree mode wild-card entries has to look like this instead:
+
+```
+dn: dc=*,dc=linuxnetworks,dc=de,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: *
+arecord: 192.168.0.1
+associateddomain: *.linuxnetworks.de
+```
+
+Aliases
+-------
+
+Aliases for an existing DNS object have to be defined in a separate LDAP
+object. You can create one object per alias (this is a must in tree
+mode) or add all aliases (as values of associateddomain) to one object.
+The only thing which is not allowed is to create loops by using the same
+name in associateddomain and in cnamerecord
+
+```
+dn: dc=server-aliases,dc=linuxnetworks,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: server-aliases
+cnamerecord: server.linuxnetworks.de
+associateddomain: proxy.linuxnetworks.de
+associateddomain: mail2.linuxnetworks.de
+associateddomain: ns.linuxnetworks.de
+```
+
+Aliases are optional. You can also add all alias domains to the
+associateddomain attribute. The only difference is that these additional
+domains aren't recognized as aliases anymore, but instead as a normal
+arecord:
+
+```
+dn: dc=server,dc=linuxnetworks,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain
+objectclass: domainrelatedobject
+dc: server
+arecord: 10.1.0.1
+associateddomain: server.linuxnetworks.de
+associateddomain: proxy.linuxnetworks.de
+associateddomain: mail2.linuxnetworks.de
+associateddomain: ns.linuxnetworks.de
+```
+
+Reverse lookups
+---------------
+
+Currently you have two options: Either reverse lookups handled by the
+code automagically or you have to add PTR records to your LDAP
+directory. If you want to derive PTR records from A records, you have
+set "ldap-method" to "strict". Otherwise add objects like below to your
+directory:
+
+```
+dn: dc=1.10.in-addr.arpa,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain2
+objectclass: domainrelatedobject
+dc: 1.10.in-addr.arpa
+soarecord: ns.linuxnetworks.de me@linuxnetworks.de 1 1800 3600 86400 7200
+nsrecord: ns.linuxnetworks.de
+associateddomain: 1.10.in-addr.arpa
+```
+
+```
+dn: dc=1.0,dc=1.10.in-addr.arpa,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain2
+objectclass: domainrelatedobject
+dc: 1.0
+ptrrecord: server.linuxnetworks.de
+associateddomain: 1.0.1.10.in-addr.arpa
+```
+
+Tree mode requires each component to be a dc element of its own:
+
+```
+dn: dc=1,dc=0,dc=1,dc=10,dc=in-addr,dc=arpa,ou=hosts,o=linuxnetworks,c=de
+objectclass: top
+objectclass: dnsdomain2
+objectclass: domainrelatedobject
+dc: 1
+ptrrecord: server.linuxnetworks.de
+associateddomain: 1.0.1.10.in-addr.arpa
+```
+
+To use this kind of record, you also have to add the dnsdomain2 schema
+to the configuration of your LDAP server.
+
+**CAUTION:**
+
+You can't use "ldap-method=strict" if you need zone transfers (AXFR) to
+other name servers. Distributing zones can only be done directly via
+LDAP replication in this case, because for a full zone transfer the
+reverse records are missing
+
+# Migration
+
+BIND zone files
+---------------
+
+There is a small utility in the PowerDNS distribution available called
+"zone2ldap", which can convert zone files used by BIND to the ldif
+format. Ldif is a text file format containing information about LDAP
+objects and can be read by every standard compliant LDAP server.
+Zone2ldap needs the BIND named.conf (usually located in /etc) as input
+and writes the dns record entries in ldif format to stdout:
+
+Usage:
+
+```
+zone2ldap
+ --basedn=`<your-basedn
+ --named-conf=`<file
+ --resume
+ > zones.ldif
+```
+
+Alternatively zone2ldap can be used to convert only single zone files
+instead all zones:
+
+Usage:
+
+```
+zone2ldap
+ --basedn=`<your-basedn
+ --zone-file=`<file
+ --zone-name=`<file
+ --resume
+ > zone.ldif
+```
+
+See [its manpage](../manpages/zone2ldap.1.md) for a complete list of options.
+
+Bind LDAP backend
+-----------------
+
+If you are using the [Bind LDAP sdb
+backend](http://bind9-ldap.bayour.com/), you can keep the records in the
+LDAP tree also for the PowerDNS LDAP backend. The schemas both backends
+utilize is almost the same except for one important thing: Domains for
+PowerDNS are stored in the attribute "associatedDomain" whereas Bind
+stores them split in "relativeDomainName" and "zoneName".
+
+There is a [migration
+script](http://www.linuxnetworks.de/pdnsldap/bind2pdns-ldap) which
+creates a file in LDIF format with the necessary LDAP updates including
+the "associatedDomain" and "dc" attributes. The utility is executed on
+the command line by:
+
+```
+./bind2pdns-ldap
+ --host=<host name or IP>
+ --basedn=<subtree dn>
+ --binddn=<admin dn>
+ > update.ldif
+```
+
+The parameter "host" and "basedn" are mandatory, "binddn" is optional.
+If "binddn" is given, you will be asked for a password, otherwise an
+anonymous bind is executed. The updates in LDIF format are written to
+stdout and can be redirected to a file.
+
+The script requires Perl and the Perl Net::LDAP module and can be
+downloaded from
+[/pdnsldap/bind2pdns-ldap](http://www.linuxnetworks.de/pdnsldap/bind2pdns-ldap).
+
+Updating the entries in the LDAP tree requires to make the dnsdomain2
+schema known to the LDAP server. Unfortunately, both schemas (dnsdomain2
+and dnszone) share the same record types and use the same OIDs so the
+LDAP server can't use both schemas at the same time. The solution is to
+add the [dnsdomain2
+schema](http://www.linuxnetworks.de/pdnsldap/dnsdomain2.schema) and
+replace the dnszone schema by the [dnszone-migrate
+schema](http://www.linuxnetworks.de/pdnsldap/dnszone-migrate.schema).
+After restarting the LDAP server you can use attributes from both
+schemas and updating the objects in the LDAP tree using the LDIF file
+generated from bind2pdns-ldap will work without errors.
+
+Other name server
+-----------------
+
+The easiest way for migrating DNS records is to use the output of a zone
+transfer (AXFR). Save the output of the "dig" program provided by bind
+into a file and call zone2ldap with the file name as option to the
+--zone-file parameter. This will generate you an appropriate ldif file,
+which you can import into your LDAP tree. The bash script except below
+automates this for you.
+
+```
+DNSSERVER=127.0.0.1
+DOMAINS="linuxnetworks.de 10.10.in-addr.arpa"
+
+for DOMAIN in $DOMAINS; do
+ dig @$DNSSERVER $DOMAIN AXFR> $DOMAIN.zone;
+ zone2ldap --zone-name=$DOMAIN --zone-file=$DOMAIN.zone> $DOMAIN.ldif;
+done
+```
+
+# Optimization
+
+LDAP indices
+------------
+
+To improve performance, you can tell the LDAP server to maintain indices
+on certain attributes. This leads to much faster searches for these type
+of attributes.
+
+The LDAP DNS backend mainly searches for values in associatedDomain, so
+maintaining an index (pres,eq,sub) on this attribute is a big
+performance improvement:
+
+`index associatedDomain pres,eq,sub`
+
+Furthermore if you set ldap-method=strict, it uses the aRecord and
+aAAARecord attribute for reverse mapping of IP addresses to names. To
+maintain an index (pres,eq) on these attributes also improves
+performance of the LDAP server:
+
+```
+index aAAARecord pres,eq
+index aRecord pres,eq
+```
+
+All other attributes than associatedDomain, aRecord or aAAARecord are
+only read if the object matches the specified criteria. Thus,
+maintaining an index on these attributes is useless.
+
+If you've inserted your entries before adding these statements to your
+slapd.conf, you have to stop your LDAP server and call slapindex on the
+command line. This will generate the indices for already existing
+attributes
+
+dNSTTL attribute
+----------------
+
+Converting the string in the dNSTTL attribute to an integer is a time
+consuming task. If you don't use a separate TTL value for each entry and
+use the default-ttl parameter in pdns.conf instead, you will gain a
+approx. 7% better performance for entries that aren't cached. You can
+still add a dNSTTL attribute to entries that should have a different TTL
+than the default TTL
+
+Access method
+-------------
+
+The method of accessing the entries in the directory affects the
+performance too. By default, the "simple" method is used search for
+entries by using their associatedDomain attribute. Alternatively you can
+choose the "tree" method, whereby the search is done along the directory
+tree, e.g. "host.example.dom" is translated into
+"dc=host,dc=example,dc=dom,...". This requires your LDAP DNS subtree
+layout to be 1:1 to the DNS tree, but then you will gain additional 7%
+better performance values.
+
+# Troubleshooting
+
+No reverse zone transfer
+------------------------
+
+Your LDAP tree must contain a separate subtree of PTR records (e.g. for
+1.1.10.10.in-addr.arpa) and you can't set "ldap-method" to "strict".
+
+IPv6 reverse lookup doesn't work in strict mode
+-----------------------------------------------
+
+For automatically generated reverse IPv6 records your aAAARecord entries
+must follow two restrictions: They have to be fully expanded ("FFFF::1"
+is not allowed and it must be "FFFF:0:0:0:0:0:0:1" instead) and they
+must not contain leading zeros, e.g. an entry containing "002A" is
+incorrect - use "2A" without zeros instead. These restrictions are due
+to the fact that LDAP DNS AAAA entries are pure text and doesn't allow
+searching by wild-cards.
+
+Bad search filter
+-----------------
+
+The release of PowerDNS 2.9.20 contains a bug in
+ldap-filter-{axfr,lookup}. A user provided string with ":target:" is
+replaced with "(associatedDomain=QUERYDATA)" and braces ARE added. So if
+you create some filter like
+
+`ldap-filter-lookup=(&(:target:)(active=yes))`
+
+it will result as
+
+`ldap-filter-lookup=(&((associatedDomain=QUERYDATA))(active=yes))`
+
+which results with bad search filter. To circumvent the bug temporarily
+you can add instead
+
+`ldap-filter-lookup=(&:target:(active=yes))`
+
+The bug will be fixed in version 2.9.21 and later versions.
+
+------------------------------------------------------------------------
+
+**Feel free to add your own tips**
+
+# Future
+
+DNS notification support
+------------------------
+
+As soon as the LDAP server implementations begin to provide the features
+of the LDAP client update protocol (LCUP, [RFC
+3928](http://www.ietf.org/rfc/rfc3928.txt)), it will be possible to
+support the DNS notification feature for the [LDAP DNS
+backend](PowerDNS_LDAP_Backend "wikilink") in case a record in the LDAP
+directory was changed.
+
+SASL support
+------------
+
+Support for more authentication methods would be handy. Anyone
+interested and willing to contribute?
--- /dev/null
+# Lua Backend
+**Warning**: The status of this backend is unknown, it compiles and works, but
+is different from the original, updated version at
+[Fredrik's github](https://github.com/fredan/luabackend).
+
+The main author for this module is Fredrik Danerklint.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|DNSSEC|Yes|
+
+**Warning**: The Lua Backend is available since PowerDNS Authoritative Server
+3.0. In 3.0 and 3.1, this backend is marked as Experimental!
+
+This backend is just a "glue" between PowerDNS and your own Lua application.
+
+What this means is that you can not have a working setup that can serve you
+dns-questions directly from start. What you need to do is to program your own
+backend completely in Lua! Which database server to use etc is now up to you!
+
+What you have here is the possibility to make your own "dns-server" without the
+knowledge of programming in c/c++.
+
+There is one thing that needs to be said. Remember that each thread
+PowerDNS launches of this backend is completely different so they cannot
+share information between each other!
+
+You will need some kind of a database that can be shared for this.
+
+All the functionnames that PowerDNS accept for a backend should be the same
+in your Lua script, in lowercase. Also, the parameters should be in the same
+order. Where there is a structure in c/c++ there is a table in the Lua backend.
+This is also true for return values. A few functions expect that you return a
+table in a table.
+
+
+## New functions
+There is a couple of new functions for you to use in Lua:
+
+### `logger(log_facility, "your", "messages")`
+
+All these `log_facilities` is available:
+* `log_all`
+* `log_ntlog`
+* `log_alert`
+* `log_critical`
+* `log_error`
+* `log_warning`
+* `log_notice,`
+* `log_info`
+* `log_debug`
+* `log_none`
+
+
+### `dnspacket()`
+This will give you back three parameters with
+`remote_ip`, `remote_port` and `local_ip` in that order.
+
+Can only be used in the functions [`list()`](#list) and [`getsoa()`](#getsoa).
+
+### `getarg("PARAMETER")`
+This one tries to get the value of the name `"lua-PARAMETER"` from the
+pdns.conf file.
+
+### `mustdo("PARAMETER")`
+This is the same as [`getarg()`](#getarg) but return a boolean instead of a string.
+
+You also have all the different QTypes in a table called 'QTypes'.
+
+# What has been tested
+The only functionality of the minimal functions except zone-transfer has
+been tested.
+
+In the included powerdns-luabackend.lua file there is a example of how
+this can be done. Note that this is more or less a static example since
+there is no possibility for each thread to know when something has changed.
+
+However, you can run `pdns_control reload` and it should reload the whole thing
+from scratch (does not work for the moment, PowerDNS only calls two thread with
+the reload command - not all of them).
+
+# What you will find under the test directory
+The following script can be used to test the server:
+```{include='../../modules/luabackend/test/powerdns-luabackend.lua'}
+```
+
+This will yield the following result:
+
+```
+$dig any www.test.com @127.0.0.1 -p5300 +multiline
+; <<>> DiG 9.7.3 <<>> any www.test.com @127.0.0.1 -p5300 +multiline
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1001
+;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+;; WARNING: recursion requested but not available
+
+;; QUESTION SECTION:
+;www.test.com. IN ANY
+
+;; ANSWER SECTION:
+www.test.com. 120 IN CNAME host.test.com.
+host.test.com. 120 IN A 10.11.12.13
+host.test.com. 120 IN AAAA 1:2:3:4:5:6:7:8
+
+;; Query time: 1 msec
+;; SERVER: 127.0.0.1#5300(127.0.0.1)
+;; WHEN: Thu Jun 2 22:19:56 2011
+;; MSG SIZE rcvd: 93
+```
+
+# Parameters
+## `lua-filename`
+Path to your lua script, 'powerdns-luabackend.lua' by default.
+
+## `lua-logging-query`
+Log queries. default is 'no'.
+
+## `lua-f_FUNCTION=NEWFUNCTION`
+You can also override all the default functionsnames for the luafunctions if you
+want. For example:
+
+`lua-f_lookup = mynewfunction`
+
+will call the function `mynewfunction` for the lookup-routine.
+
+If you want your own configuration parameters you can have that too.
+Just call the function `getarg("PARAMETER")` and it will return the value
+of `lua-PARAMETER`. For boolean you use the function `mustdo("PARAMETER")`.
+
+## Your own error function in lua
+You can have an error function in Lua when Lua gives back a error.
+
+First make your error function then you put this in `pdns.conf`:
+
+`lua-f_exec_error = YOUR_METHOD`
+
+# DNSSEC
+You can have full dnssec support in our Lua application. You should note the
+following regarding this:
+
+You don't have to implement the function 'updateDNSSECOrderAndAuth' since the
+default code will work correctly for you via the backend itself.
+
+The functions activateDomainKey and deactivateDomainKey can be implemented via a
+new function called updateDomainKey, which has three parameters (the other two
+has only two parameters) where the third is a boolean which is true or false
+depending on which function that was called from the beginning.
+
+# Information for logging
+If you have the parameter `query-logging` or `lua-logging-query` set to
+true/yes/on, then you will see what is happening in each function when PowerDNS
+calls them.
+
+This can, hopefully, help you with some debugging if you run into some kind of
+trouble with your Lua application.
--- /dev/null
+# MyDNS Backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|Case|Depends|
+|DNSSEC|No|
+|Disabled data|No|
+|Comments|No|
+|Module name|`mydns`|
+|Launch name|`mydns`|
+
+The MyDNS backend makes PowerDNS a drop-in replacement for the
+[MyDNS](http://mydns.bboy.net/) nameserver, as it uses the same database schema.
+
+## Configuration Parameters
+### `mydns-host`
+Database host to connect to.
+
+### `mydns-port`
+Port on the database server to connect to.
+
+### `mydns-dbname`
+Name of the database to connect to, "mydns" by default.
+
+### `mydns-user`
+User for the database, "powerdns" by default.
+
+### `mydns-password`
+The user password.
+
+### `mydns-socket`
+Unix socket to connect to the database.
+
+### `mydns-rr-table`
+Name of the resource record table in the database, "rr" by default.
+
+### `mydns-soa-table`
+Name of the SOA table in the database, "soa" by default.
+
+### `mydns-soa-where`
+Additional WHERE clause for SOA, default is "1 = 1".
+
+### `mydns-rr-where`
+Additional WHERE clause for resource records, default is "1 = 1".
+
+### `mydns-soa-active`
+Use the active column in the SOA table, "yes" by default.
+
+### `mydns-rr-active`
+Use the active column in the resource record table, "yes" by default.
+
+### `mydns-use-minimal-ttl`
+Setting this to 'yes' will make the backend behave like MyDNS on the TTL values.
+Setting it to 'no' will make it ignore the minimal-ttl of the zone. The default
+is "yes".
+
--- /dev/null
+# OpenDBX Backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes|
+|DNSSEC|No|
+|Module name|opendbx|
+|Launch name|opendbx|
+
+The OpenDBX backend allows the authoritative server to connect to any backend
+supported by [OpenDBX](http://www.linuxnetworks.de/doc/index.php/OpenDBX).
+
+This document contains a subset of the [full documentation](http://www.linuxnetworks.de/doc/index.php/PowerDNS_OpenDBX_Backend)
+supplied by the author Norbert Sendetzky . This module is fully supported (and
+tested) by PowerDNS.
+
+The OpenDBX backend has a mechanism to connect different database servers for
+read and write actions.
+
+The domains table for the opendbx backend has a "status" column, when set to "A",
+the domain is considered active and is actually served.
+
+# Settings
+## opendbx-backend
+Name of the backend used to connect to the database server. Currently mysql,
+pgsql, sqlite, sqlite3 and sybase are available. Default=mysql.
+
+## opendbx-host-read
+One or more host names or IP addresses of the database servers. These hosts will
+be used for retrieving the records via SELECT queries. Default=127.0.0.1
+
+## opendbx-host-write
+One or more host names or IP addresses of the database servers. These hosts will
+be used for INSERT/UPDATE statements (mostly used by zonetransfers). Default=127.0.0.1
+
+## opendbx-port
+TCP/IP port number where the database server is listening to. Most databases will
+use their default port if you leave this empty.
+
+## opendbx-database
+The database name where all domain and record entries are stored. Default=powerdns
+
+## opendbx-username
+Name of the user send to the DBMS for authentication. Default=powerdns.
+
+## opendbx-password
+Clear text password for authentication in combination with the username.
+
+## Queries
+As with the [Generic SQL backends](backend-generic-sql.md), queries are configurable.
+Note: If you change one of the SELECT statements must not change the order of
+the retrieved columns! To get the default queries, run `pdns_server --no-config --launch=opendbx --config`.
+The following queries are configurable:
+
+- `opendbx-sql-list`: Select records which will be returned to clients asking for zone transfers (AXFR).
+- `opendbx-sql-lookup`: Retrieve DNS records by name.
+- `opendbx-sql-lookupid`: Retrieve DNS records by id and name.
+- `opendbx-sql-lookuptype`: Retrieve DNS records by name and type.
+- `opendbx-sql-lookuptypeid`: Retrieve DNS records by id, name and type.
+- `opendbx-sql-lookupsoa`: Retrieve SOA record for domain.
+- `opendbx-sql-zonedelete`: Delete all records from zone before inserting new ones via AXFR.
+- `opendbx-sql-zoneinfo`: Get stored information about a domain.
+- `opendbx-sql-transactbegin`: Start transaction before updating a zone via AXFR.
+- `opendbx-sql-transactend`: Commit transaction after updating a zone via AXFR.
+- `opendbx-sql-transactabort`: Undo changes if an error occurred while updating a zone via AXFR.
+- `opendbx-sql-insert-slave`: Adds a new zone from the authoritative DNS server which is currently retrieved via AXFR.
+- `opendbx-sql-insert-record`: Adds new records of a zone form the authoritative DNS server which are currently retrieved via AXFR.
+- `opendbx-sql-update-serial`: Set zone serial to value of last update.
+- `opendbx-sql-update-lastcheck`: Set time of last zone check.
+- `opendbx-sql-master`: Get master record for zone.
+- `opendbx-sql-supermaster`: Get supermaster info.
+- `opendbx-sql-infoslaves`: Get all unfresh slaves.
+- `opendbx-sql-infomasters`: Get all updates masters.
+
+# Database schemas and information
+## Mysql
+The file below also contains trigger definitions which are necessary for [auto serial](backend-generic-sql.md#autoserial)
+support, but they are only available in MySQL 5 and later. If you are still
+using MySQL 4.x and don't want to utilize the automatically generated zone serials,
+you can safely remove the "CREATE TRIGGER" statements from the file before
+creating the database tables.
+
+```
+SET SESSION sql_mode='ANSI';
+
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL AUTO_INCREMENT,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) NOT NULL DEFAULT '',
+ "account" VARCHAR(40) NOT NULL DEFAULT '',
+ "last_check" INTEGER DEFAULT NULL,
+ "notified_serial" INTEGER DEFAULT NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) NOT NULL DEFAULT 'A',
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+) type=InnoDB;
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL AUTO_INCREMENT,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER DEFAULT NULL,
+ "prio" INTEGER DEFAULT NULL,
+ "content" VARCHAR(255) NOT NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON UPDATE CASCADE
+ ON DELETE CASCADE
+) type=InnoDB;
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) NOT NULL DEFAULT ''
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+
+DELIMITER :
+
+CREATE TRIGGER "pdns_trig_records_insert"
+AFTER INSERT ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = NEW."domain_id";
+END;:
+
+CREATE TRIGGER "pdns_trig_records_update"
+AFTER UPDATE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = NEW."domain_id";
+END;:
+
+CREATE TRIGGER "pdns_trig_records_delete"
+AFTER DELETE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = OLD."domain_id";
+END;:
+
+DELIMITER ;
+```
+
+## PostgreSQL
+```
+CREATE TABLE "domains" (
+ "id" SERIAL NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) NOT NULL DEFAULT '',
+ "account" VARCHAR(40) NOT NULL DEFAULT '',
+ "last_check" INTEGER DEFAULT NULL,
+ "notified_serial" INTEGER DEFAULT NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) NOT NULL DEFAULT 'A',
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" SERIAL NOT NULL,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER DEFAULT NULL,
+ "prio" INTEGER DEFAULT NULL,
+ "content" VARCHAR(255) NOT NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON UPDATE CASCADE
+ ON DELETE CASCADE
+);
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) NOT NULL DEFAULT ''
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "domains_id_seq" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+GRANT ALL ON "records_id_seq" TO "powerdns";
+
+CREATE RULE "pdns_rule_records_insert"
+AS ON INSERT TO "records" DO
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1 WHERE "id" = NEW."domain_id";
+
+CREATE RULE "pdns_rule_records_update"
+AS ON UPDATE TO "records" DO
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1 WHERE "id" = NEW."domain_id";
+
+CREATE RULE "pdns_rule_records_delete"
+AS ON DELETE TO "records" DO
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1 WHERE "id" = OLD."domain_id";
+```
+
+## SQLite and SQLite3
+Supported without changes since OpenDBX 1.0.0 but requires to set [`opendbx-host`](#opendbs-host)
+to the path of the SQLite file (including the trailing slash or backslash,
+depending on your operating system) and opendbx-database to the name of the file.
+
+```
+opendbx-host-read = /path/to/file/
+opendbx-host-write = /path/to/file/
+opendbx-database = powerdns.sqlite
+```
+
+### SQLite Schema
+```
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL PRIMARY KEY,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) NOT NULL DEFAULT '',
+ "account" VARCHAR(40) NOT NULL DEFAULT '',
+ "last_check" INTEGER DEFAULT NULL,
+ "notified_serial" INTEGER DEFAULT NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) NOT NULL DEFAULT 'A',
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL PRIMARY KEY,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER DEFAULT NULL,
+ "prio" INTEGER DEFAULT NULL,
+ "content" VARCHAR(255) NOT NULL,
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON UPDATE CASCADE
+ ON DELETE CASCADE
+);
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) NOT NULL DEFAULT ''
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+CREATE TRIGGER "pdns_trig_records_insert"
+AFTER INSERT ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_update"
+AFTER UPDATE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_delete"
+AFTER DELETE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = OLD."domain_id";
+END;
+```
+
+### SQLite3 Schema
+```
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) NOT NULL DEFAULT '',
+ "account" VARCHAR(40) NOT NULL DEFAULT '',
+ "last_check" INTEGER DEFAULT NULL,
+ "notified_serial" INTEGER DEFAULT NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) NOT NULL DEFAULT 'A',
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER DEFAULT NULL,
+ "prio" INTEGER DEFAULT NULL,
+ "content" VARCHAR(255) NOT NULL,
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON UPDATE CASCADE
+ ON DELETE CASCADE
+);
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) NOT NULL DEFAULT ''
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+CREATE TRIGGER "pdns_trig_records_insert"
+AFTER INSERT ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_update"
+AFTER UPDATE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_delete"
+AFTER DELETE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = OLD."domain_id";
+END;
+```
+
+## Firebird/Interbase
+Requires [`opendbx-database`](#opendbx-database) set to the path of the database
+file and doesn't support the default statement for starting transactions. Please
+add the following lines to your pdns.conf:
+
+```
+opendbx-database = /var/lib/firebird2/data/powerdns.gdb
+opendbx-sql-transactbegin = SET TRANSACTION
+```
+
+When creating the database please make sure that you call the `isql` tool with
+the parameter `-page 4096`. Otherwise, you will get an error (key size exceeds
+implementation restriction for index "pdns_unq_domains_name") when creating the tables.
+
+```
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) DEFAULT '' NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL,
+ "last_check" INTEGER,
+ "notified_serial" INTEGER,
+ "auto_serial" INTEGER DEFAULT 0 NOT NULL,
+ "status" CHAR(1) DEFAULT 'A' NOT NULL,
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE GENERATOR "pdns_gen_domains_id";
+
+SET TERM !!;
+CREATE TRIGGER "pdns_trig_domains_id" FOR "domains"
+ACTIVE BEFORE INSERT AS
+BEGIN
+ IF (NEW."id" IS NULL) THEN
+ NEW."id" = GEN_ID("pdns_gen_domains_id",1);
+END !!
+SET TERM ;!!
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER DEFAULT NULL,
+ "prio" INTEGER DEFAULT NULL,
+ "content" VARCHAR(255) NOT NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON UPDATE CASCADE
+ ON DELETE CASCADE
+);
+
+CREATE GENERATOR "pdns_gen_records_id";
+
+SET TERM !!;
+CREATE TRIGGER "pdns_trig_records_id" FOR "records"
+ACTIVE BEFORE INSERT AS
+BEGIN
+ IF (NEW."id" IS NULL) THEN
+ NEW."id" = GEN_ID("pdns_gen_records_id",1);
+END !!
+SET TERM ;!!
+
+CREATE INDEX "idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+
+SET TERM !!;
+
+CREATE TRIGGER "pdns_trig_records_insert" FOR "records"
+ACTIVE AFTER INSERT AS
+BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = NEW."domain_id";
+END !!
+
+CREATE TRIGGER "pdns_trig_records_update" FOR "records"
+ACTIVE AFTER UPDATE AS
+BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = NEW."domain_id";
+END !!
+
+CREATE TRIGGER "pdns_trig_records_delete" FOR "records"
+ACTIVE AFTER DELETE AS
+BEGIN
+ UPDATE "domains" d SET d."auto_serial" = d."auto_serial" + 1
+ WHERE d."id" = OLD."domain_id";
+END !!
+
+SET TERM ;!!
+```
+
+## Microsoft SQL Server
+Supported using the FreeTDS library. It uses a different scheme for host
+configuration (requires the name of the host section in the configuration file
+of the dblib client library) and doesn't support the default statement for
+starting transactions. Please add the following lines to your pdns.conf:
+
+```
+opendbx-host-read = MSSQL2k
+opendbx-host-write = MSSQL2k
+opendbx-sql-transactbegin = BEGIN TRANSACTION
+```
+
+```
+SET quoted_identifier ON;
+
+
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL IDENTITY,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) DEFAULT '' NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL,
+ "last_check" INTEGER NULL,
+ "notified_serial" INTEGER NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) DEFAULT 'A' NOT NULL,
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL IDENTITY,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER NULL,
+ "prio" INTEGER NULL,
+ "content" VARCHAR(255) NOT NULL,
+ "change_date" INTEGER NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+);
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX "pdns_idx_smip_smns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+
+CREATE TRIGGER "pdns_trig_records_insert"
+ON "records" FOR INSERT AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT i."domain_id" FROM "inserted" i GROUP BY i."domain_id"
+ );
+
+CREATE TRIGGER "pdns_trig_records_update"
+ON "records" FOR UPDATE AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT i."domain_id" FROM "inserted" i GROUP BY i."domain_id"
+ );
+
+CREATE TRIGGER "pdns_trig_records_delete"
+ON "records" FOR DELETE AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT d."domain_id" FROM "deleted" d GROUP BY d."domain_id"
+ );
+```
+
+## Sybase ASE
+Supported using the native Sybase ctlib or the FreeTDS library. It uses a
+different scheme for host configuration (requires the name of the host section
+in the configuration file of the ctlib client library) and doesn't support the
+default statement for starting transactions. Please add the following lines to
+your pdns.conf:
+
+```
+opendbx-host-read = SYBASE
+opendbx-host-write = SYBASE
+opendbx-sql-transactbegin = BEGIN TRANSACTION
+```
+
+```
+SET quoted_identifier ON;
+
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL IDENTITY,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) DEFAULT '' NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL,
+ "last_check" INTEGER NULL,
+ "notified_serial" INTEGER NULL,
+ "auto_serial" INTEGER NOT NULL DEFAULT 0,
+ "status" CHAR(1) DEFAULT 'A' NOT NULL,
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL IDENTITY,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER NULL,
+ "prio" INTEGER NULL,
+ "content" VARCHAR(255) NOT NULL,
+ "change_date" INTEGER NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+);
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) DEFAULT '' NOT NULL
+);
+
+CREATE INDEX "pdns_idx_smip_smns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+
+CREATE TRIGGER "pdns_trig_records_insert"
+ON "records" FOR INSERT AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT i."domain_id" FROM "inserted" i GROUP BY i."domain_id"
+ );
+
+CREATE TRIGGER "pdns_trig_records_update"
+ON "records" FOR UPDATE AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT i."domain_id" FROM "inserted" i GROUP BY i."domain_id"
+ );
+
+CREATE TRIGGER "pdns_trig_records_delete"
+ON "records" FOR DELETE AS
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = ANY (
+ SELECT d."domain_id" FROM "deleted" d GROUP BY d."domain_id"
+ );
+```
+
+## Oracle
+Uses a different syntax for transactions and requires the following additional
+line in your pdns.conf:
+
+```
+opendbx-sql-transactbegin = SET TRANSACTION NAME 'AXFR'
+```
+
+```
+CREATE TABLE "domains" (
+ "id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "master" VARCHAR(40) DEFAULT '',
+ "account" VARCHAR(40) DEFAULT '',
+ "last_check" INTEGER,
+ "notified_serial" INTEGER,
+ "auto_serial" INTEGER DEFAULT 0,
+ "status" CHAR(1) DEFAULT 'A',
+CONSTRAINT "pdns_pk_domains_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_unq_domains_name"
+ UNIQUE ("name")
+);
+
+CREATE SEQUENCE "pdns_seq_domains_id" START WITH 1 INCREMENT BY 1;
+
+CREATE TRIGGER "pdns_trig_domains_id"
+BEFORE INSERT ON "domains"
+FOR EACH ROW
+BEGIN
+ SELECT "pdns_seq_domains_id".nextval INTO :NEW."id" FROM dual;
+END;
+
+CREATE INDEX "pdns_idx_domains_status_type" ON "domains" ("status","type");
+
+CREATE TABLE "records" (
+ "id" INTEGER NOT NULL,
+ "domain_id" INTEGER NOT NULL,
+ "name" VARCHAR(255) NOT NULL,
+ "type" VARCHAR(6) NOT NULL,
+ "ttl" INTEGER NULL,
+ "prio" INTEGER NULL,
+ "content" VARCHAR(255) NOT NULL,
+ "change_date" INTEGER NULL,
+CONSTRAINT "pdns_pk_records_id"
+ PRIMARY KEY ("id"),
+CONSTRAINT "pdns_fk_records_domainid"
+ FOREIGN KEY ("domain_id")
+ REFERENCES "domains" ("id")
+ ON DELETE CASCADE
+);
+
+CREATE SEQUENCE "pdns_seq_records_id" START WITH 1 INCREMENT BY 1;
+
+CREATE TRIGGER "pdns_trig_records_id"
+BEFORE INSERT ON "records"
+FOR EACH ROW
+BEGIN
+ SELECT "pdns_seq_records_id".nextval INTO :NEW."id" FROM dual;
+END;
+
+CREATE INDEX "pdns_idx_records_name_type" ON "records" ("name","type");
+CREATE INDEX "pdns_idx_records_type" ON "records" ("type");
+
+CREATE TABLE "supermasters" (
+ "ip" VARCHAR(40) NOT NULL,
+ "nameserver" VARCHAR(255) NOT NULL,
+ "account" VARCHAR(40) NOT NULL
+);
+
+CREATE INDEX "pdns_idx_smaster_ip_ns" ON "supermasters" ("ip","nameserver");
+
+GRANT SELECT ON "supermasters" TO "powerdns";
+GRANT ALL ON "domains" TO "powerdns";
+GRANT ALL ON "records" TO "powerdns";
+
+CREATE TRIGGER "pdns_trig_records_insert"
+AFTER INSERT ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = :NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_update"
+AFTER UPDATE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = :NEW."domain_id";
+END;
+
+CREATE TRIGGER "pdns_trig_records_delete"
+AFTER DELETE ON "records"
+FOR EACH ROW BEGIN
+ UPDATE "domains" SET "auto_serial" = "auto_serial" + 1
+ WHERE "id" = :OLD."domain_id";
+END;
+```
--- /dev/null
+# Oracle backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes|
+|Slave|Yes|
+|Superslave|Yes|
+|Autoserial|Yes|
+|DNSSEC|Yes|
+|Comments|No|
+|Module name|oracle|
+|Launch name|oracle|
+
+This is the Oracle Database backend, completely rewritten for the 3.0 release, with easily configurable SQL statements, allowing you to graft PowerDNS functionality onto any Oracle database of your choosing.
+
+The Oracle backend is difficult, and possibly illegal, to distribute in binary form. To use it, you will probably need to compile PowerDNS from source. OCI headers are expected in `$ORACLE_HOME/rdbms/public`, and OCI libraries in `$ORACLE_HOME/lib`. That is where they should be with a working installation of the full Oracle Database client. Oracle InstantClient should work as well, but you will need to make the libraries and headers available in appropriate paths.
+
+This backend uses two kinds of database connections. First, it opens a session pool. Connections from this pool are used only for queries reading DNS data from the database. Second, it opens normal (non-pooled) connections on demand for any kind of write access. The reason for this split is to allow redundancy by replication. Each DNS frontend server can have a local read-only replicated instance of your database. Open the session pool to the local replicated copy, and all data will be available with high performance, even if the main database goes down. The writing connections should go directly to the main database.
+
+Of course, if you do not require this kind of redundancy, or want to avoid the substantial Oracle Database licensing costs, all connections can just go to the same database with the same credentials. Also, the write connections should be entirely unnecessary if you do not plan to use either master or slave mode.
+
+## Configuration Parameters
+### `oracle-pool-database`, `oracle-pool-username`, `oracle-pool-password`
+The database to use for read access. OracleBackend will try to create a session pool, so make sure this database user has the necessary permissions. If your connection requires environment variables to be set, e.g. `ORACLE_HOME`, `NLS_LANG`, or `LD_LIBRARY_PATH`, make sure these are set when PowerDNS runs. `/etc/default/pdns` might help.
+
+### `oracle-master-database`, `oracle-master-username`, `oracle-master-password`
+The database to use for write access. These are normal connections, not a session pool. The backend may open more than one at a time.
+
+### `oracle-session-min`, `oracle-session-max`, `oracle-session-inc`
+Parameters for the connection pool underlying the session pool. OCI will open `session-min` connections at startup, and open more connections as needed, `session-inc` at a time, until `session-max` connections are open.
+
+### `oracle-nameserver-name`
+This can be set to an arbitrary string that will be made available in the optional bind variable `:nsname` for all SQL statements. You can use this to run multiple PowerDNS instances off the same database, while serving different zones.
+
+There are many more options that are used to define the different SQL statements. These will be discussed after the reference database schema has been explained.
+
+## The Database Schema
+You can find an example database schema in `schema.sql` in the PowerDNS source distribution. It is intended more as a starting point to come up with a schema that works well for your organisation, than as something you should run as it is. As long as the semantics of the SQL statements still work out, you can store your DNS data any way you like.
+
+You should read this while having `schema.sql` to hand. Columns will not be specifically explained where their meaning is obvious.
+
+**Note**: All FQDNs should be specified in lower case and without a trailing dot. Where things are lexicographically compared or sorted, make sure a sane ordering is used. `'NLS_LANG=AMERICAN_AMERICA.AL32UTF8'` should generally work well enough; when in doubt, enforce a plain ordering with `"NLSSORT(value, 'NLS_SORT = BINARY')"`.
+
+### Zones Table
+This table lists the zones for which PowerDNS is supposed to be an authoritative nameserver, plus a small amount of information related to master/slave mode.
+
+#### name
+The FQDN of the zone apex, e.g. 'example.com'.
+
+#### type
+Describes how PowerDNS should host the zone. Valid values are 'NATIVE', 'MASTER', and 'SLAVE'. PowerDNS acts as an authoritative nameserver for the zone in all modes. In slave mode, it will additionally attempt to acquire the zone's content from a master server. In master mode, it will additionally send 'NOTIFY' packets to other nameservers for the zone when its content changes.
+
+**Tip**: There is a global setting to make PowerDNS send 'NOTIFY' packets in slave mode.
+
+#### last\_check
+This value, updated by PowerDNS, is the unix timestamp of the last successful attempt to check this zone for freshness on the master.
+
+#### refresh
+The number of seconds PowerDNS should wait after a successful freshness check before performing another one. This value is also found in the zone's SOA record. You may want to make sure to put the same thing in both places.
+
+#### serial
+The serial of the version of the zone's content we are hosting now. This value is also found in the zone's SOA record. You may want to make sure to put the same thing in both places.
+
+#### notified\_serial
+The latest serial for which we have sent `NOTIFY` packets. Updated by PowerDNS.
+
+### The Zonemasters and ZoneAlsoNotify Tables
+These are lists of hosts PowerDNS will interact with for a zone in master/slave mode. 'Zonemasters' lists the hosts PowerDNS will attempt to pull zone transfers from, and accept 'NOTIFY' packets from. 'ZoneAlsoNotify' lists hosts PowerDNS will send 'NOTIFY' packets to, in addition to any hosts that have NS records.
+
+Host entries can be IPv4 or IPv6 addresses, in string representation. If you need to specify a port, use `192.0.2.4:5300` notation for IPv4 and brackets for IPv6: `[2001:db8::1234]:5300`.
+
+### The Supermasters Table
+In superslave mode, PowerDNS can accept 'NOTIFY' packets for zones that have not been defined in the zone table yet. PowerDNS will then create an entry for the zone and attempt a zone transfer. This table defines the list of acceptable sources for supernotifications.
+
+#### name
+An identifying string for this entry. Only used for logging.
+
+#### ip
+The alleged originating IP address of the notification.
+
+#### nameserver
+The FQDN of an authoritative nameserver.
+
+A supernotification will be accepted if an entry is found such that the notification came from 'ip' and 'nameserver' appears in an NS record for that zone.
+
+### The ZoneMetadata Table
+This is a per-zone key-value store for various things PowerDNS needs to know that are not part of the zone's content or handled by other tables. Depending on your needs, you may not want this to exist as an actual table, but simulate this in PL/SQL instead.
+
+The currently defined metadata types are:
+
+#### 'PRESIGNED'
+If set to 1, PowerDNS should assume that DNSSEC signatures for this zone exist in the database and use them instead of signing records itself. For a slave zone, this will also signal to the master that we want DNSSEC records when attempting a zone transfer.
+
+#### 'NSEC3PARAM'
+The NSEC3 hashing parameters for the zone.
+
+#### 'TSIG-ALLOW-AXFR'
+The value is the name of a TSIG key. A client will be allowed to AXFR from us if the request is signed with that key.
+
+#### 'AXFR-MASTER-TSIG'
+The value is the name of a TSIG key. Outgoing `NOTIFY` packets for this zone will be signed with that key.
+
+### The Tables for Cryptographic Keys
+We have two of them: 'TSIGKeys' for symmetric TSIG keys, and 'ZoneDNSKeys' for DNSSEC signing keys.
+
+### The Records Table
+The actual DNS zone contents are stored here.
+
+#### zone\_id
+The zone this records belongs to. Normally, this is obvious. When you are dealing with zone delegations, you have to insert some records into the parent zone of their actual zone. See also `auth`.
+
+#### fqdn
+The owner name of this record. Again, this is lower case and without a trailing dot.
+
+#### revfqdn
+This should be a string that consists of the labels of the owner name, in reverse order, with spaces instead of dots separating them, for example:
+
+```
+'www.example.com' => 'com example www'
+```
+
+This is used as a quick and dirty way to get canonical zone ordering. You can chose a more correct and much more complicated implementation instead if you prefer. In the reference schema, this is automatically set by a trigger.
+
+#### fqdnhash
+The NSEC3 hash of the owner name. The reference schema provides code and a trigger to calculate this, but they are not production quality. The recommendation is to load the dnsjava classes into your database and use their facilities for dealing with DNS names and NSEC3 hashes.
+
+#### ttl
+The TTL for the record set. This should be the same for all members of a record set, but PowerDNS will quietly use the minimum if it encounters different values.
+
+#### type
+The type of the record, as a canonical identification string, e.g. 'AAAA' or 'MX'. You can set this and 'content' NULL to indicate a name that exists, but doesn't carry any record (a so called empty non-terminal) for NSEC/NSEC3 ordering purposes.
+
+#### content
+The data part of the DNS record, in canonical string representation, except that if this includes FQDNs, they should be specified without a trailing dot.
+
+#### last\_change
+The unix timestamp of the last change to this record. Used only for the deprecated autoserial feature. You can omit this unless you want to use that feature.
+
+#### auth
+0 or 1 depending on whether this record is an authoritative member of the zone specified in `zone_id`. These are the rules for determining that: A record is an authoritative member of the zone its owner name belongs to, except for DS records, which are authoritative members of the parent zone. Delegation records, that is, NS records and related A/AAAA glue records, are additionally non-authoritative members of the parent zone.
+
+PowerDNS has a function to automatically set this. OracleBackend doesn't support that. Do it in the database.
+
+### The SQL Statements
+#### Fetching DNS records
+There are five queries to do this. They all share the same set of return columns:
+
+* fqdn: The owner name of the record.
+* ttl: The TTL of the record set.
+* type: The type of the record.
+* content: The content of the record.
+* zone\_id: The numerical identifier of the zone the record belongs to. A record can belong to two zones (delegations/glue), in which case it may be returned twice.
+* last\_change: The unix timestamp of the last time this record was changed. Can safely be set as a constant 0, unless you use the autoserial feature.
+* auth: 1 or 0 depending on the zone membership (authoritative or not).
+
+Record sets (records for the same name of the same type) must appear consecutively, which means **ORDER BY** clauses are needed in some places. Empty non-terminals should be suppressed.
+
+The queries differ in which columns are restricted by 'WHERE' clauses:
+
+##### oracle-basic-query
+Looking for records based on owner name and type. Default:
+
+```
+SELECT fqdn, ttl, type, content, zone_id, last_change, auth
+FROM Records
+WHERE type = :type AND fqdn = lower(:name)
+```
+
+##### oracle-basic-id-query
+Looking for records from one zone based on owner name and type. Default:
+
+```
+SELECT fqdn, ttl, type, content, zone_id, last_change, auth
+FROM Records
+WHERE type = :type AND fqdn = lower(:name) AND zone_id = :zoneid
+```
+
+##### oracle-any-query
+Looking for records based on owner name. Default:
+
+```
+SELECT fqdn, ttl, type, content, zone_id, last_change, auth
+FROM Records
+WHERE fqdn = lower(:name)
+ AND type IS NOT NULL
+ORDER BY type
+```
+
+##### oracle-any-id-query
+Looking for records from one zone based on owner name. Default:
+
+```
+SELECT fqdn, ttl, type, content, zone_id, last_change, auth
+FROM Records
+WHERE fqdn = lower(:name)
+ AND zone_id = :zoneid
+ AND type IS NOT NULL
+ORDER BY type
+```
+
+##### oracle-list-query
+Looking for all records from one zone. Default:
+
+```
+SELECT fqdn, ttl, type, content, zone_id, last_change, auth
+FROM Records
+WHERE zone_id = :zoneid
+ AND type IS NOT NULL
+ORDER BY fqdn, type
+```
+
+#### Zone Metadata and TSIG
+
+##### oracle-get-zone-metadata-query
+Fetch the content of the metadata entries of type ':kind' for the zone called ':name', in their original order. Default:
+
+```
+SELECT md.meta_content
+FROM Zones z JOIN ZoneMetadata md ON z.id = md.zone_id
+WHERE z.name = lower(:name) AND md.meta_type = :kind
+ORDER BY md.meta_ind
+```
+
+##### oracle-del-zone-metadata-query
+Delete all metadata entries of type ':kind' for the zone called ':name'. You can skip this if you do not plan to manage zones with the `pdnsutil` tool. Default:
+
+```
+DELETE FROM ZoneMetadata md
+WHERE zone_id = (SELECT id FROM Zones z WHERE z.name = lower(:name))
+AND md.meta_type = :kind
+```
+
+##### oracle-set-zone-metadata-query
+Create a metadata entry. You can skip this if you do not plan to manage zones with the `pdnsutil` tool. Default:
+
+```
+INSERT INTO ZoneMetadata (zone_id, meta_type, meta_ind, meta_content)
+VALUES (
+ (SELECT id FROM Zones WHERE name = lower(:name)),
+ :kind, :i, :content
+)
+```
+
+##### oracle-get-tsig-key-query
+Retrieved the TSIG key specified by ':name'. Default:
+
+```
+SELECT algorithm, secret
+FROM TSIGKeys
+WHERE name = :name
+```
+
+#### DNSSEC
+##### oracle-get-zone-keys-query
+Retrieve the DNSSEC signing keys for a zone. Default:
+
+```
+SELECT k.id, k.flags, k.active, k.keydata
+FROM ZoneDNSKeys k JOIN Zones z ON z.id = k.zone_id
+WHERE z.name = lower(:name)
+```
+
+##### oracle-del-zone-key-query
+Delete a DNSSEC signing key. You can skip this if you do not plan to manage zones with the `pdnsutil` tool. Default:
+
+```
+DELETE FROM ZoneDNSKeys WHERE id = :keyid
+```
+
+##### oracle-add-zone-key-query
+Add a DNSSEC signing key. You can skip this if you do not plan to manage zones with the `pdnsutil` tool. Default:
+
+```
+INSERT INTO ZoneDNSKeys (id, zone_id, flags, active, keydata) "
+VALUES (
+ zonednskeys_id_seq.NEXTVAL,
+ (SELECT id FROM Zones WHERE name = lower(:name)),
+ :flags,
+ :active,
+ :content
+) RETURNING id INTO :keyid
+```
+
+##### oracle-set-zone-key-state-query
+Enable or disable a DNSSEC signing key. You can skip this if you do not plan to manage zones with the **pdnsutil** tool. Default:
+
+```
+UPDATE ZoneDNSKeys SET active = :active WHERE id = :keyid
+```
+
+##### oracle-prev-next-name-query
+Determine the predecessor and successor of an owner name, in canonical zone ordering. See the reference implementation for the quick and dirty way, and the RFCs for the full definition of canonical zone ordering.
+
+This statement is a PL/SQL block that writes into two of the bind variables, not a query.
+
+Default:
+
+```
+BEGIN
+ get_canonical_prev_next(:zoneid, :name, :prev, :next);
+END;
+```
+
+##### oracle-prev-next-hash-query
+Given an NSEC3 hash, this call needs to return its predecessor and successor in NSEC3 zone ordering into `:prev` and `:next`, and the FQDN of the predecessor into `:unhashed`. Default:
+
+```
+BEGIN
+ get_hashed_prev_next(:zoneid, :hash, :unhashed, :prev, :next);
+END;
+```
+
+#### Incoming AXFR
+
+#####oracle-zone-info-query
+Get some basic information about the named zone before doing master/slave things. Default:
+
+```
+SELECT id, name, type, last_check, serial, notified_serial
+FROM Zones
+WHERE name = lower(:name)
+```
+
+##### oracle-delete-zone-query
+Delete all records for a zone in preparation for an incoming zone transfer. This happens inside a transaction, so if the transfer fails, the old zone content will still be there. Default:
+
+```
+DELETE FROM Records WHERE zone_id = :zoneid
+```
+
+##### oracle-insert-record-query
+Insert a record into the zone during an incoming zone transfer. This happens inside the same transaction as delete-zone, so we will not end up with a partially transferred zone. Default:
+
+```
+INSERT INTO Records (id, fqdn, zone_id, ttl, type, content)
+VALUES (records_id_seq.NEXTVAL, lower(:name), :zoneid, :ttl, :type, :content)
+```
+
+##### oracle-finalize-axfr-query
+A block of PL/SQL to be executed after a zone transfer has successfully completed, but before committing the transaction. A good place to locate empty non-terminals, set the `auth` bit and NSEC3 hashes, and generally do any post-processing your schema requires. The do-nothing default:
+
+```
+DECLARE
+ zone_id INTEGER := :zoneid;
+BEGIN
+ NULL;
+END;
+```
+
+#### Master/Slave Stuff
+
+##### oracle-unfresh-zones-query
+Return a list of zones that need to be checked and their master servers. Return multiple rows, identical except for the master address, for zones with more than one master. Default:
+
+```
+SELECT z.id, z.name, z.last_check, z.serial, zm.master
+FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id
+WHERE z.type = 'SLAVE'
+ AND (z.last_check IS NULL OR z.last_check + z.refresh < :ts)
+ORDER BY z.id
+```
+
+##### oracle-zone-set-last-check-query
+Set the last check timestamp after a successful check. Default:
+
+```
+UPDATE Zones SET last_check = :lastcheck WHERE id = :zoneid
+```
+
+##### oracle-updated-masters-query
+Return a list of zones that need to have `NOTIFY` packets sent out. Default:
+
+```
+SELECT id, name, serial, notified_serial
+FROM Zones
+WHERE type = 'MASTER'
+AND (notified_serial IS NULL OR notified_serial < serial)
+```
+
+##### oracle-zone-set-notified-serial-query
+Set the last notified serial after packets have been sent. Default:
+
+```
+UPDATE Zones SET notified_serial = :serial WHERE id = :zoneid
+```
+
+##### oracle-also-notify-query
+Return a list of hosts that should be notified, in addition to any nameservers in the NS records, when sending `NOTIFY` packets for the named zone. Default:
+
+```
+SELECT an.hostaddr
+FROM Zones z JOIN ZoneAlsoNotify an ON z.id = an.zone_id
+WHERE z.name = lower(:name)
+```
+
+##### oracle-zone-masters-query
+Return a list of masters for the zone specified by id. Default:
+
+```
+SELECT master
+FROM Zonemasters
+WHERE zone_id = :zoneid
+```
+
+##### oracle-is-zone-master-query
+Return a row if the specified host is a registered master for the named zone. Default:
+
+```
+SELECT zm.master
+FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id
+WHERE z.name = lower(:name) AND zm.master = :master
+```
+
+#### Superslave Stuff
+##### oracle-accept-supernotification-query
+If a supernotification should be accepted from ':ip', for the master nameserver ':ns', return a label for this supermaster. Default:
+
+```
+SELECT name
+FROM Supermasters
+WHERE ip = :ip AND nameserver = lower(:ns)
+```
+
+##### oracle-insert-slave-query
+A supernotification has just been accepted, and we need to create an entry for the new zone. Default:
+
+```
+INSERT INTO Zones (id, name, type)
+VALUES (zones_id_seq.NEXTVAL, lower(:zone), 'SLAVE')
+RETURNING id INTO :zoneid
+```
+
+##### oracle-insert-master-query
+We need to register the first master server for the newly created zone. Default:
+
+```
+INSERT INTO Zonemasters (zone_id, master)
+VALUES (:zoneid, :ip)
+```
--- /dev/null
+# Pipe Backend
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|No|
+|Slave|No|
+|Superslave|No|
+|Autoserial|No|
+|Case|Depends|
+|DNSSEC|Partial, no delegation, no key storage|
+|Disabled data|No|
+|Comments|No|
+|Module name|pipe|
+|Launch name|pipe|
+
+The PipeBackend allows for easy dynamic resolution based on a 'Coprocess' which can be written in any programming language that can read a question on standard input and answer on standard output.
+
+The PipeBackend is primarily meant for allowing rapid development of new backends without tight integration with PowerDNS.
+It allows end-users to write PowerDNS backends in any language, a perl sample is provided.
+The PipeBackend is also very well suited for dynamic resolution of queries.
+Example applications include DNS based load balancing, geo-direction, DNS-based failover with low TTLs.
+
+**Note**: The [Remote Backend](backend-remote.md) offers a superset of the functionality of the PipeBackend.
+
+**Note**: Please do read the [Backend Writer' guide](../appendix/backend-writers-guide.md) carefully.
+The PipeBackend, like all other backends, must not do any DNS thinking, but answer all questions (INCLUDING THE ANY QUESTION) faithfully.
+Specifically, the queries that the PipeBackend receives will not correspond to the queries that arrived over DNS.
+So, a query for an AAAA record may turn into a backend query for an ANY record.
+There is nothing that can or should be done about this.
+
+# Configuration Parameters
+## `pipe-abi-version`
+| | |
+|:-|:-|
+|Type|Integer|
+|Default|1|
+|Mandatory|No|
+
+This is the version of the question format that is sent to the co-process ([`pipe-command`](#pipe-command)) for the pipe backend.
+
+If not set the default `pipe-abi-version` is 1.
+When set to 2, the local-ip-address field is added after the remote-ip-address, the local-ip-address refers to the IP address the question was received on.
+When set to 3, the real remote IP/subnet is added based on edns-subnet support (this also requires enabling [`edns-subnet-processing`](settings.md#edns-subnet-processing)).
+When set to 4 it sends zone name in AXFR request. See also [PipeBackend Protocol](#pipebackend-protocol) below.
+
+## `pipe-command`
+| | |
+|:-|:-|
+|Type|String|
+|Mandatory|Yes|
+
+Command to launch as backend or the path to a unix domain socket file.
+The socket should already be open and listening before PowerDNS starts.
+
+## `pipe-timeout`
+| | |
+|:-|:-|
+|Type|Integer|
+|Default|2000|
+
+Number of milliseconds to wait for an answer from the backend.
+If this time is ever exceeded, the backend is declared dead and a new process is spawned.
+
+## `pipe-regex`
+| | |
+|:-|:-|
+|Type|String (a regex)|
+
+If set, only questions matching this regular expression are even sent to the backend.
+This makes sure that most of PowerDNS does not slow down if you you deploy a slow backend.
+A query for 'www.powerdns.com' would be presented to the regex as 'www.powerdns.com', a matching regex would be `^www\.powerdns\.com$`.
+**Note**: to match the root domain, use a dot, e.g. `^\.$`
+
+# PipeBackend protocol
+Questions come in over a file descriptor, by default standard input.
+Answers are sent out over another file descriptor, standard output by default.
+Questions and answers are terminated by single newline (`\n`) characters.
+Fields in lines must be seperated by tab ('\t') characters.
+
+## Handshake
+PowerDNS sends out `HELO\t1`, indicating that it wants to speak the protocol as defined in this document, version 1.
+For abi-version 2 or 3, PowerDNS sends `HELO\t2` or `HELO\t3`.
+A PowerDNS Coprocess must then send out a banner, prefixed by `OK\t`, indicating it launched successfully.
+If it does not support the indicated version, it should respond with `FAIL`, but not exit.
+Suggested behaviour is to try and read a further line, and wait to be terminated.
+
+**Note**: fields are separated by a tab ('\t') character, even though they are displayed with spaces in this document.
+
+
+## `Q`: Regular queries for data
+The question format, for type Q questions.
+
+### pipe-abi-version = 1 [default]
+```
+Q qname qclass qtype id remote-ip-address
+```
+
+### pipe-abi-version = 2
+```
+Q qname qclass qtype id remote-ip-address local-ip-address
+```
+
+### pipe-abi-version = 3
+```
+Q qname qclass qtype id remote-ip-address local-ip-address edns-subnet-address
+```
+
+Fields are tab separated, and terminated with a single `\n`.
+The `remote-ip-address` is the IP address of the nameserver asking the question, the `local-ip-address` is the IP address on which the question was received.
+
+Type is the tag above, `qname` is the domain the question is about.
+`qclass` is always 'IN' currently, denoting an INternet question.
+`qtype` is the kind of information desired, the record type, like A, CNAME or AAAA.
+`id` can be specified to help your backend find an answer if the `id` is already known from an earlier query.
+You can ignore it unless you want to support `AXFR`.
+
+`edns-subnet-address` is the actual client subnet as provided via edns-subnet support.
+Note that for the SOA query that precedes an AXFR, edns-subnet is always set to 0.0.0.0/0.
+
+**Note**: Queries for wildcard names should be answered literally, without expansion.
+So, if a backend gets a question for "*.powerdns.com", it should only answer with data if there is an actual "*.powerdns.com" name.
+
+**Note**: In some (broken) network setups, the `remote-ip-address` and/or `local-ip-address`, when it is an IPv6 address, may be suffixed with a `%` and
+the name of the network interface (e.g. `%eth1`).
+Keep this in mind when checking the IP addresses.
+
+## `AXFR`: List an entire zone
+AXFR-queries look like this:
+
+```
+AXFR id zone-name
+```
+
+The `id` is gathered from the answer to a SOA query. `zone-name` is given in ABI version 4.
+
+## Answers
+Each answer starts with a tag, possibly followed by a TAB and more data.
+
+* `DATA`: Indicating a successful line of DATA.
+* `END`: Indicating the end of an answer - no further data.
+* `FAIL`: Indicating a lookup failure. Also serves as 'END'. No further data.
+* `LOG`: For specifying things that should be logged. Can only be sent after a query and before an END line. After the tab, the message to be logged.
+
+### ABI version 1 and 2
+So, letting it be known that there is no data consists of sending 'END' without anything else.
+The answer format (for abi-version 1 and 2):
+
+```
+DATA qname qclass qtype ttl id content
+```
+
+Again, all fields are tab-separated.
+
+`content` is as specified in [Types](../types.md).
+For MX and SRV, content consists of the priority, followed by a tab, followed by the actual content.
+
+A sample dialogue may look like this (note that in reality, almost all queries will actually be for the ANY qtype):
+
+```
+Q www.example.org IN CNAME -1 203.0.113.210
+DATA www.example.org IN CNAME 3600 1 ws1.example.org
+END
+Q ws1.example.org IN CNAME -1 203.0.113.210
+END
+Q wd1.example.org IN A -1 203.0.113.210
+DATA ws1.example.org IN A 3600 1 192.0.2.4
+DATA ws1.example.org IN A 3600 1 192.0.2.5
+DATA ws1.example.org IN A 3600 1 192.0.2.6
+END
+```
+
+This would correspond to a remote webserver 203.0.113.210 wanting to resolve the IP address of www.example.org, and PowerDNS traversing the CNAMEs to find the IP addresses of ws1.example.org.
+Another dialogue might be:
+
+```
+Q example.org IN SOA -1 203.0.113.210
+DATA example.org IN SOA 86400 1 ahu.example.org ...
+END
+AXFR 1
+DATA example.org IN SOA 86400 1 ahu.example.org ...
+DATA example.org IN NS 86400 1 ns1.example.org
+DATA example.org IN NS 86400 1 ns2.example.org
+DATA ns1.example.org IN A 86400 1 203.0.113.210
+DATA ns2.example.org IN A 86400 1 63.123.33.135
+.
+.
+END
+```
+
+This is a typical zone transfer.
+
+### ABI version 3 and higher
+
+For abi-version 3, DATA-responses get two extra fields:
+
+```
+DATA scopebits auth qname qclass qtype ttl id content
+```
+
+`scopebits` indicates how many bits from the subnet provided in the question (originally from edns-subnet) were used in determining this answer.
+This can aid caching (although PowerDNS does not currently use this value).
+
+The `auth` field indicates whether this response is authoritative, this is for DNSSEC.
+The `auth` field should be set to '1' for data for which the zone itself is authoritative, which includes the SOA record and its own NS records.
+The `auth` field should be 0 for NS records which are used for delegation, and also for any glue (A, AAAA) records present for this purpose. Do note that the DS record for a secure delegation should be authoritative!
+
+For abi-versions 1 and 2, the two new fields fall back to default values.
+The default value for scopebits is 0.
+The default for auth is 1 (meaning authoritative).
+
+## Direct backend commands
+With abi-version 5 you can use [backend-cmd](dnssec.md#pdnsutil) for executing commands on your backend.
+PowerDNS will use the following query/answer format:
+
+```
+CMD Whatever you wrote
+Answer goes here
+And can be multiple lines
+until we see
+END
+```
+
+# Sample backends
+
+* [ABI version 1](https://raw.githubusercontent.com/PowerDNS/pdns/master/modules/pipebackend/backend.pl)
+* [ABI version 3](https://raw.githubusercontent.com/PowerDNS/pdns/master/modules/pipebackend/backend-v3.pl)
+* [ABI version 5](https://raw.githubusercontent.com/PowerDNS/pdns/master/modules/pipebackend/backend-v5.pl)
--- /dev/null
+# Random Backend
+
+* Native: Yes
+* Master: No
+* Slave: No
+* Superslave: No
+* Autoserial: No
+* Case: Depends
+* DNSSEC: Yes, no key storage
+* Disabled data: No
+* Comments: No
+* Module name: built in
+* Launch: random
+
+This is a very silly backend which is discussed in the [Backends writer's guide](../appendix/backend-writers-guide.md#simple-backends) as a demonstration on how to write a PowerDNS backend.
+
+This backend knows about only one hostname, and only about its IP address at that. With every query, a new random IP address is generated.
+
+It only makes sense to load the random backend in combination with a regular backend. This can be done by prepending it to the [`launch`](settings.md#launch) instruction, such as `launch=random,gmysql`.
+
+## Configuration Parameters
+### `random-hostname`
+* String
+
+Hostname for which to supply a random IP address.
--- /dev/null
+# Remote Backend
+**Warning**: The Remote Backend is available since PowerDNS Authoritative Server 3.2. This backend is stable on version 3.3, not before.
+
+| | |
+|:--|:--|
+|Native|Yes|
+|Master|Yes*|
+|Slave|Yes*|
+|Superslave|Yes*|
+|Autoserial|Yes*|
+|DNSSEC|Yes*|
+|Multiple instances|Yes|
+
+\* If provided by the responder (your script).
+
+This backend provides Unix socket, Pipe, HTTP and ZeroMQ remoting for powerdns. You should think this as normal RPC thin client, which converts native C++ calls into JSON/RPC and passes them to you via connector.
+
+## Important notices
+Please do not use remotebackend shipped before version 3.3. This version has severe bug that can crash the entire process.
+
+There is a breaking change on v4.0 and later. Before version 4.0, the DNS names passed in queries were without trailing dot, after version 4.0 the DNS names are sent with trailing dot. F.ex. example.org is now sent as example.org.
+
+In some (broken) network setups, the IP addresses provided in the request (when
+this is an IPv6 address) may be suffixed with a `%` and the name of the network
+interface (e.g. `%eth1`). Keep this in mind when checking the IP addresses.
+
+## Compiling
+To compile this backend, you need to configure `--with-modules="remote"`.
+
+For versions prior to 3.4.0, if you want to use http connector, you need libcurl and use `--enable-remotebackend-http`.
+
+If you want to use ZeroMQ connector, you need libzmq-dev or libzmq3-dev and use `--enable-remotebackend-zeromq`.
+
+## Usage
+The only configuration options for backend are remote-connection-string and remote-dnssec.
+
+```
+remote-connection-string=<type>:<param>=<value>,<param>=<value>...
+```
+
+You can pass as many parameters as you want. For unix and pipe connectors, these are passed along to the remote end as initialization. See [API](#api). Initialize is not called for http connector.
+
+### Unix connector
+parameters: path, timeout (default 2000ms)
+
+```
+remote-connection-string=unix:path=/path/to/socket
+```
+
+### Pipe connector
+parameters: command,timeout (default 2000ms)
+
+```
+remote-connection-string=pipe:command=/path/to/executable,timeout=2000
+```
+
+### HTTP connector
+parameters: url, url-suffix, post, post\_json, timeout (default 2000ms)
+
+```
+remote-connection-string=http:url=http://localhost:63636/dns,url-suffix=.php
+```
+
+HTTP connector tries to do RESTful requests to your server. See examples. You can also use post to change behaviour so that it will send POST request to url/method + url\_suffix with parameters=json-formatted-parameters. If you use post and post\_json, it will POST url with text/javascript containing JSON formatted RPC request, just like for pipe and unix. You can use '1', 'yes', 'on' or 'true' to turn these features on.
+
+URL should not end with /, and url-suffix is optional, but if you define it, it's up to you to write the ".php" or ".json". Lack of dot causes lack of dot in URL. Timeout is divided by 1000 because libcurl only supports seconds, but this is given in milliseconds for consistency with other connectors.
+
+HTTPS is not supported, [stunnel](https://www.stunnel.org) is the suggested workaround. HTTP Authentication is not supported.
+
+### ZeroMQ connector
+parameters: endpoint, timeout (default 2000ms)
+
+```
+remote-connection-string=zeromq:endpoint=ipc:///tmp/tmp.sock
+```
+
+0MQ connector implements a REQ/REP RPC model. Please see <http://zeromq.org/> for more information.
+
+# API
+## Queries
+Unix, Pipe and ZeroMQ connectors send JSON formatted strings to the remote end. Each JSON query has two sections, 'method' and 'parameters'.
+
+HTTP connector calls methods based on URL and has parameters in the query string. Most calls are GET; see the methods listing for details. You can change this with post and post\_json attributes.
+
+## Replies
+You **must** always reply with JSON hash with at least one key, 'result'. This must be boolean false if the query failed. Otherwise it must conform to the expected result. For HTTP connector, to signal bare success, you can just reply with HTTP 200 OK, and omit any output. This will result in same outcome as sending {"result":true}.
+
+You can optionally add an array of strings to the 'log' array; each line in this array will be logged in PowerDNS at loglevel `info` (6).
+
+## Methods
+### `initialize`
+Called to initialize the backend. This is not called for HTTP connector. You should do your initializations here.
+
+* Mandatory: Yes (except HTTP connector)
+* Parameters: all parameters in connection string
+* Reply: true on success / false on failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"initialize", "parameters":{"command":"/path/to/something", "timeout":"2000", "something":"else"}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+### `lookup`
+This method is used to do the basic query. You can omit auth, but if you are using DNSSEC this can lead into trouble.
+
+* Mandatory: Yes
+* Parameters: qtype, qname, zone\_id
+* Optional parameters: remote, local, real-remote
+* Reply: array of `qtype,qname,content,ttl,domain\_id,scopeMask,auth`
+* Optional values: domain\_id, scopeMask and auth
+* Note: priority field is required before 4.0, after 4.0 priority is added to content. This applies to any resource record which uses priority, for example SRV or MX.
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"lookup", "parameters":{"qtype":"ANY", "qname":"www.example.com", "remote":"192.0.2.24", "local":"192.0.2.1", "real-remote":"192.0.2.24", "zone-id":-1}}
+```
+
+Response:
+```
+{"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/lookup/www.example.com/ANY HTTP/1.1
+X-RemoteBackend-remote: 192.0.2.24
+X-RemoteBackend-local: 192.0.2.1
+X-RemoteBackend-real-remote: 192.0.2.24
+X-RemoteBackend-zone-id: -1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
+```
+
+### `list`
+Lists all records for the zonename. If you are running dnssec, you should take care of setting auth to appropriate value, otherwise things can go wrong.
+
+* Mandatory: No (Gives AXFR support)
+* Parameters: zonename, domain\_id
+* Optional parameters: domain\_id
+* Reply: array of `qtype,qname,content,ttl,domain\_id,scopeMask,auth`
+* Optional values: domain\_id, scopeMask and auth
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"list", "parameters":{"zonename":"example.com","domain_id":-1}}
+```
+
+Response (split into lines for ease of reading)
+```
+{"result":[
+ {"qtype":"SOA", "qname":"example.com", "content":"dns1.icann.org. hostmaster.icann.org. 2012081600 7200 3600 1209600 3600", "ttl": 3600},
+ {"qtype":"NS", "qname":"example.com", "content":"ns1.example.com", "ttl": 60},
+ {"qtype":"MX", "qname":"example.com", "content":"10 mx1.example.com.", "ttl": 60},
+ {"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60},
+ {"qtype":"A", "qname":"ns1.example.com", "content":"192.0.2.2", "ttl": 60},
+ {"qtype":"A", "qname":"mx1.example.com", "content":"192.0.2.3", "ttl": 60}
+]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/list/-1/example.com HTTP/1.1
+X-RemoteBackend-domain-id: -1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":[{"qtype":"SOA", "qname":"example.com", "content":"dns1.icann.org. hostmaster.icann.org. 2012081600 7200 3600 1209600 3600", "ttl": 3600},{"qtype":"NS", "qname":"example.com", "content":"ns1.example.com", "ttl": 60},{"qtype":"MX", "qname":"example.com", "content":"10 mx1.example.com.", "ttl": 60},{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60},{"qtype":"A", "qname":"ns1.example.com", "content":"192.0.2.2", "ttl": 60},{"qtype":"A", "qname":"mx1.example.com", "content":"192.0.2.3", "ttl": 60}]}
+```
+
+### `getBeforeAndAfterNamesAbsolute`
+Asks the names before and after qname. qname is given without dots or domain part. The query will be hashed when using NSEC3. Care must be taken to handle wrap-around when qname is first or last in the ordered list. Do not return nil for either one.
+
+* Mandatory: for NSEC/NSEC3 non-narrow
+* Parameters: id, qname
+* Reply: before, after
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"getbeforeandafternamesabsolute", "params":{"id":0,"qname":"www.example.com"}}
+```
+
+Response:
+```
+{”result":{"before":"ns1","after":""}}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+/dnsapi/getbeforeandafternamesabsolute/0/www.example.com
+```
+
+Response:
+```
+{”result":{"before":"ns1","after":""}}
+```
+
+### `getAllDomainMetadata`
+Returns the value(s) for variable kind for zone name. You **must** always return something, if there are no values, you shall return empty set or false.
+* Mandatory: No
+* Parameters: name
+* Reply: hash of key to array of strings
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"getalldomainmetadata", "parameters":{"name":"example.com"}}
+```
+
+Response:
+```
+{"result":{"PRESIGNED":["0"]}}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/getalldomainmetadata/example.com HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":{"PRESIGNED":["0"]}}
+```
+
+### `getDomainMetadata`
+Returns the value(s) for variable kind for zone name. Most commonly it's one of NSEC3PARAM, PRESIGNED, SOA-EDIT. Can be others, too. You **must** always return something, if there are no values, you shall return empty array or false.
+
+* Mandatory: No
+* Parameters: name, kind
+* Reply: array of strings
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"getdomainmetadata", "parameters":{"name":"example.com","kind":"PRESIGNED"}}
+```
+
+Response:
+```
+{"result":["0"]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/getdomainmetadata/example.com/PRESIGNED HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":["0"]}
+```
+
+### `setDomainMetadata`
+Replaces the value(s) on domain name for variable kind to string(s) on array value. The old value is discarded. Value can be an empty array, which can be interprepted as deletion request.
+
+* Mandatory: No
+* Parameters: name, kind, value
+* Reply: true on success, false on failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"setdomainmetadata","parameters":{"name":"example.com","kind":"PRESIGNED","value":["YES"]}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/setdomainmetadata/example.com/PRESIGNED HTTP/1.1
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 12
+
+value[]=YES&
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `getDomainKeys`
+Retrieves any keys of kind. The id, flags are unsigned integers, and active is boolean. Content must be valid key record in format that PowerDNS understands. You are encouraged to implement [the section called "addDomainKey"](#adddomainkey), as you can use [`pdnsutil`](../manpages/pdnsutil.1.md) to provision keys.
+
+* Mandatory: for DNSSEC
+* Parameters: name, kind
+* Reply: array of `id, flags, active, content`
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"getdomainkeys","parameters":{"name":"example.com","kind":0}}
+```
+
+Response:
+```
+{"result":[{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+Algorithm: 8 (RSASHA256)
+Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
+PublicExponent: AQAB
+PrivateExponent: CYC93UtVnOM6wrFJZ+qA9+Yx+p5yk0CSi0Q7c+/6EVMuABQ5gNyTuu0j65lU3X81bwUk2wHPx6smfgoVDRAW5jjO4jgIFV6nE4inzk5YQKycQSL8YG3Nm9GciLFya1KUXs81sHsQpkvK7MNaSbvkaHZQ6iv16bZ4t73Wascwa/E=
+Prime1: 6a165cIC0nNsGlTW/s2jRu7idq5+U203iE1HzSIddmWgx5KIKE/s3I+pwfmXYRUmq+4H9ASd/Yot1lSYW98szw==
+Prime2: wLoCPKxxnuxDx6/9IKOYz8t9ZNLY74iCeQ85koqvTctkFmB9jpOUHTU9BhecaFY2euP9CuHV7z3PLtCoO8s1MQ==
+Exponent1: CuzJaiR/7UboLvL4ekEy+QYCIHpX/Z6FkiHK0ZRevEJUGgCHzRqvgEBXN3Jr2WYbwL4IMShmGoxzSCn8VY9BkQ==
+Exponent2: LDR9/tyu0vzuLwc20B22FzNdd5rFF2wAQTQ0yF/3Baj5NAi9w84l0u07KgKQZX4g0N8qUyypnU5YDyzc6ZoagQ==
+Coefficient: 6S0vhIQITWzqfQSLj+wwRzs6qCvJckHb1+SD1XpwYjSgMTEUlZhf96m8WiaE1/fIt4Zl2PC3fF7YIBoFLln22w=="}]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/getdomainkeys/example.com/0 HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":[{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+Algorithm: 8 (RSASHA256)
+Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
+PublicExponent: AQAB
+PrivateExponent: CYC93UtVnOM6wrFJZ+qA9+Yx+p5yk0CSi0Q7c+/6EVMuABQ5gNyTuu0j65lU3X81bwUk2wHPx6smfgoVDRAW5jjO4jgIFV6nE4inzk5YQKycQSL8YG3Nm9GciLFya1KUXs81sHsQpkvK7MNaSbvkaHZQ6iv16bZ4t73Wascwa/E=
+Prime1: 6a165cIC0nNsGlTW/s2jRu7idq5+U203iE1HzSIddmWgx5KIKE/s3I+pwfmXYRUmq+4H9ASd/Yot1lSYW98szw==
+Prime2: wLoCPKxxnuxDx6/9IKOYz8t9ZNLY74iCeQ85koqvTctkFmB9jpOUHTU9BhecaFY2euP9CuHV7z3PLtCoO8s1MQ==
+Exponent1: CuzJaiR/7UboLvL4ekEy+QYCIHpX/Z6FkiHK0ZRevEJUGgCHzRqvgEBXN3Jr2WYbwL4IMShmGoxzSCn8VY9BkQ==
+Exponent2: LDR9/tyu0vzuLwc20B22FzNdd5rFF2wAQTQ0yF/3Baj5NAi9w84l0u07KgKQZX4g0N8qUyypnU5YDyzc6ZoagQ==
+Coefficient: 6S0vhIQITWzqfQSLj+wwRzs6qCvJckHb1+SD1XpwYjSgMTEUlZhf96m8WiaE1/fIt4Zl2PC3fF7YIBoFLln22w=="}]}
+```
+
+### `addDomainKey`
+Adds key into local storage. See [`getDomainKeys`](#getdomainkeys) for more information.
+
+* Mandatory: No
+* Parameters: name, key=`<flags,active,content>`
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"adddomainkey", "parameters":{"key":{"id":1,"flags":256,"active":true,"content":"Private-key-format: v1.2
+Algorithm: 8 (RSASHA256)
+Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
+PublicExponent: AQAB
+PrivateExponent: CYC93UtVnOM6wrFJZ+qA9+Yx+p5yk0CSi0Q7c+/6EVMuABQ5gNyTuu0j65lU3X81bwUk2wHPx6smfgoVDRAW5jjO4jgIFV6nE4inzk5YQKycQSL8YG3Nm9GciLFya1KUXs81sHsQpkvK7MNaSbvkaHZQ6iv16bZ4t73Wascwa/E=
+Prime1: 6a165cIC0nNsGlTW/s2jRu7idq5+U203iE1HzSIddmWgx5KIKE/s3I+pwfmXYRUmq+4H9ASd/Yot1lSYW98szw==
+Prime2: wLoCPKxxnuxDx6/9IKOYz8t9ZNLY74iCeQ85koqvTctkFmB9jpOUHTU9BhecaFY2euP9CuHV7z3PLtCoO8s1MQ==
+Exponent1: CuzJaiR/7UboLvL4ekEy+QYCIHpX/Z6FkiHK0ZRevEJUGgCHzRqvgEBXN3Jr2WYbwL4IMShmGoxzSCn8VY9BkQ==
+Exponent2: LDR9/tyu0vzuLwc20B22FzNdd5rFF2wAQTQ0yF/3Baj5NAi9w84l0u07KgKQZX4g0N8qUyypnU5YDyzc6ZoagQ==
+Coefficient: 6S0vhIQITWzqfQSLj+wwRzs6qCvJckHb1+SD1XpwYjSgMTEUlZhf96m8WiaE1/fIt4Zl2PC3fF7YIBoFLln22w=="}}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PUT /dnsapi/adddomainkey/example.com
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 965
+
+flags=256&active=1&content=Private-key-format: v1.2
+Algorithm: 8 (RSASHA256)
+Modulus: r+vmQll38ndQqNSCx9eqRBUbSOLcH4PZFX824sGhY2NSQChqt1G4ZfndzRwgjXMUwiE7GkkqU2Vbt/g4iP67V/+MYecMV9YHkCRnEzb47nBXvs9JCf8AHMCnma567GQjPECh4HevPE9wmcOfpy/u7UN1oHKSKRWuZJadUwcjbp8=
+PublicExponent: AQAB
+PrivateExponent: CYC93UtVnOM6wrFJZ+qA9+Yx+p5yk0CSi0Q7c+/6EVMuABQ5gNyTuu0j65lU3X81bwUk2wHPx6smfgoVDRAW5jjO4jgIFV6nE4inzk5YQKycQSL8YG3Nm9GciLFya1KUXs81sHsQpkvK7MNaSbvkaHZQ6iv16bZ4t73Wascwa/E=
+Prime1: 6a165cIC0nNsGlTW/s2jRu7idq5+U203iE1HzSIddmWgx5KIKE/s3I+pwfmXYRUmq+4H9ASd/Yot1lSYW98szw==
+Prime2: wLoCPKxxnuxDx6/9IKOYz8t9ZNLY74iCeQ85koqvTctkFmB9jpOUHTU9BhecaFY2euP9CuHV7z3PLtCoO8s1MQ==
+Exponent1: CuzJaiR/7UboLvL4ekEy+QYCIHpX/Z6FkiHK0ZRevEJUGgCHzRqvgEBXN3Jr2WYbwL4IMShmGoxzSCn8VY9BkQ==
+Exponent2: LDR9/tyu0vzuLwc20B22FzNdd5rFF2wAQTQ0yF/3Baj5NAi9w84l0u07KgKQZX4g0N8qUyypnU5YDyzc6ZoagQ==
+Coefficient: 6S0vhIQITWzqfQSLj+wwRzs6qCvJckHb1+SD1XpwYjSgMTEUlZhf96m8WiaE1/fIt4Zl2PC3fF7YIBoFLln22w==
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `removeDomainKey`
+Removes key id from domain name.
+
+* Mandatory: No
+* Parameters: name, id
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"removedomainkey","parameters":"{"name":"example.com","id":1}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+DELETE /dnsapi/removedomainkey/example.com/1 HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `activateDomainKey`
+Activates key id for domain name.
+
+* Mandatory: No
+* Parameters: name, id
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"activatedomainkey","parameters":{"name":"example.com","id":1}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/activatedomainkey/example.com/1 HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; utf-8
+
+{"result": true}
+```
+
+### `deactivateDomainKey`
+Deactivates key id for domain name.
+
+* Mandatory: No
+* Parameters: name, id
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"deactivatedomainkey","parameters":{"name":"example.com","id":1}}
+```
+
+Response:
+```
+{"result": true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/deactivatedomainkey/example.com/1 HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; utf-8
+
+{"result": true}
+```
+
+### `getTSIGKey`
+Retrieves the key needed to sign AXFR.
+
+* Mandatory: No
+* Parameters: name
+* Reply: algorithm, content
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"gettsigkey","parameters":{"name":"example.com"}}
+```
+
+Response:
+```
+{"result":{"algorithm":"hmac-md5","content:"kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/gettsigkey/example.com
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":{"algorithm":"hmac-md5","content:"kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="}}
+```
+
+### `getDomainInfo`
+Retrieves information about given domain from the backend. If your return value has no zone attribute, the backend will signal error. Everything else will default to something. Default values: serial:0, kind:NATIVE, id:-1, notified\_serial:-1, last\_check:0, masters: []. Masters, if present, must be array of strings.
+
+* Mandatory: No
+* Parameters: name
+* Reply: zone
+* Optional values: serial, kind, id, notified\_serial, last\_check, masters
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"getdomaininfo","parameters":{"name":"example.com"}}
+```
+
+Response:
+```
+{"result":{id:1,"zone":"example.com","kind":"NATIVE","serial":2002010100}}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/getdomaininfo/example.com HTTP/1.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+content-Type: text/javascript: charset=utf-8
+
+{"result":{id:1,"zone":"example.com","kind":"NATIVE","serial":2002010100}}
+```
+
+### `setNotified`
+Updates last notified serial for the domain id. Any errors are ignored.
+
+* Mandatory: No
+* Parameters: id, serial
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"setnotified","parameters":{"id":1,"serial":2002010100}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/setnotified/1
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 17
+
+serial=2002010100
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `isMaster`
+Determines whether given IP is master for given domain name.
+
+* Mandatory: No
+* Parameters: name,ip
+* Reply: true for success, false for failure.
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"isMaster","parameters":{"name":"example.com","ip":"198.51.100.0.1"}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/isMaster/example.com/198.51.100.0.1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `superMasterBackend`
+Creates new domain with given record(s) as master servers. IP address is the address where notify is received from. nsset is array of NS resource records.
+
+* Mandatory: No
+* Parameters: ip,domain,nsset,account
+* Reply: true for success, false for failure. can also return account=>name of account< and nameserver.
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"superMasterBackend","parameters":{"ip":"198.51.100.0.1","domain":"example.com","nsset":[{"qtype":"NS","qname":"example.com","qclass":1,"content":"ns1.example.com","ttl":300,"auth":true},{"qtype":"NS","qname":"example.com","qclass":1,"content":"ns2.example.com","ttl":300,"auth":true}]}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+Alternative response:
+```
+{"result":{"account":"my account","nameserver":"ns2.example.com"}}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/supermasterbackend/198.51.100.0.1/example.com
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 317
+
+nsset[1][qtype]=NS&nsset[1][qname]=example.com&nsset[1][qclass]=1&nsset[1][content]=ns1.example.com&nsset[1][ttl]=300&nsset[1][auth]=true&nsset[2][qtype]=NS&nsset[2][qname]=example.com&nsset[2][qclass]=1&nsset[2][content]=ns2.example.com&nsset[2][ttl]=300&nsset[2][auth]=true
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+Alternative response
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":{"account":"my account}}
+```
+
+### `createSlaveDomain`
+Creates new domain. This method is called when NOTIFY is received and you are superslaving.
+
+Mandatory: No
+Parameters: ip, domain
+Optional parameters: nameserver, account
+Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"createSlaveDomain","parameters":{"ip":"198.51.100.0.1","domain":"pirate.example.net"}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/createslavedomain/198.51.100.0.1/pirate.example.net
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 0
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `replaceRRSet`
+This method replaces a given resource record with new set. The new qtype can be different from the old.
+
+* Mandatory: No
+* Parameters: domain\_id, qname, qtype, rrset
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"replaceRRSet","parameters":{"domain_id":2,"qname":"replace.example.com","qtype":"A","trxid":1370416133,"rrset":[{"qtype":"A","qname":"replace.example.com","qclass":1,"content":"1.1.1.1","ttl":300,"auth":true}]}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/replacerrset/2/replace.example.com/A
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 135
+
+trxid=1370416133&rrset[qtype]=A&rrset[qname]=replace.example.com&rrset[qclass]=1&rrset[content]=1.1.1.1&rrset[auth]=1
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `feedRecord`
+Asks to feed new record into system. If startTransaction was called, trxId identifies a transaction. It is not always called by PowerDNS.
+
+* Mandatory: No
+* Parameters: rr, trxid
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"feedRecord","parameters":{"rr":{"qtype":"A","qname":"replace.example.com","qclass":1,"content":"127.0.0.1","ttl":300,"auth":true},"trxid":1370416133}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/feedrecord/1370416133
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 117
+
+rr[qtype]=A&rr[qname]=replace.example.com&rr[qclass]=1&rr[content]=127.0.0.1&rr[ttl]=300&rr[auth]=true
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `feedEnts`
+This method is used by pdnsutil rectify-zone to populate missing non-terminals. This is used when you have, say, record like \_sip.\_upd.example.com, but no \_udp.example.com. PowerDNS requires that there exists a non-terminal in between, and this instructs you to add one. If startTransaction is called, trxid identifies a transaction.
+
+* Mandatory: No
+* Parameters: nonterm, trxid
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"feedEnts","parameters":{"domain_id":2,"trxid":1370416133,"nonterm":["_sip._udp","_udp"]}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/feedents/2
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 50
+
+trxid=1370416133&nonterm[]=_udp&nonterm[]=_sip.udp
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `feedEnts3`
+Same as [`feedEnts`](#feedents), but provides NSEC3 hashing parameters. Note that salt is BYTE value, and can be non-readable text.
+
+* Mandatory: No
+* Parameters: trxid, domain\_id, domain, times, salt, narrow, nonterm
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC\
+Query:
+```
+{"method":"feedEnts3","parameters":{"domain_id":2,"domain":"example.com","times":1,"salt":"9642","narrow":false,"trxid":1370416356,"nonterm":["_sip._udp","_udp"]}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+PATCH /dnsapi/2/example.com
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 78
+
+trxid=1370416356×=1&salt=9642&narrow=0&nonterm[]=_sip._udp&nonterm[]=_udp
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `startTransaction`
+Starts a new transaction. Transaction ID is chosen for you. Used to identify f.ex. AXFR transfer.
+
+* Mandatory: No
+* Parameters: domain\_id, domain, trxid
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"startTransaction","parameters":{"trxid":1234,"domain_id":1,"domain":"example.com"}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/starttransaction/1/example.com
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 10
+
+trxid=1234
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `commitTransaction`
+Signals successful transfer and asks to commit data into permanent storage.
+
+* Mandatory: No
+* Parameters: trxid
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"commitTransaction","parameters":{"trxid":1234}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/committransaction/1234
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 0
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `abortTransaction`
+Signals failed transaction, and that you should rollback any changes.
+
+* Mandatory: No
+* Parameters: trxid
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"abortTransaction","parameters":{"trxid":1234}}
+```
+
+Response:
+```
+{"result":true}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/aborttransaction/1234
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 0
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":true}
+```
+
+### `calculateSOASerial`
+Asks you to calculate a new serial based on the given data and update the serial.
+
+* Mandatory: No
+* Parameters: domain,sd
+* Reply: true for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"calculateSOASerial","parameters":{"domain":"unit.test","sd":{"qname":"unit.test","nameserver":"ns.unit.test","hostmaster":"hostmaster.unit.test","ttl":300,"serial":1,"refresh":2,"retry":3,"expire":4,"default_ttl":5,"domain_id":-1,"scopeMask":0}}}
+```
+
+Response:
+```
+{"result":2013060501}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/calculatesoaserial/unit.test
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 198
+
+sd[qname]=unit.test&sd[nameserver]=ns.unit.test&sd[hostmaster]=hostmaster.unit.test&sd[ttl]=300&sd[serial]=1&sd[refresh]=2&sd[retry]=3&sd[expire]=4&sd[default_ttl]=5&sd[domain_id]=-1&sd[scopemask]=0
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":2013060501}
+```
+
+### `directBackendCmd`
+Can be used to send arbitrary commands to your backend using (backend-cmd)(dnssec.md#pdnsutil).
+
+* Mandatory: no
+* Parameters: query
+* Reply: anything but boolean false for success, false for failure
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"directBackendCmd","parameters":{"query":"PING"}}
+```
+
+Response:
+```
+{"result":"PONG"}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+POST /dnsapi/directBackendCmd
+Content-Type: application/x-www-form-urlencoded
+Content-Length: 10
+
+query=PING
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":"PONG"}
+```
+
+### `getAllDomains`
+Get DomainInfo records for all domains in your backend.
+
+* Mandatory: no
+* Parameters: include_disabled
+* Reply: array of DomainInfo
+
+#### Example JSON/RPC
+Query:
+```
+{"method": "getAllDomains", "parameters": {"include_disabled": true}}
+```
+
+Response:
+```
+{"result":[{"id":1,"zone":"unit.test.","masters":["10.0.0.1"],"notified_serial":2,"serial":2,"last_check":1464693331,"kind":"native"}]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/getAllDomains?includeDisabled=true
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+Content-Length: 135
+{"result":[{"id":1,"zone":"unit.test.","masters":["10.0.0.1"],"notified_serial":2,"serial":2,"last_check":1464693331,"kind":"native"}]}
+```
+
+### `searchRecords`
+Can be used to search records from the backend. This is used by web api.
+
+* Mandatory: no
+* Parameters: pattern, maxResults
+* Reply: same as [lookup](#lookup) or false to indicate failed search
+
+#### Example JSON/RPC
+Query:
+```
+{"method":"searchRecords","parameters":{"pattern":"www.example*","maxResults":100}}
+```
+
+Response:
+```
+{"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
+```
+
+#### Example HTTP/RPC
+Query:
+```
+GET /dnsapi/searchRecords?q=www.example*&maxResults=100
+```
+
+Response:
+```
+HTTP/1.1 200 OK
+Content-Type: text/javascript; charset=utf-8
+
+{"result":[{"qtype":"A", "qname":"www.example.com", "content":"203.0.113.2", "ttl": 60}]}
+```
+
+# Examples
+## Scenario: SOA lookup via pipe, unix or zeromq connector
+Query:
+```
+{
+ "method": "lookup",
+ "parameters": {
+ "qname": "example.com",
+ "qtype": "SOA",
+ "zone_id": "-1"
+ }
+}
+```
+
+Reply:
+```
+{
+ "result":
+ [
+ { "qtype": "SOA",
+ "qname": "example.com",
+ "content": "dns1.icann.org. hostmaster.icann.org. 2012080849 7200 3600 1209600 3600",
+ "ttl": 3600,
+ "domain_id": -1
+ }
+ ]
+}
+```
+
+## Scenario: SOA lookup with HTTP connector
+Query:
+```
+/dns/lookup/example.com/SOA
+```
+
+Reply:
+```
+{
+ "result":
+ [
+ { "qtype": "SOA",
+ "qname": "example.com",
+ "content": "dns1.icann.org. hostmaster.icann.org. 2012080849 7200 3600 1209600 3600",
+ "ttl": 3600,
+ "domain_id": -1
+ }
+ ]
+}
+```
--- /dev/null
+# TinyDNS Backend
+
+* Native: Yes
+* Master: Yes
+* Slave: No
+* Superslave: No
+* Autoserial: No
+* DNSSEC: No
+* Multiple Instances: Yes
+* Module name: tinydns
+* Launch: tinydns
+
+The TinyDNS backend allows you to use [djbdns's](http://cr.yp.to/djbdns.html) `data.cdb` file format as the storage of your DNS records. The `data.cdb` file is created using [tinydns-data](http://cr.yp.to/djbdns/tinydns-data.html). The backend is designed to be able to use the `data.cdb` files without any changes.
+
+## Configuration Parameters
+These are the configuration file parameters that are available for the TinyDNS backend. It is recommended to set the `tinydns-dbfile`.
+
+### `tinydns-dbfile`
+* String
+* Default: data.cdb
+
+Specifies the name of the data file to use.
+
+### `tinydns-tai-adjust`
+* Integer
+* Default: 11
+
+This adjusts the [TAI](http://www.tai64.com/) value if timestamps are used. These seconds will be added to the start point (1970) and will allow you to adjust for leap seconds. The current default is 11. The last update was on [june 30th 2012](http://hpiers.obspm.fr/iers/bul/bulc/bulletinc.dat).
+
+### `tinydns-notify-on-startup`
+* Boolean
+* Default: no
+
+Tell the TinyDNSBackend to notify all the slave nameservers on startup. This might cause broadcast storms.
+
+### `tinydns-ignore-bogus-records`
+* Boolean
+* Default: no
+
+The `tinydns-data` program can create data.cdb files that have bad/corrupt RDATA. PowerDNS will crash when it tries to read that bad/corrupt data. This option (change to yes), allows you to ignore that bad RDATA to make PowerDNS operate when bad data is in your CDB file. Be aware that the records are then ignored, where tinydns would still send out the bogus data. The option is primarily useful in master mode, as that reads all the packets in the zone to find all the SOA records.
+
+### `tinydns-locations`
+* Boolean
+* Default: yes
+
+Enable or Disable location support in the backend. Changing the value to 'no' will make the backend ignore the locations. This then returns all records. When the setting is changed to 'no' an AXFR will also return all the records. With the setting on 'yes' an AXFR will only return records without a location.
+
+## Location and Timestamp support
+Both timestamp and location are supported in the backend. Locations support can be changed using the [`tinydns-locations`](#tinydns-locations) setting. Timestamp and location only work as expected when [`cache-ttl`](settings.md#cache-ttl) and [`query-cache-ttl`](settings.md#query-cache-ttl) are set to 0 (which disables these caches). Timestamp can operate with [`cache-ttl`](settings.md#cache-ttl) if cache is needed, but the TTL returned for the timestamped racked will not be totally correct. The record will expire once the cache is expired and the backend is queried again. Please note that [`cache-ttl`](settings.md#cache-ttl) is a performance related setting. See [Performance related settings](performance.md). Location support only exists for IPv4!
+
+## Master mode
+The TinyDNSBackend supports master mode. This allows it to notify slave nameservers of updates to a zone. You simply need to rewrite the `data.cdb` file with an updated/increased serial and PowerDNS will notify the slave nameservers of that domain. The [`tinydns-notify-on-startup`](#tinydns-notify-on-startup) configuration setting tells the backend if it should notify all the slave nameservers just after startup.
+
+The CDB datafile does not allow PowerDNS to easily query for newly added domains or updated serial numbers. The CDB datafile requires us to do a full scan of all the records. When running with verbose logging, this could lead to a lot of output. The scanning of the CDB file may also take a while on systems with large files. The scan happens at an interval set by the [`slave-cycle-interval`](settings.md#slave-cycle-interval). It might be useful to raise this value to limit the amount of scans on the CDB file.
+
+The TinyDNSBackend also keeps a list of all the zones. This is needed to detect an updated serial and to give every zone a unique id. The list is updated when a zone is added, but not when a zone is removed. This leads to some memory loss.
+
+## Useful implementation Notes
+This backend might solve some issues you have with the current tinydns noted on [Jonathan de Boyne Pollard's](http://homepage.ntlworld.com/jonathan.deboynepollard/author.html) [djbdns known problems page](http://homepage.ntlworld.com/jonathan.deboynepollard/FGA/djbdns-problems.html).
+
+The `data.cdb` file format support all types of records. They are sometimes difficult to create because you need to specify the actual content of the rdata. [Tinydns.org](http://tinydns.org/) provides a number of links to tools/cgi-scripts that allow you to create records. [Anders Brownworth](http://anders.com/) also provides a number of useful record building scripts on his [djbdnsRecordBuilder](http://anders.com/projects/sysadmin/djbdnsRecordBuilder/).
+
+PowerDNS and TinyDNS handle wildcards differently. Looking up foo.www.example.com with the below records on TinyDNS will return 198.51.100.1, PowerDNS will return NXDOMAIN. According to [RFC 4592](https://tools.ietf.org/html/rfc4592) \*.example.com should only match subdomains in under example.com, not \*.\*.example.com. This compatibility issue is [noted on the axfer-get page for the djbdns suite](https://cr.yp.to/djbdns/axfr-get.html).
+
+```
+*.example.com A 198.51.100.1
+www.example.com A 198.51.100.1
+```
+
+Compiling the TinyDNS backend requires you to have [tinycdb](http://www.corpit.ru/mjt/tinycdb.html) version 0.77.
--- /dev/null
+# Serving authoritative DNSSEC data
+PowerDNS contains support for DNSSEC, enabling the easy serving of DNSSEC secured
+data, with minimal administrative overhead.
+
+In PowerDNS, DNS and signatures and keys are (usually) treated as separate
+entities. The domain & record storage is thus almost completely devoid of DNSSEC
+record types.
+
+Instead, keying material is stored separately, allowing operators to focus on the
+already complicated task of keeping DNS data correct. In practice, DNSSEC related
+material is often stored within the same database, but within separate tables.
+
+If a DNSSEC configuration is found for a domain, the PowerDNS daemon will provide
+key records, signatures and (hashed) denials of existence automatically.
+
+As an example, securing an existing zone can be as simple as:
+
+```
+$ pdnsutil secure-zone powerdnssec.org
+```
+
+Alternatively, PowerDNS can serve pre-signed zones, without knowledge of
+private keys.
+
+# A brief introduction to DNSSEC
+DNSSEC is a complicated subject, but it is not required to know all the ins and
+outs of this protocol to be able to use PowerDNS. In this section, we explain the
+core concepts that are needed to operate a PowerDNSSEC installation.
+
+Zone material is enhanced with signatures using 'keys'. Such a signature (called
+an RRSIG) is a cryptographic guarantee that the data served is the original data.
+DNSSEC keys are asymmetric (RSA, DSA, ECSDA or GOST), the public part is published
+in DNS and is called a DNSKEY record, and is used for verification. The private
+part is used for signing and is never published.
+
+To make sure that the internet knows that the key that is used for signing is the
+authentic key, confirmation can be gotten from the parent zone. This means that
+to become operational, a zone operator will have to publish a representation of
+the signing key to the parent zone, often a ccTLD or a gTLD. This representation
+is called a DS record, and is a shorter (hashed) version of the DNSKEY.
+
+Once the parent zone has the DS, and the zone is signed with the DNSSEC key, we
+are done in theory.
+
+However, for a variety of reasons, most DNSSEC operations run with another layer
+of keys. The so called 'Key Signing Key' is sent to the parent zone, and this Key
+Signing Key is used to sign a new set of keys called the Zone Signing Keys.
+
+This setup allows us to change our keys without having to tell the zone operator
+about it.
+
+A final challenge is how to DNSSEC sign the answer 'no such domain'. In the
+language of DNS, the way to say 'there is no such domain' (NXDOMAIN) or there is
+no such record type is to send an empty answer. Such empty answers are universal,
+and can't be signed.
+
+In DNSSEC parlance we therefore sign a record that says 'there are no domains
+between A.powerdnssec.org and C.powerdnssec.org'. This securely tells the world
+that B.powerdnssec.org does not exist. This solution is called NSEC, and is
+simple but has downsides - it also tells the world exactly which records DO exist.
+
+So alternatively, we can say that if a certain mathematical operation (an
+'iterated salted hash') is performed on a question, that no valid answers exist
+that have as outcome of this operation an answer between two very large numbers.
+This leads to the same 'proof of non-existence'. This solution is called NSEC3.
+
+A PowerDNS zone can either be operated in NSEC or in one of two NSEC3 modes
+('inclusive' and 'narrow').
+
+# Profile, Supported Algorithms and Record Types
+PowerDNS aims to serve unexciting, standards compliant, DNSSEC information. One
+goal is to have relevant parts of our output be identical or equivalent to important
+fellow-traveller software like NLNetLabs' NSD.
+
+Particularly, if a PowerDNS secured zone is transferred via AXFR, it should be
+able to contain the same records as when that zone was signed using `ldns-signzone`
+using the same keys and settings.
+
+PowerDNS supports serving pre-signed zones, as well as online ('live') signed
+operations. In the last case, Signature Rollover and Key Maintenance are fully
+managed by PowerDNS.
+
+## Supported Algorithms
+Supported Algorithms (See the [IANA website](http://www.iana.org/assignments/dns-sec-alg-numbers/dns-sec-alg-numbers.xhtml#dns-sec-alg-numbers-1) for more information):
+
+- RSASHA1 (algorithm 5, algorithm 7)
+- RSASHA256 (algorithm 8)
+- RSASHA512 (algorithm 10)
+- ECC-GOST (algorithm 12)
+- ECDSA (algorithm 13 and 14)
+
+For the DS records, these [digest algorithms](http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml#ds-rr-types-1)
+are supported:
+
+- SHA-1 (algorithm 1)
+- SHA-256 (algorithm 2)
+- GOST R 34.11-94 (algorithm 3)
+- SHA-384 (algorithm 4)
+
+This corresponds to:
+- [RFC 4033](http://tools.ietf.org/html/rfc4033): DNS Security Introduction and Requirements
+- [RFC 4034](http://tools.ietf.org/html/rfc4034): Resource Records for the DNS Security Extensions, Protocol Modifications for the DNS Security Extensions
+- [RFC 4035](http://tools.ietf.org/html/rfc4035): Protocol Modifications for the DNS Security Extensions
+- [RFC 4509](http://tools.ietf.org/html/rfc4509): Use of SHA-256 in DNSSEC Delegation Signer (DS) Resource Records (RRs)
+- [RFC 5155](http://tools.ietf.org/html/rfc5155): DNS Security (DNSSEC) Hashed Authenticated Denial of Existence
+- [RFC 5702](http://tools.ietf.org/html/rfc5702): Use of SHA-2 Algorithms with RSA in DNSKEY and RRSIG Resource Records for DNSSEC
+- [RFC 5933](http://tools.ietf.org/html/rfc5933): Use of GOST Signature Algorithms in DNSKEY and RRSIG Resource Records for DNSSEC
+- [RFC 6605](http://tools.ietf.org/html/rfc6605): Elliptic Curve Digital Signature Algorithm (DSA) for DNSSEC
+
+In order to facilitate interoperability with existing technologies, PowerDNS keys
+can be imported and exported in industry standard formats.
+
+When using OpenSSL for ECDSA signatures (this is default), starting from OpenSSL
+1.1.0, the algorithm used is resilient against PRNG failure, while not
+strictly conforming to [RFC 6979](http://tools.ietf.org/html/rfc6979).
+
+**Note**: Actual supported algorithms depend on the crypto-libraries PowerDNS was
+compiled against. To check the supported DNSSEC algoritms in your build of PowerDNS,
+run `pdnsutil list-algorithms`.
+
+# DNSSEC Modes of Operation
+Traditionally, DNSSEC signatures have been added to unsigned zones, and then this
+signed zone could be served by any DNSSEC capable authoritative server. PowerDNS
+supports this mode fully.
+
+In addition, PowerDNS supports taking care of the signing itself, in which case
+PowerDNS operates differently from most tutorials and handbooks. This mode is
+easier however.
+
+For relevant tradeoffs, please see [Security](#security) and
+[Performance](#performance.html).
+
+## Online Signing
+In the simplest situation, there is a single "SQL" database that contains, in
+separate tables, all domain data, keying material and other DNSSEC related settings.
+
+This database is then replicated to all PowerDNS instances, which all serve
+identical records, keys and signatures.
+
+In this mode of operation, care should be taken that the database replication
+occurs over a secure network, or over an encrypted connection. This is because
+keying material, if intercepted, could be used to counterfeit DNSSEC data using
+the original keys.
+
+Such a single replicated database requires no further attention beyond monitoring
+already required during non-DNSSEC operations.
+
+### Records, Keys, signatures, hashes within PowerDNS in online signing mode
+Within PowerDNS live signing, keys are stored separately from the zone records.
+Zone data are only combined with signatures and keys when requests come in over
+the internet.
+
+Each zone can have a number of keys associated with it, with varying key lengths.
+Typically 1 or at most 2 of these keys are employed as actual Zone Signing Keys (ZSKs).
+During normal operations, this means that only 1 ZSK is 'active', and the other is inactive.
+
+Should it be desired to 'roll over' to a new key, both keys can temporarily be
+active (and used for signing), and after a while the old key can be inactivated.
+Subsequently it can be removed.
+
+As elucidated above, there are several ways in which DNSSEC can deny the existence
+of a record, and this setting too is stored away from zone records, and lives
+with the DNSSEC keying material.
+
+### (Hashed) Denial of Existence
+PowerDNS supports unhashed secure denial of existence using NSEC records. These
+are generated with the help of the (database) backend, which needs to be able
+to supply the 'previous' and 'next' records in canonical ordering.
+
+The Generic SQL Backends have fields that allow them to supply these relative
+record names.
+
+In addition, hashed secure denial of existence is supported using NSEC3 records,
+in two modes, one with help from the database, the other with the help of some
+additional calculations.
+
+NSEC3 in 'broad' or 'inclusive' mode works with the aid of the backend, where
+the backend should be able to supply the previous and next domain names in hashed
+order.
+
+NSEC3 in 'narrow' mode uses additional hashing calculations to provide hashed
+secure denial of existence 'on the fly', without further involving the database.
+
+### Signatures
+In PowerDNS live signing mode, signatures, as served through RRSIG records, are
+calculated on the fly, and heavily cached. All CPU cores are used for the calculation.
+
+RRSIGs have a validity period, in PowerDNS by default this period starts at most
+a week in the past, and continues at least a week into the future.
+
+Precisely speaking, the time period used is always from the start of the previous
+Thursday until the Thursday two weeks later. This two-week interval jumps with
+one-week increments every Thursday.
+
+**Note**: Why Thursday? POSIX-based operating systems count the time since GMT
+midnight January 1st of 1970, which was a Thursday. PowerDNS inception/expiration
+times are generated based on an integral number of weeks having passed since the
+start of the 'epoch'.
+
+PowerDNS also serves the DNSKEY records in live-signing mode. Their TTL is derived
+from the SOA records *minimum* field. When using NSEC3, the TTL of the NSEC3PARAM
+record is also derived from that field.
+
+## Pre-signed records
+In this mode, PowerDNS serves zones that already contain DNSSEC records. Such
+zones can either be slaved from a remote master, or can be signed using tools
+like OpenDNSSEC, ldns-signzone or dnssec-signzone.
+
+Even in this mode, PowerDNS will synthesize NSEC(3) records itself because of its
+architecture. RRSIGs of these NSEC(3) will still need to be imported. See the
+[Presigned migration guide](#From-existing-DNSSEC-non-PowerDNS-setups-pre-signed).
+
+## Front-signing
+As a special feature, PowerDNS can operate as a signing server which operates as
+a slave to an unsigned master.
+
+In this way, if keying material is available for an unsigned zone that is
+retrieved from a master server, this keying material will be used when serving
+data from this zone.
+
+As part of the zone retrieval, the equivalent of `pdnsutil rectify-zone` is run
+to make sure that all DNSSEC-related fields are set correctly.
+
+Signatures and Hashing is similar as described [above](#online-signing)
+
+## BIND-mode operation
+Starting with PowerDNS 3.1, the bindbackend can manage keys in an SQLite3 database
+without launching a separate gsqlite3 backend.
+
+To use this mode, add [`bind-dnssec-db=/var/db/bind-dnssec-db.sqlite3`](backend-bind.md#bind-dnssec-db)
+to pdns.conf, and run `pdnsutil create-bind-db /var/db/bind-dnssec-db.sqlite3`.
+Then, restart PowerDNS.
+
+After this, you can use `pdnsutil secure-zone` and all other pdnsutil commands
+on your BIND zones without trouble.
+
+## Hybrid BIND-mode operation
+**Warning**: This mode is only supported in 3.0, 3.0.1 and 3.4.0 and up! In 3.1
+to 3.3.1, the bindbackend always did its own key storage. In 3.4.0 and up hybrid
+bind mode operation is optional and enabled with the bindbackend [`hybrid`](backend-bind.md#bind-hybrid)
+config option.
+
+PowerDNS can also operate based on 'BIND'-style zone & configuration files. This
+'bindbackend' has full knowledge of DNSSEC, but has no native way of storing
+keying material.
+
+However, since PowerDNS supports operation with multiple simultaneous backends,
+this is not a problem.
+
+In hybrid mode, keying material and zone records are stored in different backends.
+This allows for 'bindbackend' operation in full DNSSEC mode.
+
+To benefit from this mode, include at least one database-based backend in the
+'launch' statement. The [Generic SQLite backend (gsqlite3)](backend-generic-sqlite.md)
+probably complements BIND mode best, since it does not require a database server
+process.
+
+**Warning**: For now, it is necessary to execute a manual SQL 'insert' into the
+domains table of the backend hosting the keying material. This is needed to
+generate a zone-id for the relevant domain. Sample SQL statement:
+
+```
+insert into domains (name, type) values ('powerdnssec.org', 'NATIVE');
+```
+
+# `pdnsutil`
+`pdnsutil` (previously called `pdnssec`) is a powerful command that is the
+operator-friendly gateway into PowerDNS configuration. Behind the scenes,
+`pdnsutil` manipulates a PowerDNS backend database, which also means that for
+many databases, `pdnsutil` can be run remotely, and can configure key material
+on different servers.
+
+For a list of available commands, see the [manpage](../manpages/pdnsutil.1.md).
+
+## DNSSEC Defaults
+Since version 4.0, when securing a zone using `pdnsutil secure-zone`, a single
+ECDSA (algorithm 13, ECDSAP256SHA256) key is generated that is used as ZSK.
+Before 4.0, 3 RSA (algorithm 8) keys were generated, one as the KSK and two ZSKs.
+As all keys are online in the database, it made no sense to have this split-key
+setup.
+
+The default negative answer strategy is NSEC.
+
+**Note**: not all registrars support algorithm 13.
+
+# Migration
+This chapter discusses various migration strategies, from existing PowerDNS setups,
+from existing unsigned installations and finally from previous non-PowerDNS
+DNSSEC deployments.
+
+## From an existing PowerDNS installation
+To migrate an existing database-backed PowerDNS installation, ensure you are
+running at least PowerDNS 3.3.3 and preferably 3.4 or newer.
+
+If you run an older version of PowerDNS, please upgrade to 3.4 and apply all the
+changes in database schemas as shown in the [upgrade documentation](upgrading.md).
+
+**Warning**: Once the relevant `backend-dnssec` switch has been set, stricter
+rules apply for filling out the database! The short version is: run
+`pdnsutil rectify-all-zones`, even those not secured with DNSSEC! For more
+information, see the [DNSSEC documentation for Generic SQL backends](backend-generic-sql.md#handling-dnssec-signed-zones).
+
+To deliver a correctly signed zone with the [DNSSEC defaults](#dnssec-defaults),
+invoke:
+
+```
+pdnsutil secure-zone ZONE
+```
+
+To view the DS records for this zone (to transfer to the parent zone), run
+
+```
+pdnsutil show-zone ZONE
+```
+
+For a more traditional setup with a KSK and a ZSK, use the following sequence
+of commands:
+
+```
+pdnsutil add-zone-key ZONE ksk 2048 active rsasha256
+pdnsutil add-zone-key ZONE zsk 1024 active rsasha256
+pdnsutil add-zone-key ZONE zsk 1024 inactive rsasha256
+```
+
+This will add a 2048-bit RSA Key Signing Key and two 1024-bit RSA Zone Signing Keys.
+One of the ZSKs is inactive and can be rolled to if needed.
+
+## From existing non-DNSSEC non-PowerDNS setups
+It is recommended to [migrate to PowerDNS](migration.md) before securing your
+zones. After that, see the instructions [above](#from-an-existing-PowerDNS-installation).
+
+## From existing DNSSEC non-PowerDNS setups, pre-signed
+Industry standard signed zones can be served natively by PowerDNS, without
+changes. In such cases, signing happens externally to PowerDNS, possibly via
+OpenDNSSEC, ldns-sign or dnssec-sign.
+
+PowerDNS needs to know if a zone should receive DNSSEC processing. To configure,
+run `pdnsutil set-presigned ZONE`.
+
+If you import presigned zones into your database, please do not import the NSEC
+or NSEC3 records. PowerDNS will synthesize these itself. Putting them in the
+database might cause duplicate records in responses. [`zone2sql`](migration.md#zone2sql)
+filters NSEC and NSEC3 automatically.
+
+**Warning** Right now, you will also need to configure NSEC(3) settings for
+pre-signed zones using `pdnsutil set-nsec3`. Default is NSEC, in which case no
+further configuration is necessary.
+
+## From existing DNSSEC non-PowerDNS setups, live signing
+The `pdnsutil` tool features the option to import zone keys in the industry
+standard private key format, version 1.2. To import an existing KSK, use
+
+```
+pdnsutil import-zone-key ZONE FILENAME ksk
+```
+
+replace 'ksk' by 'zsk' for a Zone Signing Key.
+
+If all keys are imported using this tool, a zone will serve mostly identical
+records to before, with the important change that the RRSIG inception dates will
+be different.
+
+**Note**: Within PowerDNS, the 'algorithm' for RSASHA1 keys is modulated based
+on the NSEC3 setting. So if an algorithm=7 key is imported in a zone with no
+configured NSEC3, it will appear as algorithm 5!
+
+# DNSSEC advice & precautions
+DNSSEC is a major change in the way DNS works. Furthermore, there is a bewildering
+array of settings that can be configured.
+
+It is well possible to configure DNSSEC in such a way that your domain will not
+operate reliably, or even, at all. We advise operators to stick to the keying
+defaults of `pdnsutil secure-zone`.
+
+**Note**: GOST may be more widely available in Russia, because it might be
+mandatory to implement this regional standard there.
+
+It is possible to operate a zone with different keying algorithms simultaneously,
+but it has also been observed that this is not reliable.
+
+Depending on your master/slave setup, you may need to tinker with the
+[`SOA-EDIT`](domainmetadata.md#soa-edit) metadata on your master. This is described
+in the [operational instructions](#soa-edit) below.
+
+## Packet sizes, fragments, TCP/IP service
+DNSSEC answers contain (bulky) keying material and signatures, and are therefore
+a lot larger than regular DNS answers. Normal DNS responses almost always fit in
+the 'magical' 512 byte limit previously imposed on DNS.
+
+In order to support DNSSEC, operators must make sure that their network allows for:
+
+- Larger than 512 byte UDP packets on port 53
+- Fragmented UDP packets
+- ICMP packets related to fragmentation
+- TCP queries on port 53
+- EDNS0 queries/responses (filtered by some firewalls)
+
+If any of the conditions outlined above is not met, DNSSEC service will suffer
+or be completely unavailable.
+
+In addition, the larger your DNS answers, the more critical the above becomes.
+It is therefore advised not to provision too many keys, or keys that are
+unnecessarily large.
+
+# Operational instructions
+Several How to's describe operational practices with DNSSEC:
+
+* [KSK Rollover](howtos.md#ksk-rollover)
+* [ZSK Rollover](howtos.md#zsk-rollover)
+
+Below, frequently used commands are described:
+
+## Publishing a DS
+To publish a DS to a parent zone, utilize `pdnsutil show-zone` and take the DS
+from its output, and transfer it securely to your parent zone.
+
+## Going insecure
+```
+pdnsutil disable-dnssec ZONE
+```
+
+**Warning**: Going insecure with a zone that has a DS record in the parent zone
+will make the zone BOGUS. Make sure the parent zone removes the DS record *before*
+going insecure.
+
+## Setting the NSEC modes and parameters
+As stated earlier, PowerDNS uses NSEC by default. If you want to use NSEC3 instead,
+issue:
+
+```
+pdnsutil set-nsec3 ZONE [PARAMETERS]
+```
+
+e.g.
+
+```
+pdnsutil set-nsec3 example.net '1 0 1 ab'
+```
+
+The quoted part is the content of the NSEC3PARAM records, as defined in [RFC 5155
+](https://tools.ietf.org/html/rfc5155#section-4), in order:
+
+* Hash algorithm, should always be `1` (SHA1)
+* Flags, set to `1` for [NSEC3 Opt-out](https://tools.ietf.org/html/rfc5155#section-6), this best set as `0`
+* Number of iterations of the hash function, read [RFC 5155, Section 10.3](https://tools.ietf.org/html/rfc5155#section-10.3) for recommendations
+* Salt (in hexadecimal) to apply during hashing
+
+To convert a zone from NSEC3 to NSEC operations, run:
+
+```
+pdnsutil unset-nsec3 ZONE
+```
+
+**Warning**: Don't change from NSEC to NSEC3 (or the other way around) for zones
+with algorithm 5 (RSASHA1), 6 (DSA-NSEC3-SHA1) or 7 (RSASHA1-NSEC3-SHA1).
+
+## SOA-EDIT: ensure signature freshness on slaves
+As RRSIGs can expire, slave servers need to know when to re-transfer the zone. In
+most implementations (BIND, NSD), this is done by re-signing the full zone outside
+of the nameserver, increasing the SOA serial and serving the new zone on the master.
+
+With PowerDNS in Live-signing mode, the SOA serial is not increased by default
+when the RRSIG dates are rolled.
+
+For zones that use [native](modes-of-operation.md#native-operation) replication
+PowerDNS will serve valid RRSIGs on all servers.
+
+For [master](modes-of-operation.md#master-operation) zones (where replication
+happens by means of AXFR), PowerDNS slaves will automatically re-transfer the zone
+when it notices the RRSIGs have changed, even when the SOA serial is not increased.
+This ensures the zone never serves old signatures.
+
+If your DNS setup uses non-PowerDNS slaves, the slaves need to know when the
+signatures have been updated. This can be accomplished by setting the
+[SOA-EDIT](domainmetadata.md#soa-edit) metadata for DNSSEC signed zones. This
+value controls how the value of the SOA serial is modified by PowerDNS.
+
+**Note**: The SOA serial in the datastore will be untouched, SOA-EDIT is applied
+to DNS answers with the SOA record.
+
+The [`default-soa-edit`](settings.md#default-soa-edit) or [`default-soa-edit-signed`](settings.md#default-soa-edit-signed)
+configuration options can instead be set to ensure SOA-EDIT is set for every zone.
+
+### Possible SOA-EDIT values
+The 'inception' refers to the time the RRSIGs got updated in
+[live-signing mode](#online-signing). This happens every week (see [Signatures](#signatures)).
+The inception time does not depend on local timezone, but some modes below will
+use localtime for representation.
+
+#### INCREMENT-WEEKS
+Increments the serial with the number of weeks since the UNIX epoch. This should
+work in every setup; but the result won't look like YYYYMMDDSS anymore.
+
+For example: a serial of 12345678 will become 12348079 on Wednesday 13th of January
+2016 (2401 weeks after the epoch).
+
+#### INCEPTION-EPOCH
+Sets the new SOA serial number to the maximum of the old SOA serial number, and
+age in seconds of the last inception. This requires your backend zone to use the
+number of seconds since the UNIX epoch as SOA serial. The result is still the age
+in seconds of the last change to the zone, either by operator changes to the zone
+or the 'addition' of new RRSIGs.
+
+As an example, a serial of 12345678 becomes 1452124800 on Wednesday 13th of January
+2016.
+
+#### INCEPTION-INCREMENT
+Uses YYYYMMDDSS format for SOA serial numbers. If the SOA serial from the backend
+is within two days after inception, it gets incremented by two (the backend should
+keep SS below 98). Otherwise it uses the maximum of the backend SOA serial number
+and inception time in YYYYMMDD01 format. This requires your backend zone to use
+YYYYMMDDSS as SOA serial format. Uses localtime to find the day for inception time.
+
+This changes a serial of 2015120810 to 2016010701 on Wednesday 13th of January
+2016.
+
+#### INCEPTION (not recommended)
+Sets the SOA serial to the last inception time in YYYYMMDD01 format. Uses localtime
+to find the day for inception time.
+
+**Warning**: The SOA serial will only change on inception day, so changes to the
+zone will get visible on slaves only on the following inception day.
+
+**Note**: Will be removed in PowerDNS Authoritative Server 4.1.0
+
+#### INCEPTION-WEEK (not recommended)
+Sets the SOA serial to the number of weeks since the epoch, which is the last
+inception time in weeks.
+
+**Warning**: Same problem as INCEPTION.
+
+**Note**: Will be removed in PowerDNS Authoritative Server 4.1.0
+
+#### EPOCH
+Sets the SOA serial to the number of seconds since the epoch.
+
+**Warning**: Don't combine this with AXFR - the slaves would keep refreshing all
+the time. If you need fast updates, sync the backend databases directly with
+incremental updates (or use the same database server on the slaves)
+
+**Note**: Will be removed in PowerDNS Authoritative Server 4.1.0
+
+#### NONE
+Ignore [`default-soa-edit`](settings.md#default-soa-edit) and/or
+[`default-soa-edit-signed`](settings.md#default-soa-edit-signed) setings.
+
+# PKCS\#11 support
+**Note**: This feature is experimental, and not ready for production. Use at your own risk!
+**Note**: As of version 4.0, slot IDs are deprecated, and you are expected to use slot label instead
+
+To enable it, compile PowerDNS Authoritative Server using
+`--enable-experimental-pkcs11` flag on configure. This requires you to have
+p11-kit libraries and headers.
+
+You can also log on to the tokens after starting server, in this case you need
+to edit your PKCS#11 cryptokey record and remove PIN or set it empty. PIN is
+required for assigning keys to zone.
+
+## Using with SoftHSM
+To test this feature, a software HSM can be used. It is **not recommended** to
+use this in production.
+
+Instructions on how to setup SoftHSM to work with the feature after compilation
+on ubuntu/debian (tested with Ubuntu 12 and 14).
+- `apt-get install softhsm p11-kit opensc`
+- create directory /etc/pkcs11/modules
+- Add file called 'softhsm' there with (on newer versions, use softhsm.module)
+ ```
+ module: /home/cmouse/softhsm/lib/softhsm/libsofthsm.so
+ managed: yes
+ ```
+- Verify it works: `p11-kit -l`
+- Create at least two tokens (ksk and zsk) with (slot-number starts from 0)
+
+ ```
+ sudo softhsm --init-token --slot slot-number --label zone-ksk|zone-zsk --pin some-pin --so-pin another-pin
+ ```
+
+- Using pkcs11-tool, initialize your new keys.
+
+ ```
+ sudo pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk|zone-zsk --slot-index slot-number
+ ```
+
+- Assign the keys using (note that token label is not necessarely same as object label, see p11-kit -l)
+
+ ```
+ pdnsutil hsm assign zone rsasha256 ksk|zsk softhsm token-label pin zone-ksk|zsk
+ ```
+
+- Verify that everything worked, you should see valid data there
+
+ ```
+ pdnsutil show-zone zone
+ ```
+
+- SoftHSM signatures are fast enough to be used in live environment.
+
+## Using CryptAS
+Instructions on how to use CryptAS [`Athena IDProtect Key USB Token V2J`](http://www.cryptoshop.com/products/smartcards/idprotect-key-j-laser.html)
+Smart Card token on Ubuntu 14.
+- install the manufacturer`s support software on your system and initialize the Smart Card token as per instructions (do not use PIV).
+- apt-get install p11-kit opensc
+- create directory /etc/pkcs11/modules
+- Add file called 'athena.module' with content
+
+ ```
+ module: /lib64/libASEP11.so
+ managed: yes
+ ```
+
+- Verify it worked, it should resemble output below. do not continue if this does not show up.
+
+ ```
+ $ p11-kit -l
+ athena: /lib64/libASEP11.so
+ library-description: ASE Cryptoki
+ library-manufacturer: Athena Smartcard Solutions
+ library-version: 3.1
+ token: IDProtect#0A50123456789
+ manufacturer: Athena Smartcard Solutions
+ model: IDProtect
+ serial-number: 0A50123456789
+ hardware-version: 1.0
+ firmware-version: 1.0
+ flags:
+ rng
+ login-required
+ user-pin-initialized
+ token-initialized
+ ```
+- Using pkcs11-tool, initialize your new keys. After this IDProtect Manager no longer can show your token certificates and keys, at least on version v6.23.04.
+
+ ```
+ pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-ksk
+ pkcs11-tool --module=/home/cmouse/softhsm/lib/softhsm/libsofthsm.so -l -p some-pin -k --key-type RSA:2048 -a zone-zsk
+ ```
+
+- Verify that keys are there.
+
+ ```
+ $ pkcs11-tool --module=/lib64/libASEP11.so -l -p some-pin -O
+ Using slot 0 with a present token (0x0)
+ Public Key Object; RSA 2048 bits
+ label: zone-ksk
+ Usage: encrypt, verify, wrap
+ Public Key Object; RSA 2048 bits
+ label: zone-zsk
+ Usage: encrypt, verify, wrap
+ Private Key Object; RSA
+ label: zone-ksk
+ Usage: decrypt, sign, unwrap
+ Private Key Object; RSA
+ label: zone-zsk
+ Usage: decrypt, sign, unwrap
+ ```
+
+- Assign the keys using
+
+ ```
+ pdnsutil hsm assign zone rsasha256 ksk|zsk athena IDProtect#0A50123456789 pin zone-ksk|zsk
+ ```
+
+- Verify that everything worked, you should see valid data there.
+
+ ```
+ pdnsutil show-zone zone
+ ```
+
+- Note that the physical token is pretty slow, so you have to use it as hidden master. It has been observed to produce about 1.5signatures/second.
+
+# Secure transfers
+From 3.3.1 and up, PowerDNS support secure DNSSEC transfers as described in
+[draft-koch-dnsop-dnssec-operator-change](https://datatracker.ietf.org/doc/draft-koch-dnsop-dnssec-operator-change/).
+If the [`direct-dnskey`](settings.md#direct-dnskey) option is enabled the foreign
+DNSKEY records stored in the database are added to the keyset and signed with the
+KSK. Without the direct-dnskey option DNSKEY records in the database are silently
+ignored.
+
+# Security
+During typical PowerDNS operation, the private part of the signing keys are
+'online', which can be compared to operating an HTTPS server, where the
+private key is available on the webserver for cryptographic purposes.
+
+In some settings, having such (private) keying material available online is
+considered undesirable. In this case, consider running in pre-signed mode.
+
+# Performance
+DNSSEC has a performance impact, mostly measured in terms of additional memory
+used for the signature caches. In addition, on startup or AXFR-serving, a lot of
+signing needs to happen.
+
+Most best practices are documented in [RFC 6781](https://tools.ietf.org/html/rfc6781).
+
+# Thanks to, acknowledgements
+PowerDNS DNSSEC has been made possible by the help & contributions of many people.
+We would like to thank:
+
+- Peter Koch (DENIC)
+- Olaf Kolkman (NLNetLabs)
+- Wouter Wijngaards (NLNetLabs)
+- Marco Davids (SIDN)
+- Markus Travaille (SIDN)
+- Antoin Verschuren (SIDN)
+- Olafur Guðmundsson (IETF)
+- Dan Kaminsky (Recursion Ventures)
+- Roy Arends (Nominet)
+- Miek Gieben
+- Stephane Bortzmeyer (AFNIC)
+- Michael Braunoeder (nic.at)
+- Peter van Dijk
+- Maik Zumstrull
+- Jose Arthur Benetasso Villanova
+- Stefan Schmidt (CCC ;-))
+- Roland van Rijswijk (Surfnet)
+- Paul Bakker (Brainspark/Fox-IT)
+- Mathew Hennessy
+- Johannes Kuehrer (Austrian World4You GmbH)
+- Marc van de Geijn (bHosted.nl)
+- Stefan Arentz
+- Martin van Hensbergen (Fox-IT)
+- Christoph Meerwald
+- Leen Besselink
+- Detlef Peeters
+- Christof Meerwald
+- Jack Lloyd
+- Frank Altpeter
+- Fredrik Danerklint
+- Vasiliy G Tolstov
+- Brielle Bruns
+- Evan Hunt (ISC)
+- Ralf van der Enden
+- Jan-Piet Mens
+- Justin Clift
+- Kees Monshouwer
+- Aki Tuomi
+- Ruben Kerkhof
+- Christian Hofstaedtler
+- Ruben d'Arco
+- Morten Stevens
+- Pieter Lexis
+- .. this list is far from complete yet ..
--- /dev/null
+# Dynamic DNS Update (RFC2136)
+Starting with the PowerDNS Authoritative Server 3.4.0, DNS update support is available. There are a number of items NOT supported:
+
+* There is no support for GSS*TSIG and SIG (TSIG is supported);
+* WKS records are specifically mentioned in the RFC, we don't specifically care about WKS records;
+* Anything we forgot....
+
+The implementation requires the backend to support a number of new oparations. Currently, the following backends have been modified to support DNS update:
+
+* [gmysql](backend-generic-mysql.md)
+* [gpgsql](backend-generic-postgresql.md)
+* [gsqlite3](backend-generic-sqlite.md)
+* [goracle](backend-generic-oracle.md)
+* [godbc](backend-generic-odbc.md)
+
+# Configuration options
+There are two configuration parameters that can be used within the powerdns configuration file.
+
+## `dnsupdate`
+A setting to enable/disable DNS update support completely. The default is no, which means that DNS updates are ignored by PowerDNS (no message is logged about this!). Change the setting to **dnsupdate=yes** to enable DNS update support. Default is **no**.
+
+## `allow-dnsupdate-from`
+A list of IP ranges that are allowed to perform updates on any domain. The default is 0.0.0.0/0, which means that all ranges are accepted. Multiple entries can be used on this line (**allow-dnsupdate-from=198.51.100.0/8 203.0.113.2/32**). The option can be left empty to disallow everything, this then should be used in combination with the **allow-dnsupdate-from** domainmetadata setting per zone.
+
+## `forward-dnsupdate`
+Tell PowerDNS to forward to the master server if the zone is configured as slave. Masters are determined by the masters field in the domains table. The default behaviour is enabled (yes), which means that it will try to forward. In the processing of the update packet, the **allow-dnsupdate-from** and **TSIG-ALLOW-DNSUPDATE** are processed first, so those permissions apply before the **forward-dnsupdate** is used. It will try all masters that you have configured until one is successful.
+
+The semantics are that first a dynamic update has to be allowed either by the global allow-dnsupdate-from setting, or by a per-zone ALLOW-DNSUPDATE-FROM metadata setting.
+
+Secondly, if a zone has a TSIG-ALLOW-DNSUPDATE metadata setting, that must match too.
+
+So to only allow dynamic DNS updates to a zone based on TSIG key, and regardless of IP address, set allow-dnsupdate-from to empty, set ALLOW-DNSUPDATE-FROM to "0.0.0.0/0" and "::/0" and set the TSIG-ALLOW-DNSUPDATE to the proper key name.
+
+Further information can be found [below](#how-it-works).
+
+# Per zone settings
+For permissions, a number of per zone settings are available via the domain metadata (See [Per zone settings aka Domain Metadata](domainmetadata.md)).
+
+## ALLOW-DNSUPDATE-FROM
+This setting has the same function as described in the configuration options (See [above](#configuration-options)). Only one item is allowed per row, but multiple rows can be added. An example:
+
+```
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘ALLOW-DNSUPDATE-FROM’,’198.51.100.0/8’);
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘ALLOW-DNSUPDATE-FROM’,’203.0.113.2/32’);
+```
+
+This will allow 198.51.100.0/8 and 203.0.113.2/32 to send DNS update messages for the example.org domain.
+
+## TSIG-ALLOW-DNSUPDATE
+This setting allows you to set the TSIG key required to do an DNS update. If you have GSS-TSIG enabled, you can use Kerberos principals here. An example:
+
+```
+sql> insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-DNSUPDATE', 'test');
+```
+
+An example of how to use a TSIG key with the **nsupdate** command:
+
+```
+nsupdate <<!
+server <ip> <port>
+zone example.org
+update add test1.example.org 3600 A 203.0.113.1
+key test kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=
+send
+!
+```
+
+If a TSIG key is set for the domain, it is required to be used for the update. The TSIG is extra security on top of the **ALLOW-DNSUPDATE-FROM** setting. If a TSIG key is set, the IP(-range) still needs to be allowed via **ALLOW-DNSUPDATE-FROM**.
+
+## FORWARD-DNSUPDATE
+See [Configuration options](#configuration-options) for what it does, but per domain.
+
+```
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘FORWARD-DNSUPDATE’,’’);
+```
+
+There is no content, the existence of the entry enables the forwarding. This domain-specific setting is only useful when the configuration option **forward-dnsupdate** is set to 'no', as that will disable it globally. Using the domainmetadata setting than allows you to enable it per domain.
+
+## NOTIFY-DNSUPDATE
+Send a notification to all slave servers after every update. This will speed up the propagation of changes and is very useful for acme verification.
+
+```
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘NOTIFY-DNSUPDATE’,’1’);
+```
+
+## SOA-EDIT-DNSUPDATE
+This configures how the soa serial should be updated. See [below](#soa-serial-updates).
+
+# SOA Serial Updates
+After every update, the soa serial is updated as this is required by section 3.7 of RFC2136. The behaviour is configurable via domainmetadata with the SOA-EDIT-DNSUPDATE option. It has a number of options listed below. If no behaviour is specified, DEFAULT is used.
+
+RFC2136 (Section 3.6) defines some specific behaviour for updates of SOA records. Whenever the SOA record is updated via the update message, the logic to change the SOA is not executed.
+
+**Note**: Powerdns will always use **SOA-EDIT** when serving SOA records, thus a query for the SOA record of the recently update domain, might have an unexpected result due to a SOA-EDIT setting.
+
+An example:
+
+```
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘SOA-EDIT-DNSUPDATE’,’INCREASE’);
+```
+
+This will make the SOA Serial increase by one, for every successful update.
+
+## SOA-EDIT-DNSUPDATE settings
+These are the settings available for **SOA-EDIT-DNSUPDATE**.
+
+* DEFAULT: Generate a soa serial of YYYYMMDD01. If the current serial is lower than the generated serial, use the generated serial. If the current serial is higher or equal to the generated serial, increase the current serial by 1.
+* INCREASE: Increase the current serial by 1.
+* EPOCH: Change the serial to the number of seconds since the EPOCH, aka unixtime.
+* SOA-EDIT: Change the serial to whatever SOA-EDIT would provide. See [Domain metadata](domainmetadata.md)
+* SOA-EDIT-INCREASE: Change the serial to whatever SOA-EDIT would provide. If what SOA-EDIT provides is lower than the current serial, increase the current serial by 1.
+
+# DNS update How-to: Setup dyndns/rfc2136 with dhcpd
+DNS update is often used with DHCP to automatically provide a hostname whenever a new IP-address is assigned by the DHCP server. This section describes how you can setup PowerDNS to receive DNS updates from ISC's dhcpd (version 4.1.1-P1).
+
+## Setting up dhcpd
+We're going to use a TSIG key for security. We're going to generate a key using the following command:
+
+```
+dnssec-keygen -a hmac-md5 -b 128 -n USER dhcpdupdate
+```
+
+This generates two files (Kdhcpdupdate.*.key and Kdhcpdupdate.*.private). You're interested in the .key file:
+
+```
+# ls -l Kdhcp*
+-rw------- 1 root root 53 Aug 26 19:29 Kdhcpdupdate.+157+20493.key
+-rw------- 1 root root 165 Aug 26 19:29 Kdhcpdupdate.+157+20493.private
+
+# cat Kdhcpdupdate.+157+20493.key
+dhcpdupdate. IN KEY 0 3 157 FYhvwsW1ZtFZqWzsMpqhbg==
+```
+
+The important bits are the name of the key (**dhcpdupdate**) and the hash of the key (**FYhvwsW1ZtFZqWzsMpqhbg==**
+
+Using the details from the key you've just generated. Add the following to your dhcpd.conf:
+
+```
+key "dhcpdupdate" {
+ algorithm hmac-md5;
+ secret "FYhvwsW1ZtFZqWzsMpqhbg==";
+};
+```
+
+You must also tell dhcpd that you want dynamic dns to work, add the following section:
+
+```
+ddns-updates on;
+ddns-update-style interim;
+update-static-leases on;
+```
+
+This tells dhcpd to:
+
+1. Enable Dynamic DNS
+2. Which style it must use (interim)
+3. Update static leases as well
+
+For more information on this, consult the dhcpd.conf manual.
+
+Per subnet, you also have to tell **dhcpd** which (reverse-)domain it should update and on which master domain server it is running.
+
+```
+ddns-domainname "example.org";
+ddns-rev-domainname "in-addr.arpa.";
+
+zone example.org {
+ primary 127.0.0.1;
+ key dhcpdupdate;
+}
+
+zone 1.168.192.in-addr.arpa. {
+ primary 127.0.0.1;
+ key dhcpdupdate;
+}
+```
+
+This tells **dhcpd** a number of things:
+
+1. Which domain to use (**ddns-domainname "example.org";**)
+2. Which reverse-domain to use (**dnssec-rev-domainname "in-addr.arpa.";**)
+3. For the zones, where the primary master is located (**primary 127.0.0.1;**)
+4. Which TSIG key to use (**key dhcpdupdate;**). We defined the key earlier.
+
+This concludes the changes that are needed to the **dhcpd** configuration file.
+
+## Setting up PowerDNS
+A number of small changes are needed to powerdns to make it accept dynamic updates from **dhcpd**.
+
+Enabled DNS update (RFC2136) support functionality in PowerDNS by adding the following to the PowerDNS configuration file (pdns.conf).
+
+```
+dnsupdate=yes
+allow-dnsupdate-from=
+```
+
+This tells PowerDNS to:
+
+1. Enable DNS update support([`dnsupdate`](settings.md#dnsupdate))
+2. Allow updates from NO ip-address ([`allow-dnsupdate-from=`](settings.md#allow-dnsupdate-from))
+
+We just told powerdns (via the configuration file) that we accept updates from nobody via the [`allow-dnsupdate-from`](settings.md#allow-dnsupdate-from) parameter. That's not very useful, so we're going to give permissions per zone, via the domainmetadata table.
+
+```
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata(domain_id, kind, content) values(5, ‘ALLOW-DNSUPDATE-FROM’,’127.0.0.1’);
+```
+
+This gives the ip '127.0.0.1' access to send update messages. Make sure you use the ip address of the machine that runs **dhcpd**.
+
+Another thing we want to do, is add TSIG security. This can only be done via the domainmetadata table:
+
+```
+sql> insert into tsigkeys (name, algorithm, secret) values ('dhcpdupdate', 'hmac-md5', 'FYhvwsW1ZtFZqWzsMpqhbg==');
+sql> select id from domains where name='example.org';
+5
+sql> insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-DNSUPDATE', 'dhcpdupdate');
+sql> select id from domains where name='1.168.192.in-addr.arpa';
+6
+sql> insert into domainmetadata (domain_id, kind, content) values (6, 'TSIG-ALLOW-DNSUPDATE', 'dhcpdupdate');
+```
+
+This will:
+
+1. Add the 'dhcpdupdate' key to our PowerDNSinstallation
+2. Associate the domains with the given TSIG key
+
+Restart PowerDNS and you should be ready to go!
+
+# How it works
+This is a short description of how DNS update messages are processed by PowerDNS.
+
+1. The DNS update message is received. If it is TSIG signed, the TSIG is validated against the tsigkeys table. If it is not valid, Refused is returned to the requestor.
+2. A check is performed on the zone to see if it is a valid zone. ServFail is returned when not valid.
+3. The **dnsupdate** setting is checked. Refused is returned when the setting is 'no'.
+4. If the **ALLOW-DNSUPDATE-FROM** has a value (from both domainmetadata and the configuration file), a check on the value is performed. If the requestor (sender of the update message) does not match the values in **ALLOW-DNSUPDATE-FROM**, Refused is returned.
+5. If the message is TSIG signed, the TSIG keyname is compared with the TSIG keyname in domainmetadata. If they do not match, a Refused is send. The TSIG-ALLOW-DNSUPDATE domainmetadata setting is used to find which key belongs to the domain.
+6. The backends are queried to find the backend for the given domain.
+7. If the domain is a slave domain, the **forward-dnsupdate** option and domainmetadata settings are checked. If forwarding to a master is enabled, the message is forward to the master. If that fails, the next master is tried until all masters are tried. If all masters fail, ServFail is returned. If a master succeeds, the result from that master is returned.
+8. A check is performed to make sure all updates/prerequisites are for the given zone. NotZone is returned if this is not the case.
+9. The transaction with the backend is started.
+10. The prerequisite checks are performed (section 3.2 of RFC2136). If a check fails, the corresponding RCode is returned. No further processing will happen.
+11. Per record in the update message, a the prescan checks are performed. If the prescan fails, the corresponding RCode is returned. If the prescan for the record is correct, the actual update/delete/modify of the record is performed. If the update fails (for whatever reason), ServFail is returned. After changes to the records have been applied, the ordername and auth flag are set to make sure DNSSEC remains working. The cache for that record is purged.
+12. If there are records updated and the SOA record was not modified, the SOA serial is updated. See [SOA Serial Updates](#soa-serial-updates). The cache for this record is purged.
+13. The transaction with the backend is committed. If this fails, ServFail is returned.
+14. NoError is returned.
--- /dev/null
+# Per zone settings aka Domain Metadata
+Each served zone can have "metadata". Such metadata determines how this zone
+behaves in certain circumstances.
+
+**Warning**: Domain metadata is only available for DNSSEC capable backends! Make
+sure to enable the proper '-dnssec' setting to benefit, and to have performed
+the DNSSEC schema update.
+
+For the BIND backend, this information is either stored in the
+[`bind-dnssec-db`](backend-bind.md) or the hybrid database, depending on your
+settings.
+
+For the implementation in non-sql backends, please review your backend's documentation.
+
+## ALLOW-AXFR-FROM
+Starting with the PowerDNS Authoritative Server 3.1, per-zone AXFR ACLs can be
+stored in the domainmetadata table.
+
+Each ACL row can list one subnet (v4 or v6), or the magical value 'AUTO-NS' that
+tries to allow all potential slaves in.
+
+Example:
+
+```
+select id from domains where name='example.com';
+7
+insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','AUTO-NS');
+insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','2001:db8::/48');
+```
+
+To dissallow all IP's, except those explicitly allowed by domainmetadata records, add `allow-axfr-ips=` to `pdns.conf`.
+
+## AXFR-SOURCE
+The IP address to use as a source address for sending AXFR and IXFR requests.
+
+## ALLOW-DNSUPDATE-FROM, TSIG-ALLOW-DNSUPDATE, FORWARD-DNSUPDATE, SOA-EDIT-DNSUPDATE, NOTIFY-DNSUPDATE
+See the documentation on [Dynamic DNS update](dnsupdate.md)
+
+## ALSO-NOTIFY
+When notifying this domain, also notify this nameserver (can occur multiple times).
+The nameserver may have contain an optional port number. e.g.:
+
+```
+insert into domainmetadata (domain_id, kind, content) values (7,'ALSO-NOTIFY','192.0.2.1:5300');
+insert into domainmetadata (domain_id, kind, content) values (7,'ALLOW-AXFR-FROM','2001:db8:53::1');
+```
+
+## AXFR-MASTER-TSIG
+Use this named TSIG key to retrieve this zone from its master, see
+[Provisioning signed notification and AXFR requests](tsig.md#provisioning-signed-notification-and-axfr-requests).
+
+## GSS-ALLOW-AXFR-PRINCIPAL
+Allow this GSS principal to perform AXFR retrieval. Most commonly it is
+`host/something@REALM`, `DNS/something@REALM` or `user@REALM`. (See
+[GSS-TSIG support](tsig.md#gss-tsig-support)).
+
+## GSS-ACCEPTOR-PRINCIPAL
+Use this principal for accepting GSS context. (See [GSS-TSIG support](tsig.md#gss-tsig-support)).
+
+## IXFR
+If set to 1, attempt IXFR when retrieving zone updates. Otherwise IXFR is not attempted.
+
+## LUA-AXFR-SCRIPT
+Script to be used to edit incoming AXFRs, see [Modifying a slave zone using a script](modes-of-operation.md#modifying-a-slave-zone-using-a-script).
+This value will override the [`lua-axfr-script`](settings.md#lua-axfr-scriptmaster) setting.
+Use 'NONE' to remove a global script.
+
+## NSEC3NARROW
+Set to "1" to tell PowerDNS this zone operates in NSEC3 'narrow' mode. See
+`set-nsec3` for [`pdnsutil`](dnssec.md#pdnsutil).
+
+## NSEC3PARAM
+NSEC3 parameters of a DNSSEC zone. Will be used to synthesize the NSEC3PARAM
+record. If present, NSEC3 is used, if not present, zones default to NSEC. See
+`set-nsec3` in [`pdnsutil`](dnssec.md#pdnsutil). Example content: "1 0 1 ab".
+
+## PRESIGNED
+This zone carries DNSSEC RRSIGs (signatures), and is presigned. PowerDNS sets
+this flag automatically upon incoming zone transfers (AXFR) if it detects DNSSEC
+records in the zone. However, if you import a presigned zone using `zone2sql` or
+`pdnsutil load-zone` you must explicitly set the zone to be `PRESIGNED`. Note that
+PowerDNS will not be able to correctly serve the zone if the imported data is
+bogus or incomplete. Also see `set-presigned` in [`pdnsutil`](dnssec.md#pdnsutil).
+
+If a zone is presigned, the content of the metadata must be "1" (without the
+quotes). Any other value will not signal prisignedness.
+
+## PUBLISH-CDNSKEY, PUBLISH-CDS
+Whether to publish CDNSKEY and/or CDS recording defined in [RFC 7344](https://tools.ietf.org/html/rfc7344).
+
+To publish CDNSKEY records of the KSKs for the zone, set `PUBLISH-CDNSKEY` to `1`.
+
+To publish CDS records for the KSKs in the zone, set `PUBLISH-CDS` to a comma-
+separated list of [signature algorithm numbers](http://www.iana.org/assignments/ds-rr-types/ds-rr-types.xhtml#ds-rr-types-1).
+
+This metadata can also be set using the [`pdnsutil`](dnssec.md#pdnsutil) options
+`set-publish-cdnskey` and `set-publish-cds`. For an example for an RFC 7344
+key rollover, see the [CDS and CDNSKEY howto](howtos.md#cds-dnskey-key-rollover).
+
+## SOA-EDIT
+When serving this zone, modify the SOA serial number in one of several ways.
+Mostly useful to get slaves to re-transfer a zone regularly to get fresh RRSIGs.
+See the [DNSSEC documentation](dnssec.md#soa-edit-ensure-signature-freshness-on-slaves)
+for more information.
+
+## TSIG-ALLOW-AXFR
+Allow these named TSIG keys to AXFR this zone, see [Provisioning outbound AXFR access](tsig.md#provisioning-outbound-axfr-access).
+
+## TSIG-ALLOW-DNSUPDATE
+This setting allows you to set the TSIG key required to do an [DNS update](dnsupdate.md). If
+[GSS-TSIG](tsig.md#gss-tsig) is enabled, you can put kerberos principals here as well.
--- /dev/null
+# Basic setup: configuring database connectivity
+This shows you how to configure the Generic MySQL backend. This backend
+is called 'gmysql', and needs to be configured in `pdns.conf`. Add the
+following lines, adjusted for your local setup (specifically, you may not
+want to use the 'root' user):
+
+```
+launch=gmysql
+gmysql-host=127.0.0.1
+gmysql-user=root
+gmysql-dbname=pdns
+gmysql-password=mysecretpassword
+```
+
+Remove any earlier [`launch`](settings.md#launch) statements and other configuration
+statements for backends.
+
+**Warning**: Make sure that you can actually resolve the hostname of your database without accessing the database! It is advised to supply an IP address here to prevent chicken/egg problems!
+
+Now start PowerDNS using the monitor command:
+
+```
+# service pdns monitor
+(...)
+Dec 30 13:40:09 About to create 3 backend threads for UDP
+Dec 30 13:40:09 gmysql Connection failed: Unable to connect to database: Access denied for user 'hubert'@'localhost' to database 'pdns-non-existant'
+Dec 30 13:40:09 Caught an exception instantiating a backend: Unable to launch gmysql connection: Unable to connect to database: Access denied for user 'hubert'@'localhost' to database 'pdns-non-existant'
+Dec 30 13:40:09 Cleaning up
+Dec 30 13:40:10 Done launching threads, ready to distribute questions
+```
+
+This is as to be expected - we did not yet add anything to MySQL for PowerDNS to read from. At this point you may also see other errors which indicate that PowerDNS either could not find your MySQL server or was unable to connect to it. Fix these before proceeding.
+
+General MySQL knowledge is assumed in this chapter, please do not interpret these commands as DBA advice!
+
+## Example: configuring MySQL
+Connect to MySQL as a user with sufficient privileges and issue the following commands:
+
+```
+!!include=../modules/gmysqlbackend/schema.mysql.sql
+```
+
+Now we have a database and an empty table. PowerDNS should now be able to launch in monitor mode and display no errors:
+
+```
+# /etc/init.d/pdns monitor
+(...)
+15:31:30 PowerDNS 1.99.0 (Mar 12 2002, 15:00:28) starting up
+15:31:30 About to create 3 backend threads
+15:39:55 [gMySQLbackend] MySQL connection succeeded
+15:39:55 [gMySQLbackend] MySQL connection succeeded
+15:39:55 [gMySQLbackend] MySQL connection succeeded
+```
+
+In a different shell, a sample query sent to the server should now return quickly without data:
+
+```
+$ dig +short www.example.com @127.0.0.1
+$
+```
+
+**Warning**: When debugging DNS problems, don't use `host`. Please use `dig` or `drill`.
+
+And indeed, the control console now shows:
+
+```
+Mar 12 15:41:12 We're not authoritative for 'www.example.com', sending unauth normal response
+```
+
+Now we need to add some records to our database (in a separate shell):
+
+```
+# mysql pdnstest
+mysql> INSERT INTO domains (name, type) values ('example.com', 'NATIVE');
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'example.com','localhost ahu@ds9a.nl 1','SOA',86400,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'example.com','dns-us1.powerdns.net','NS',86400,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'example.com','dns-eu1.powerdns.net','NS',86400,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'www.example.com','192.0.2.10','A',120,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'mail.example.com','192.0.2.12','A',120,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'localhost.example.com','127.0.0.1','A',120,NULL);
+INSERT INTO records (domain_id, name, content, type,ttl,prio)
+VALUES (1,'example.com','mail.example.com','MX',120,25);
+```
+
+**Warning**: Host names and the MNAME of a [SOA](../types.md#soa) records are NEVER terminated with a '.' in PowerDNS storage! If a trailing '.' is present it will inevitably cause problems, problems that may be hard to debug.
+
+If we now requery our database, `www.example.com` should be present:
+
+```
+$ dig +short www.example.com @127.0.0.1
+192.0.2.10
+
+$ dig +short example.com MX @127.0.0.1
+25 mail.example.com
+```
+
+To confirm what happened, issue the command `SHOW *` to the control console:
+
+```
+% show *
+corrupt-packets=0,latency=0,packetcache-hit=2,packetcache-miss=5,packetcache-size=0,
+qsize-a=0,qsize-q=0,servfail-packets=0,tcp-answers=0,tcp-queries=0,
+timedout-packets=0,udp-answers=7,udp-queries=7,
+%
+```
+
+The actual numbers will vary somewhat. Now enter `QUIT` and start PowerDNS as a regular daemon, and check launch status:
+
+```
+# /etc/init.d/pdns start
+pdns: started
+# /etc/init.d/pdns status
+pdns: 8239: Child running
+# /etc/init.d/pdns dump
+pdns: corrupt-packets=0,latency=0,packetcache-hit=0,packetcache-miss=0,
+packetcache-size=0,qsize-a=0,qsize-q=0,servfail-packets=0,tcp-answers=0,
+tcp-queries=0,timedout-packets=0,udp-answers=0,udp-queries=0,
+```
+
+You now have a working database driven nameserver! To convert other zones already present, use the [`zone2sql`](migration.md#zone2sql) tool.
+
+## Common problems
+Most problems involve PowerDNS not being able to connect to the database.
+
+### Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
+Your MySQL installation is probably defaulting to another location for its socket. Can be resolved by figuring out this location (often `/var/run/mysqld.sock`), and specifying it in the configuration file with the [`gmysql-socket`](backend-generic-mysql.md#gmysql-socket) parameter.
+
+Another solution is to not connect to the socket, but to 127.0.0.1, which can be achieved by specifying [`gmysql-host=127.0.0.1`](backend-generic-mysql.md#gmysql-host).
+
+### Host 'x.y.z.w' is not allowed to connect to this MySQL server
+These errors are generic MySQL errors. Solve them by trying to connect to your MySQL database with the MySQL console utility `mysql` with the parameters specified to PowerDNS. Consult the MySQL documentation.
+
+## Typical Errors after Installing
+At this point some things may have gone wrong. Typical errors include:
+
+### binding to UDP socket: Address already in use
+This means that another nameserver is listening on port 53 already. You can resolve this problem by determining if it is safe to shutdown the nameserver already present, and doing so. If uncertain, it is also possible to run PowerDNS on another port. To do so, add [`local-port=5300`](settings.md#local-port) to `pdns.conf`, and try again. This however implies that you can only test your nameserver as clients expect the nameserver to live on port 53.
+
+### binding to UDP socket: Permission denied
+You must be superuser in order to be able to bind to port 53. If this is not a possibility, it is also possible to run PowerDNS on another port. To do so, add [`local-port=5300`](settings.md#local-port) to `pdns.conf`, and try again. This however implies that you can only test your nameserver as clients expect the nameserver to live on port 53.
+
+### Unable to launch, no backends configured for querying
+PowerDNS did not find the `launch=bind` instruction in pdns.conf.
+
+### Multiple IP addresses on your server, PowerDNS sending out answers on the wrong one, Massive amounts of 'recvfrom gave error, ignoring: Connection refused'
+If you have multiple IP addresses on the internet on one machine, UNIX often sends out answers over another interface than which the packet came in on. In such cases, use [`local-address`](settings.md#local-address) to bind to specific IP addresses, which can be comma separated. The second error comes from remotes disregarding answers to questions it didn't ask to that IP address and sending back ICMP errors.
+
+# Using ALIAS records
+The ALIAS record provides a way to have CNAME-like behaviour on the zone apex.
+
+In order to correctly serve ALIAS records, set the [`recursor`](settings.md#recursor)
+setting to an existing resolver:
+
+```
+recursor=[::1]:5300
+```
+
+and add the ALIAS record to your zone apex. e.g.:
+
+```
+$ORIGIN example.net
+$TTL 1800
+
+@ IN SOA ns1.example.net. hostmaster.example.net. 2015121101 1H 15 1W 2H
+
+@ IN NS ns1.example.net.
+
+@ IN ALIAS mywebapp.paas-provider.net.
+```
+
+When the authoritative server receives a query for the A-record for `example.net`,
+it will resolve the A record for `mywebapp.paas-provider.net` and serve an answer
+for `example.net` with that A record.
+
+When a zone containing ALIAS records is transferred over AXFR, the
+[`outgoing-axfr-expand-alias`](settings.md#outgoing-axfr-expand-alias) setting
+controls the behaviour of ALIAS records. When set to 'no' (the default), ALIAS
+records are sent as-is (RRType 65401 and a DNSName in the RDATA) in the AXFR.
+When set to 'yes', PowerDNS will lookup the A and AAAA records of the name in the
+ALIAS-record and send the results in the AXFR.
+
+Set `outgoing-axfr-expand-alias` to 'yes' if your slaves don't understand ALIAS
+or should not look up the addresses themselves. Note that slaves will not
+automatically follow changes in those A/AAAA records unless you AXFR regularly.
+
+## ALIAS and DNSSEC
+Starting with the PowerDNS Authoritative Server 4.0.0, DNSSEC 'washing' of ALIAS
+records is supported on AXFR (**not** on live-siging). Set `outgoing-axfr-expand-alias`
+to 'yes' and enable DNSSEC for the zone on the master. PowerDNS will sign the
+A/AAAA records during the AXFR.
+
+# KSK Rollover
+Before attempting a KSK rollover, please read [RFC 6581 "DNSSEC Operational
+Practices, Version 2", section 4](https://tools.ietf.org/html/rfc6781#section-4)
+carefully to understand the terminology, actions and timelines (TTL and RRSIG
+expiry) involved in rolling a KSK.
+
+This How To describes the "Double-Signature Key Signing Key Rollover" from the
+above mentioned RFC.
+
+To start the rollover, add an **active** new KSK to the zone (example.net in this
+case):
+
+```
+pdnsutil add-zone-key example.net ksk active
+```
+
+Note that a key with same algorith as the KSK to be replaced should be created,
+as this is not an algorithm roll over.
+
+If this zone is of the type 'MASTER', increase the SOA serial. The rollover is
+now in the "New KSK" stage. Retrieve the DS record(s) for the new KSK:
+
+```
+pdnsutil show-zone example.net
+```
+
+And communicate this securely to your registrar/parent zone. Now wait until the
+new DS is published in the parent zone and at least the TTL for the DS records
+has passed. The rollover is now in the "DS Change" state and can continue to the
+"DNSKEY Removal" stage by actually deleting the old KSK.
+
+**Note**: The key-id for the old KSK is shown in the output of `pdnsutil show-zone
+example.net`.
+
+```
+pdnsutil remove-zone-key example.net KEY-ID
+```
+
+The rollover is now complete.
+
+# ZSK Rollover
+This how to describes the way to roll a ZSK that is not a secure entrypoint (a
+ZSK that is not tied to a DS record in the parent zone) using the ["RFC 6781
+Pre-Publish Zone Signing Key Rollover"](https://tools.ietf.org/html/rfc6781#section-4.1.1.1)
+method. The documentation linked above also lists the minimum time between
+stages. **PLEASE READ THAT DOCUMENT CAREFULLY**
+
+First, create a new inactive ZSK for the zone (if one already exists, you can
+skip this step), we add an ECDSA 256 bit key (algorithm 13) here:
+
+```
+pdnsutil add-zone-key example.net zsk inactive ecdsa256
+
+```
+
+You are now almost at the "new DNSKEY"-stage of the rollover, if the zone is of
+type 'MASTER' you'll need to update the SOA serial in the database and wait for
+the slaves to pickup the zone change.
+
+To change the RRSIGs on your records, the new key must be made active. Note: you
+can get the key-ids with `pdnsutil show-zone example.net`:
+
+```
+pdnsutil activate-zone-key example.net new-key-id
+pdnsutil deactivate-zone-key example.net previous-key-id
+```
+
+Again, if this is a 'MASTER'-zone, update the SOA serial. You are now at the "new
+RRSIGs" stage of the roll over.
+
+The last step is to remove the old key from the completely:
+
+```
+pdnsutil remove-zone-key example.net previous-key-id
+```
+
+Don't forget to update the SOA serial for 'MASTER' zones. The rollover is now at
+the "DNSKEY removal" stage and complete.
+
+# CDS & CDNSKEY Key Rollover
+If the upstream registry supports [RFC 7344](https://tools.ietf.org/html/rfc7344)
+key rollovers you can use several [`pdnsutil`](dnssec.md#pdnsutil) commands to do
+this rollover. This HowTo follows the rollover example from the RFCs [Appendix B](https://tools.ietf.org/html/rfc7344#appendix-B).
+
+We assume the zone name is example.com and is already DNSSEC signed.
+
+Start by adding a new KSK to the zone: `pdnsutil add-zone-key example.com ksk 2048 inactive`.
+The "inactive" means that the key is not used to sign any ZSK records. This limits
+the size of `ANY` and DNSKEY responses.
+
+Publish the CDS records: `pdnsutil set-publish-cds example.com`, these records
+will tell the parent zone to update its DS records. Now wait for the DS records
+to be updated in the parent zone.
+
+Once the DS records are updated, do the actual key-rollover: `pdnsutil activate-zone-key example.com new-key-id`
+and `pdnsutil deactivate-zone-key example.com old-key-id`. You can get the `new-key-id`
+and `old-key-id` by listing them through `pdnsutil show-zone example.com`.
+
+After the rollover, wait *at least* until the TTL on the DNSKEY records have
+expired so validating resolvers won't mark the zone as BOGUS. When the wait is
+over, delete the old key from the zone: `pdnsutil remove-zone-key example.com old-key-id`.
+This updates the CDS records to reflect only the new key.
+
+Wait for the parent to pick up on the CDS change. Once the upstream DS records
+show only the DS records for the new KSK, you may disable sending out the CDS
+responses: `pdnsutil unset-publish-cds example.com`.
+
+Done!
+
+# Adding new DNS record types
+Here are the full descriptions on how we added the TLSA record type to all
+PowerDNS products, with links to the actual source code.
+
+First, define the TLSARecordContent class in [dnsrecords.hh](https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsrecords.hh#L396):
+
+```
+class TLSARecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(TLSA)
+
+private:
+ uint8_t d_certusage, d_selector, d_matchtype;
+ string d_cert;
+};
+```
+
+The `includeboilerplate(TLSA)` macro generates the four methods that do everything
+PowerDNS would ever want to do with a record:
+
+- read TLSA records from zonefile format
+- write out a TLSA record in zonefile format
+- read a TLSA record from a packet
+- write a TLSA record to a packet
+
+The [actual parsing code](https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsrecords.cc#L304):
+
+```
+boilerplate_conv(TLSA, 52,
+ conv.xfr8BitInt(d_certusage);
+ conv.xfr8BitInt(d_selector);
+ conv.xfr8BitInt(d_matchtype);
+ conv.xfrHexBlob(d_cert, true);
+ )
+```
+
+This code defines the TLSA rrtype number as 52. Secondly, it says there are 3
+eight bit fields for Certificate Usage, Selector and Match type. Next, it defines
+that the rest of the record is the actual certificate (hash).
+['conv'](https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsparser.hh#L68)
+methods are supplied for all DNS data types in use.
+
+Now add `TLSARecordContent::report()` to [`reportOtherTypes()`](https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/dnsrecords.cc#L594).
+
+And that's it. For completeness, add TLSA and 52 to the QType enum in [`qtype.hh`](https://github.com/PowerDNS/pdns/blob/5a3409cbb4314b84f1171a69c7337386568fa886/pdns/qtype.hh#L116),
+which makes it easier to refer to the TLSA record in code if so required.
--- /dev/null
+# PowerDNS Authoritative Nameserver
+The PowerDNS Authoritative Server is a versatile nameserver which supports a large number of backends. These backends can either be plain zone files or be more dynamic in nature.
+
+Examples of backends include relational databases, other DNS data formats and coprocesses.
+
+# Backends
+PowerDNS has the concepts of 'backends'. A backend is a datastore that the server will consult that contains DNS records (and some meta-data).
+The backends range from database backends (Mysql, PostgreSQL, Oracle) and Bind-zonefiles to co-processes and JSON API's.
+
+Multiple backends can be enabled in the configuration by using the [`launch`](settings.md#launch) option. Each backend can be configured separetly.
+
+## Backend Capabilities
+The following table describes the capabilities of the backends.
+
+| Name | Status | Native | Master | Slave | Superslave | [Autoserial](backend-generic-sql.md#autoserial) | DNSSEC | [Disabled Data](backend-generic-sql.md#disabled-data) | Comments | Launch Name |
+|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|:---|
+| [BIND](backend-bind.md) | Supported | Yes | Yes | Yes | Experimental | No | Yes | No | No\* | `bind` |
+| [Generic MySQL](backend-generic-mysql.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | `gmysql` |
+| [Generic ODBC](backend-generic-odbc.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes| `godbc` |
+| [Generic Oracle](backend-generic-oracle.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | `goracle` |
+| [Generic PostgreSQL](backend-generic-postgresql.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | `gpgsql` |
+| [Generic SQLite 3](backend-generic-sqlite.md) 3 | Supported | Yes | Yes | Yes | Yes | Yes | Yes | Yes | Yes | `gsqlite3` |
+| [GeoIP](backend-geoip.md) | Supported | Yes | No | No | No | No | Yes | No | No | `geoip` |
+| [LDAP](backend-ldap.md) | Supported | Yes | No | No | No | No | No | No | No | `ldap` |
+| [MyDNS](backend-mydns.md) | Supported | Yes | No | No | No | No | No | No | No | `mydns` |
+| [OpenDBX](backend-opendbx.md) | Supported | Yes | Yes | Yes | Yes | No | No | No | No | `opendbx` |
+| [Oracle](backend-oracle.md) | Supported | Yes | Yes | Yes | Yes | Yes | Yes | No | No | `oracle` |
+| [Pipe](backend-pipe.md) | Supported | Yes | No | No | No | No | Partial (no delegation, no key storage) | No | No | `pipe` |
+| [Random](backend-random.md) | Supported | Yes | No | No | No | No | Yes (no key storage) | No | No | `random` |
+| [Remote](backend-remote.md) | Supported | Yes | Yes\* | Yes\* | Yes\* | Yes\* | Yes\* | No | No | `remote` |
+| [TinyDNS](backend-tinydns.md) | Experimental | Yes | Yes | No | No | No | No | No | No | `tinydns` |
+
+\*: Please read the backend-specific documentation.
+
+### Native, Master, Slave, Superslave
+Which [Mode of Operation](modes-of-operation.md) (DNS data replication) is supported.
+
+### Autoserial
+Can the backend [automatically](backend-generic-sql.md#autoserial) generate a SOA serial
+
+### DNSSEC
+Is serving DNSSEC signed data supported?
+
+### Disabled Data
+Can a record be [marked 'disabled'](backend-generic-sql.md#disabled-data) and not be served but still be in the datastore?
+
+### Comments
+Are comments on records supported?
--- /dev/null
+# Installing PowerDNS
+Installation of the PowerDNS Authoritative server on UNIX systems can be done in several ways:
+
+ * Binary packages provided by your distribution
+ * Binary packages provided by PowerDNS on [repo.powerdns.com](https://repo.powerdns.com)
+ * Compiling from source
+
+## Binary Packages
+### Debian-based Systems
+PowerDNS Authoritative Server is available through the [apt](https://packages.debian.org/pdns-server) system.
+
+```
+# apt-get install pdns-server
+```
+
+Debian splits the backends into [several different packages](https://packages.debian.org/pdns-backend), install the required backend as follows:
+
+```
+# apt-get install pdns-backend-$backend
+```
+
+### Redhat-based Systems
+On RedHat based system there are 2 options to install PowerDNS, from
+[EPEL](https://fedoraproject.org/wiki/EPEL), the [repository from Kees
+Monshouwer](https://www.monshouwer.eu/download/3rd_party/pdns/) or from
+[the PowerDNS repositories](https://repo.powerdns.com):
+
+Add either to your list of reposities and install PowerDNS by issueing:
+
+```
+# yum install pdns
+```
+
+The different backends can be installed using
+
+```
+# yum install pdns-backend-$backend
+```
+
+### FreeBSD
+PowerDNS Authoritative Server is available through the [ports](http://www.freshports.org/dns/powerdns/) system:
+
+For the package:
+
+```
+# pkg install dns/powerdns
+```
+
+To have your system build the port:
+```
+cd /usr/ports/dns/powerdns/ && make install clean
+```
+
+### Mac OS X
+PowerDNS Authoritative Server is available through Homebrew:
+
+```
+$ brew install pdns
+```
+
+## From source
+See the [Compiling PowerDNS](../appendix/compiling-powerdns.md) chapter
+
+# After installation
+Once installed, [set your first steps](howtos.md#basic-setup-configuring-database-connectivity)
+using MySQL or start [migrating](migration.md) your data.
--- /dev/null
+# Migrating to PowerDNS
+Before migrating to PowerDNS a few things should be considered.
+
+PowerDNS does not operate as a ['slave'](modes-of-operation.md#slave-operation)
+or ['master'](modes-of-operation.md#master-operation) server with all backends.
+The [Generic SQL](backend-generic-sql.md), [BIND](backend-bind.md) backends have
+the ability to act as master or slave. See the [table of backends](index.md#backend-capabilities)
+which other backends support these modes.
+
+# Using AXFR to a Slave-Capable Backend
+The easiest way to migrate all your zones from your old infrastructure to PowerDNS
+is to add all your domains as a slave domain with your current master as the
+master, wait for the zones to be transferred and change the zones to master.
+Make sure [`slave`](settings.md#slave) is set to "yes" in your pdns.conf.
+
+## To A Generic SQL Backend
+**Note**: This assumes the schema provided with PowerDNS is in place
+
+In order to migrate to a Generic SQL backend, add all your domains to the 'domains'
+table with the IP of your current master. On your current master, make sure that
+this master allows AXFRs to this new slave.
+
+```
+INSERT INTO domains (name,type,master) VALUES ('example.net', 'SLAVE', '198.51.100.101');
+```
+
+Then start PowerDNS and wait for all the zones to be transferred. If this server
+is the new [master](modes-of-operation.md#master-operation), change the type of
+domain in the database:
+
+```
+UPDATE domains set type='MASTER' where type='SLAVE';
+```
+
+And set [`master`](settings.md#master) to "yes" in your pdns.conf and restart
+PowerDNS.
+
+Or, if you want to use [native](modes-of-operation.md#native-operation):
+
+```
+UPDATE domains set type='NATIVE' where type='SLAVE';
+```
+
+## To the BIND backend
+Create a named.conf with all the domains as slave domains, e.g.:
+
+```
+zone "example.net" in {
+ type slave;
+ file "/var/lib/powerdns/zones/example.net.zone";
+ masters {
+ 198.51.100.101;
+ };
+};
+```
+
+Make sure the directory is writable for the `pdns_server` process and that [`bind-config`](backend-bind.md#bind-config)
+parameter references this file. Now start PowerDNS and wait untill all zones are
+transferred. Now you can change the zone type to master:
+
+```
+zone "example.net" in {
+ type master;
+ file "/var/lib/powerdns/zones/example.net.zone";
+};
+```
+
+Don't forget to enable [`master`](settings.md#master) in your pdns.conf and restart,
+or if this setting was already set, use `pdns_control rediscover` to load these
+zones as master zones.
+
+# From zonefiles to PowerDNS
+## Using the BIND backend
+To use the bind backend, set `launch=bind` and `bind-config=/path/to/named.conf`
+in your `pdns.conf`. Note that PowerDNS will not honor any options from named.conf,
+it will only use the `zone` statements. See the [Bind backend](backend-bind.md)
+documentation for more information.
+
+## To a Generic SQL backend
+There are several methods to migrate to a [Generic SQL](backend-generic-sql.md)
+backend.
+
+### Using `zone2sql`
+To migrate, the `zone2sql` tool is provided. This tool parses a BIND `named.conf`
+file and zone files and outputs SQL on standard out, which can then be fed to your
+database. It understands the Bind master file extension `$GENERATE` and will also
+honour `$ORIGIN` and `$TTL`.
+
+For backends supporting slave operation, there is also an option to keep slave
+zones as slaves, and not convert them to native operation.
+
+`zone2sql` can generate SQL for nearly all the Generic SQL backends. See [its
+manpage](../manpages/zone2sql.1.md) for more information.
+
+An example call to `zone2sql` could be:
+
+```
+zone2sql --named-conf=/path/to/named.conf --gmysql | mysql -u pdns -p pdns-db
+```
+
+This will generate the SQL statements for the [Generic MySQL](backend-generic-mysql.md)
+and pipe them into the pdns-db database in MySQL.
+
+# Migrating Data from one Backend to Another Backend
+NB! This is experimental feature.
+
+Syntax: `pdnsutil b2b-migrate old new`
+
+This tool lets you migrate data from one backend to another, it moves all data,
+including zones, metadata and crypto keys (if present). Some example use cases
+are moving from Bind style zonefiles to SQL based, or other way around, or moving
+from MyDNS to gMySQL.
+
+## Prerequisites
+
+ - Target backend must support same features as source from set of domains, zones, metadata, DNSSEC and TSIG. See [Backend Capabilities](index.md)
+ - There must be no data in the target backend, otherwise the migration will fail. This is checked.
+
+You can perform live upgrade with this tool, provided you follow the procedure.
+
+## Moving from source to target.
+
+- Take backups of everything.
+- Configure both backends to pdns.conf, if you have source configured, you can just add target backend. **DO NOT RESTART AUTH SERVER BEFORE YOU HAVE FINISHED**
+- Then run `pdnsutil b2b-migrate old new`, the old and new being configuration prefixes in pdns.conf. If something goes wrong, make sure you properly clear **ALL** data from target backend before retrying.
+- Remove (or comment out) old backend from pdns.conf, and run `pdnsutil rectify-all-zones` and `pdnsutil check-all-zones` to make sure everything is OK.
+- If everything is OK, then go ahead to restart your PowerDNS service. Check logs to make sure everything went ok.
--- /dev/null
+PowerDNS offers full master and slave semantics for replicating domain information.
+Furthermore, PowerDNS can benefit from native database replication.
+
+# Native replication
+Native replication is the default, unless other operation is specifically
+configured. Native replication basically means that PowerDNS will not send out DNS
+update notifications, nor will react to them. PowerDNS assumes that the backend is
+taking care of replication unaided.
+
+MySQL replication has proven to be very robust and well suited, even over
+transatlantic connections between badly peering ISPs. Other PowerDNS users employ
+Oracle replication which also works very well.
+
+To use native replication, configure your backend storage to do the replication
+and do not configure PowerDNS to do so.
+
+# Master operation
+When operating as a master, PowerDNS sends out notifications of changes to slaves,
+which react to these notifications by querying PowerDNS to see if the zone changed,
+and transferring its contents if it has. Notifications are a way to promptly
+propagate zone changes to slaves, as described in [RFC 1996](http://tools.ietf.org/html/rfc1996).
+Since version 4.0.0, the NOTIFY messages have a TSIG record added (transaction
+signature) if zone has been configured to use TSIG and feature has been enabled.
+
+**Warning**: Master support is OFF by default, turn it on by adding
+[`master`](settings.md#master) to the configuration.
+
+**Warning**: If you have DNSSEC-signed zones and non-PowerDNS slaves, please
+check your [`SOA-EDIT`](domainmetadata.md#SOA-EDIT) settings.
+
+**Warning**: Notifications are only sent for domains with type MASTER in your backend.
+
+Left open by RFC 1996 is who is to be notified - which is harder to figure out
+than it sounds. All slaves for this domain must receive a notification but the
+nameserver only knows the names of the slaves - not the IP addresses, which is
+where the problem lies. The nameserver itself might be authoritative for the name
+of its secondary, but not have the data available.
+
+To resolve this issue, PowerDNS tries multiple tactics to figure out the IP
+addresses of the slaves, and notifies everybody. In contrived configurations this
+may lead to duplicate notifications being sent out, which shouldn't hurt.
+
+Some backends may be able to detect zone changes, others may chose to let the
+operator indicate which zones have changed and which haven't. Consult the
+documentation for your backend to see how it processes changes in zones.
+
+To help deal with slaves that may have missed notifications, or have failed to
+respond to them, several override commands are available via the
+[`pdns_control`](../authoritative/running.md#pdnscontrol) tool:
+
+* `pdns_control notify <domain>`
+This instructs PowerDNS to notify all IP addresses it considers to be slaves of this domain.
+
+* `pdns_control notify-host <domain> <ip-address>`
+This is truly an override and sends a notification to an arbitrary IP address.
+Can be used in [`also-notify`](settings.md#also-notify) situations or when PowerDNS
+has trouble figuring out who to notify - which may happen in contrived configurations.
+
+# Slave operation
+On launch, PowerDNS requests from all backends a list of domains which have not been
+checked recently for changes. This should happen every '**refresh**' seconds, as
+specified in the SOA record. All domains that are unfresh are then checked for
+changes over at their master. If the [SOA](../types.md#soa) serial number there
+is higher, the domain is retrieved and inserted into the database. In any case,
+after the check the domain is declared 'fresh', and will only be checked again
+after '**refresh**' seconds have passed.
+
+**Warning**: Slave support is OFF by default, turn it on by adding [`slave`](settings.md#slave) to the configuration.
+**Note**: When running PowerDNS via the provided systemd service file, [`ProtectSystem`](http://www.freedesktop.org/software/systemd/man/systemd.exec.html#ProtectSystem=) is set to `full`, this means PowerDNS is unable to write to e.g. `/etc` and `/home`, possibly being unable to write AXFR's zones.
+
+PowerDNS also reacts to notifies by immediately checking if the zone has updated
+and if so, retransfering it.
+
+All backends which implement this feature must make sure that they can handle
+transactions so as to not leave the zone in a half updated state. MySQL configured
+with either BerkeleyDB or InnoDB meets this requirement, as do PostgreSQL and
+Oracle. The Bindbackend implements transaction semantics by renaming files if and
+only if they have been retrieved completely and parsed correctly.
+
+Slave operation can also be programmed using several [`pdns_control`](running.md#pdnscontrol)
+commands. The `retrieve` command is especially useful as it triggers an immediate
+retrieval of the zone from the configured master.
+
+PowerDNS supports multiple masters. For the BIND backend, the native BIND
+configuration language suffices to specify multiple masters, for SQL based backends,
+list all master servers separated by commas in the 'master' field of the domains table.
+
+Since version 4.0.0, PowerDNS requires that masters sign their
+notifications. During transition and interoperation with other nameservers,
+you can use options **allow-unsigned-notify** to permit unsigned
+notifications. For 4.0.0 this is turned off by default, but it might be
+turned on permanently in future releases.
+
+## IXFR: incremental zone transfers
+If the 'IXFR' zone metadata item is set to 1 for a zone, PowerDNS will attempt to retrieve
+zone updates via IXFR.
+
+As of 4.0.0, if a slave zone changes from non-DNSSEC to DNSSEC, an IXFR
+update will not set the PRESIGNED flag. In addition, a change in NSEC3 mode
+will also not be picked up.
+
+In such cases, make sure to delete the zone contents to force a fresh retrieval.
+
+Finally, IXFR updates that "plug" Empty Non Terminals do not yet remove ENT
+records. A 'pdnsutil rectify-zone' may be required.
+
+PowerDNS itself is currently only able to retrieve updates via IXFR. It can not serve IXFR updates.
+
+## Supermaster: automatic provisioning of slaves
+PowerDNS can recognize so called 'supermasters'. A supermaster is a host which is
+master for domains and for which we are to be a slave. When a master (re)loads a
+domain, it sends out a notification to its slaves. Normally, such a notification
+is only accepted if PowerDNS already knows that it is a slave for a domain.
+
+However, a notification from a supermaster carries more persuasion. When PowerDNS
+determines that a notification comes from a supermaster and it is bonafide, it
+can provision the domain automatically, and configure itself as a slave for that zone.
+
+Before a supermaster notification succeeds, the following conditions must be met:
+- The supermaster must carry a SOA record for the notified domain
+- The supermaster IP must be present in the 'supermaster' table
+- The set of NS records for the domain, as retrieved by the slave from the supermaster, must include the name that goes with the IP address in the supermaster table
+- If your master sends signed NOTIFY it will mark that TSIG key as the TSIG key used for retrieval as well
+- If you turn off **allow-unsigned-supermaster*, then your supermaster(s) are required to sign their notifications.
+
+**Warning**: If you use another PowerDNS server as master and have DNSSEC enabled
+on that server please don't forget to rectify the domains after every change. If
+you don't do this there is no SOA record available and one requirement will fail.
+
+So, to benefit from this feature, a backend needs to know about the IP address
+of the supermaster, and how PowerDNS will be listed in the set of NS records
+remotely, and the 'account' name of your supermaster. There is no need to fill
+the account name out but it does help keep track of where a domain comes from.
+
+**Note**: Removal of zones provisioned using the supermaster must be done on the
+slaves themselves. As there is no way to signal this removal from the master to
+the slave.
+
+## Modifying a slave zone using a script
+The PowerDNS Authoritative Server can invoke a Lua script on an incoming AXFR
+zone transfer. The user-defined function `axfrfilter` within your script is
+invoked for each resource record read during the transfer, and the outcome of
+the function defines what PowerDNS does with the records.
+
+What you can accomplish using a Lua script:
+- Ensure consistent values on SOA
+- Change incoming SOA serial number to a YYYYMMDDnn format
+- Ensure consistent NS RRset
+- Timestamp the zone transfer with a TXT record
+
+To enable a Lua script for a particular slave zone, determine the `domain_id`
+for the zone from the `domains` table, and add a row to the `domainmetadata`
+table for the domain. Supposing the domain we want has an `id` of 3, the
+following SQL statement will enable the Lua script `my.lua` for that domain:
+
+```
+INSERT INTO domainmetadata (domain_id, kind, content) VALUES (3, "LUA-AXFR-SCRIPT", "/lua/my.lua");
+```
+
+**Warning**: The Lua script must both exist and be syntactically correct; if not,
+the zone transfer is not performed.
+
+Your Lua functions have access to the query codes through a pre-defined Lua table
+called `pdns`. For example if you want to check for a CNAME record you can either
+compare `qtype` to the numeric constant 5 or the value `pdns.CNAME` -- they are equivalent.
+
+If your function decides to handle a resource record it must return a result code
+of 0 together with a Lua table containing one or more replacement records to be
+stored in the back-end database (if the table is empty, no record is added).
+If, on the other hand, your function decides not to modify a record, it must
+return pdns.PASS and an empty table indicating that PowerDNS should handle the
+incoming record as normal.
+
+Consider the following simple example:
+
+```
+ function axfrfilter(remoteip, zone, qname, qtype, ttl, prio, content)
+
+ -- Replace each HINFO records with this TXT
+ if qtype == pdns.HINFO then
+ resp = {}
+ resp[1] = { qname = qname,
+ qtype = pdns.TXT,
+ ttl = 99,
+ content = "Hello Ahu!"
+ }
+ return 0, resp
+ end
+
+ -- Grab each _tstamp TXT record and add a time stamp
+ if qtype == pdns.TXT and string.starts(qname, "_tstamp.") then
+ resp = {}
+ resp[1] = {
+ qname = qname,
+ qtype = qtype,
+ ttl = ttl,
+ content = os.date("Ver %Y%m%d-%H:%M")
+ }
+ return 0, resp
+ end
+
+ resp = {}
+ return pdns.PASS, resp
+ end
+
+ function string.starts(s, start)
+ return s.sub(s, 1, s.len(start)) == start
+ end
+```
+
+Upon an incoming AXFR, PowerDNS calls our `axfrfilter` function for each record.
+All HINFO records are replaced by a TXT record with a TTL of 99 seconds and the
+specified string. TXT Records with names starting with `_tstamp.` get their value
+(rdata) set to the current time stamp. All other records are unhandled.
--- /dev/null
+# Performance and Tuning
+In general, best performance is achieved on recent Linux 3.x kernels and using MySQL, although many of the largest PowerDNS installations are based on PostgreSQL. FreeBSD also performs very well.
+
+Database servers can require configuration to achieve decent performance. It is especially worth noting that several vendors ship PostgreSQL with a slow default configuration.
+
+**Warning**: When deploying (large scale) IPv6, please be aware some Linux distributions leave IPv6 routing cache tables at very small default values. Please check and if necessary raise `sysctl net.ipv6.route.max_size`.
+
+# Performance related settings
+When PowerDNS starts up it creates a number of threads to listen for packets. This is configurable with the [`receiver-threads`](settings.md#receiver-threads) setting which defines how many sockets will be opened by the powerdns process. In versions of linux before kernel 3.9 having too many receiver threads set up resulted in decreased performance due to socket contention between multiple CPUs - the typical sweet spot was 3 or 4. For optimal performance on kernel 3.9 and following with [`reuseport`](settings.md#reuseport) enabled you'll typically want a receiver thread for each core on your box if backend latency/performance is not an issue and you want top performance.
+
+Different backends will have different characteristics - some will want to have more parallel instances than others. In general, if your backend is latency bound, like most relational databases are, it pays to open more backends.
+
+This is done with the [`distributor-threads`](settings.md#distributor-threads) setting which says how many distributors will be opened for each receiver thread. Of special importance is the choice between 1 or more backends. In case of only 1 thread, PowerDNS reverts to unthreaded operation which may be a lot faster, depending on your operating system and architecture.
+
+Another very important setting is [`cache-ttl`](settings.md#cache-ttl). PowerDNS caches entire packets it sends out so as to save the time to query backends to assemble all data. The default setting of 20 seconds may be low for high traffic sites, a value of 60 seconds rarely leads to problems.
+
+Some PowerDNS operators set cache-ttl to many hours or even days, and use [`pdns_control`](running.md#pdns_control)` purge` to selectively or globally notify PowerDNS of changes made in the backend. Also look at the [Query Cache](#query-cache) described in this chapter. It may materially improve your performance.
+
+To determine if PowerDNS is unable to keep up with packets, determine the value of the [`qsize-q`](../common/logging.md#counters) variable. This represents the number of packets waiting for database attention. During normal operations the queue should be small.
+
+Logging truly kills performance as answering a question from the cache is an order of magnitude less work than logging a line about it. Busy sites will prefer to turn [`log-dns-details`](settings.md#log-dns-details) off.
+
+# Packet Cache
+PowerDNS by default uses the 'Packet Cache' to recognise identical questions and supply them with identical answers, without any further processing. The default time to live is 10 seconds. It has been observed that the utility of the packet cache increases with the load on your nameserver.
+
+Not all backends may benefit from the packetcache. If your backend is memory based and does not lead to context switches, the packetcache may actually hurt performance.
+
+The size of the packetcache can be observed with `/etc/init.d/pdns show packetcache-size`
+
+# Query Cache
+Besides entire packets, PowerDNS can also cache individual backend queries. Each DNS query leads to a number of backend queries, the most obvious additional backend query is the check for a possible CNAME. So, when a query comes in for the 'A' record for 'www.powerdns.com', PowerDNS must first check for a CNAME for 'www.powerdns.com'.
+
+The Query Cache caches these backend queries, many of which are quite repetitive. PowerDNS only caches queries with no answer, or with exactly one. In the future this may be expanded but this lightweight solution is very simple and therefore fast.
+
+Most gain is made from caching negative entries, ie, queries that have no answer. As these take little memory to store and are typically not a real problem in terms of speed-of-propagation, the default TTL for negative queries is a rather high 60 seconds.
+
+This only is a problem when first doing a query for a record, adding it, and immediately doing a query for that record again. It may then take up to 60 seconds to appear. Changes to existing records however do not fall under the negative query ttl ([`negquery-cache-ttl`](settings.md#negquery-cache-ttl)), but under the generic [`query-cache-ttl`](settings.md#query-cache-ttl) which defaults to 20 seconds.
+
+The default values should work fine for many sites. When tuning, keep in mind that the Query Cache mostly saves database access but that the Packet Cache also saves a lot of CPU because 0 internal processing is done when answering a question from the Packet Cache.
+
+# Performance Monitoring
+## Counters & variables
+A number of counters and variables are set during PowerDNS Authoritative Server operation.
+
+### Counters
+All counters that show the "number of X" count since the last startup of the
+daemon.
+
+* `corrupt-packets`: Number of corrupt packets received
+* `deferred-cache-inserts`: Number of cache inserts that were deferred because of maintenance
+* `deferred-cache-lookup`: Number of cache lookups that were deferred because of maintenance
+* `dnsupdate-answers`: Number of DNS update packets successfully answered
+* `dnsupdate-changes`: Total number of changes to records from DNS update
+* `dnsupdate-queries`: Number of DNS update packets received
+* `dnsupdate-refused`: Number of DNS update packets that were refused
+* `incoming-notifications`: Number of NOTIFY packets that were received
+* `key-cache-size`: Number of entries in the key cache
+* `latency`: Average number of microseconds a packet spends within PowerDNS
+* `meta-cache-size`: Number of entries in the metadata cache
+* `overload-drops`: Number of questions dropped because backends overloaded
+* `packetcache-hit`: Number of packets which were answered out of the cache
+* `packetcache-miss`: Number of times a packet could not be answered out of the cache
+* `packetcache-size`: Amount of packets in the packetcache
+* `qsize-q`: Number of packets waiting for database attention
+* `query-cache-hit`: Number of hits on the [query cache](performance.md#query-cache)
+* `query-cache-miss`: Number of misses on the [query cache](performance.md#query-cache)
+* `rd-queries`: Number of packets sent by clients requesting recursion (regardless of if we'll be providing them with recursion). Since 3.4.0.
+* `recursing-answers`: Number of packets we supplied an answer to after recursive processing
+* `recursing-questions`: Number of packets we performed recursive processing for
+* `recursion-unanswered`: Number of packets we sent to our recursor, but did not get a timely answer for. Since 3.4.0.
+* `security-status`: Security status based on [security polling](../common/security.md#implementation)
+* `servfail-packets`: Amount of packets that could not be answered due to database problems
+* `signature-cache-size`: Number of entries in the signature cache
+* `signatures`: Number of DNSSEC signatures created
+* `sys-msec`: Number of CPU miliseconds sent in system time
+* `tcp-answers-bytes`: Total number of answer bytes sent over TCP (since 4.0.0)
+* `tcp-answers`: Number of answers sent out over TCP
+* `tcp-queries`: Number of questions received over TCP
+* `tcp4-answers-bytes`: Total number of answer bytes sent over TCPv4 (since 4.0.0)
+* `tcp4-answers`: Number of answers sent out over TCPv4
+* `tcp4-queries`: Number of questions received over TCPv4
+* `tcp6-answers-bytes`: Total number of answer bytes sent over TCPv6 (since 4.0.0)
+* `tcp6-answers`: Number of answers sent out over TCPv6
+* `tcp6-queries`: Number of questions received over TCPv6
+* `timedout-packets`: Amount of packets that were dropped because they had to wait too long internally
+* `udp-answers-bytes`: Total number of answer bytes sent over UDP
+* `udp-answers`: Number of answers sent out over UDP
+* `udp-do-queries`: Number of queries received with the DO (DNSSEC OK) bit set
+* `udp-in-errors`: Number of packets, received faster than the OS could process them
+* `udp-noport-errors`: Number of UDP packets where an ICMP response was received that the remote port was not listening
+* `udp-queries`: Number of questions received over UDP
+* `udp-recvbuf-errors`: Number of errors caused in the UDP receive buffer
+* `udp-sndbuf-errors`: Number of errors caused in the UDP send buffer
+* `udp4-answers-bytes`: Total number of answer bytes sent over UDPv4 (Since 4.0.0)
+* `udp4-answers`: Number of answers sent out over UDPv4
+* `udp4-queries`: Number of questions received over UDPv4
+* `udp6-answers-bytes`: Total number of answer bytes sent over UDPv6 (Since 4.0.0)
+* `udp6-answers`: Number of answers sent out over UDPv6
+* `udp6-queries`: Number of questions received over UDPv6
+* `uptime`: Uptime in seconds of the daemon
+* `user-msec`: Number of milliseconds spend in CPU 'user' time
+
+### Ring buffers
+Besides counters, PowerDNS also maintains the ringbuffers. A ringbuffer records events, each new event gets a place in the buffer until it is full. When full, earlier entries get overwritten, hence the name 'ring'.
+
+By counting the entries in the buffer, statistics can be generated. These statistics can currently only be viewed using the webserver and are in fact not even collected without the webserver running.
+
+The following ringbuffers are available:
+
+* **logmessages**: All messages logged
+* **noerror-queries**: Queries for existing records but for a type we don't have.
+Queries for, say, the AAAA record of a domain, when only an A is available. Queries are listed in the following format: name/type. So an AAAA query for pdns.powerdns.com looks like pdns.powerdns.com/AAAA.
+* **nxdomain-queries**: Queries for non-existing records within existing domains.
+If PowerDNS knows it is authoritative over a domain, and it sees a question for a record in that domain that does not exist, it is able to send out an authoritative 'no such domain' message. Indicates that hosts are trying to connect to services really not in your zone.
+* **udp-queries**: All UDP queries seen.
+* **remotes**: Remote server IP addresses.
+Number of hosts querying PowerDNS. Be aware that UDP is anonymous - person A can send queries that appear to be coming from person B.
+* **remote-corrupts**: Remotes sending corrupt packets.
+Hosts sending PowerDNS broken packets, possibly meant to disrupt service. Be aware that UDP is anonymous - person A can send queries that appear to be coming from person B.
+* **remote-unauth**: Remotes querying domains for which we are not authoritative.
+It may happen that there are misconfigured hosts on the internet which are configured to think that a PowerDNS installation is in fact a resolving nameserver. These hosts will not get useful answers from PowerDNS. This buffer lists hosts sending queries for domains which PowerDNS does not know about.
+* **servfail-queries**: Queries that could not be answered due to backend errors.
+For one reason or another, a backend may be unable to extract answers for a certain domain from its storage. This may be due to a corrupt database or to inconsistent data. When this happens, PowerDNS sends out a 'servfail' packet indicating that it was unable to answer the question. This buffer shows which queries have been causing servfails.
+* **unauth-queries**: Queries for domains that we are not authoritative for.
+If a domain is delegated to a PowerDNS instance, but the backend is not made aware of this fact, questions come in for which no answer is available, nor is the authority. Use this ringbuffer to spot such queries.
--- /dev/null
+# Recursion with the Authoritative Server
+From 2.9.5 onwards, PowerDNS offers both authoritative nameserving capabilities
+and a [recursive nameserver](../recursor/index.md) component. These two halves
+are normally separate but many users insist on combining both recursion and
+authoritative service on one IP address. This can be likened to running Apache
+and Squid both on port 80.
+
+However, many sites want to do this anyhow and some with good reason. For
+example, a setup like this allows the creation of fake domains which only exist
+for local users. Such domains often don't end on ".com" or ".org" but on
+".intern" or ".name-of-isp".
+
+PowerDNS can cooperate with either its own recursor or any other you have
+available to deliver recursive service on its port.
+
+By specifying the [`recursor`](settings.md#recursor) option in the configuration
+file, questions requiring recursive treatment will be handed over to the IP
+address specified. An example configuration might be `recursor=203.0.113.7`,
+which designates 203.0.113.7 as the nameserver to handle recursive queries.
+
+**Warning**: Using `recursor` is NOT RECOMMENDED as it comes with many
+potentially nasty surprises. For more info, you can read
+[Dan Bernstein's article](http://cr.yp.to/djbdns/separation.html) on this topic.
+
+Take care not to point [`recursor`](settings.md#recursor) to the PowerDNS
+Authoritative Server itself, which leads to a very tight packet loop!
+
+By specifying [`allow-recursion`](settings.md#allow-recursion), recursion can be
+restricted to netmasks specified. The default is to allow recursion from
+everywhere. Example: `allow-recursion=203.0.113.0/24, 198.51.100.0/26, 192.0.2.4`, `::1`.
+
+## Details
+Questions carry a number of flags. One of these is called 'Recursion Desired'.
+If PowerDNS is configured to allow recursion, AND such a flag is seen, AND the
+IP address of the client is allowed to recurse via PowerDNS, then the packet may
+be handed to the recursing backend.
+
+If a Recursion Desired packet arrives and PowerDNS is configured to allow
+recursion, but not to the IP address of the client, resolution will proceed as
+if the RD flag were unset and the answer will indicate that recursion was not
+available.
+
+It is also possible to use a resolver living on a different port. To do so,
+specify a recursor like this: `recursor=192.0.2.1:5300`.
+
+**Reminder:** [according to RFC3986](https://tools.ietf.org/html/rfc3986#section-3.2.2) for IPv6, the notation is to
+encode the IPv6 IP number in square brackets like this: `recursor=[::1]:5300`, as
+they explain in section 3.2.2: Host:
+
+> A host identified by an Internet Protocol literal address, version 6 [RFC3513] or
+later, is distinguished by enclosing the IP literal within square brackets ("[" and "]").
+This is the only place where square bracket characters are allowed in the URI syntax.
+In anticipation of future, as-yet-undefined IP literal address formats, an
+implementation may use an optional version flag to indicate such a format explicitly
+rather than rely on heuristic determination.
+
+So, be careful! The authoritative `pdns` service won't communicate with `pdns-recursor`
+if you write wrongly the IPv6 IP number in the `recursor` line of `pdns.conf`. Therefore,
+~~`recursor=::1:5300`~~ won't work because of the missing required square brackets ("[" and "]")
+enclosing the IP literal. Please respect IPv6 notation.
+
+If the backend does not answer a question within a large amount of time, this is
+logged as 'Recursive query for remote 198.51.100.15 with internal id 0 was not
+answered by backend within timeout, reusing id'. This may happen when using
+'BIND' as a recursor as it is prone to drop queries which it can't answer
+immediately.
+
+To make sure that the local authoritative database overrides recursive
+information, PowerDNS first tries to answer a question from its own database.
+If that succeeds, the answer packet is sent back immediately without involving
+the recursor in any way. This means that for questions for which there is no
+answer, PowerDNS will consult the recursor for an recursive query, even if
+PowerDNS is authoritative for a domain! This will only cause problems if you
+'fake' domains which don't really exist. This also means that if you delegate a
+subzone to another set or authoritative servers, when a request comes in for
+that sub-zone, PowerDNS will respond with a delegation response (as that is the
+answer from the authoritative perspective) and will *not* involve the recursor.
+
+If you want to create such fake domains or override existing domains, please set
+the `allow-recursion-override` feature (available from 2.9.14 until 2.9.22.6).
+
+Some packets, like those asking for MX records which are needed for SMTP
+transport of email, can be subject to 'additional processing'. This means that a
+recursing nameserver is obliged to try to add A records (IP addresses) for any
+of the mail servers mentioned in the packet, should it have these addresses
+available.
+
+If PowerDNS encounters records needing such processing and finds that it does
+not have the data in its authoritative database, it will send an opportunistic
+quick query to the recursing component to see if it perhaps has such data. This
+question is worded such that the recursing nameserver should return immediately
+such as not to block the authoritative nameserver.
+
+This marks a change from pre-2.9.5 behaviour where a packet was handed wholesale
+to the recursor in case it needed additional processing which could not proceed
+from the authoritative database.
--- /dev/null
+# Running and Operating PowerDNS
+PowerDNS is normally controlled via a SysV-style init.d script, often located in
+`/etc/init.d` or `/etc/rc.d/init.d`. For Linux distributions with systemd, a
+service file is provided (either in the package or in the contrib directory of
+the tarball).
+
+Furthermore, PowerDNS can be run on the foreground for testing or in other init-
+systems that supervise processes.
+
+## Guardian
+When the init-system of the Operating System does not properly supervises processes,
+like SysV init, it is recommended to run PowerDNS with the [`guardian`](settings.md#guardian)
+option set to 'yes'.
+
+When launched with `guardian=yes`, `pdns_server` wraps itself inside a 'guardian'.
+This guardian monitors the performance of the inner `pdns_server` instance which
+shows up in the process list of your OS as `pdns_server-instance`. It is also
+this guardian that [`pdns_control`](#pdns_control) talks to. A **STOP** is
+interpreted by the guardian, which causes the guardian to sever the connection
+to the inner process and terminate it, after which it terminates itself. Requests
+that require data from the actual nameserver are passed to the inner process as well.
+
+# Controlling A Running PowerDNS Server
+As a DNS server is critical infrastructure, downtimes should be avoided as much
+as possible. Even though PowerDNS (re)starts very fast, it offers a way to
+control it while running.
+
+## Control Socket
+The controlsocket is the means to contact a running PowerDNS process. Over this
+socket, instructions can be sent using the `pdns_control` program. The control
+socket is called `pdns.controlsocket` and is created inside the [`socket-dir`](settings.md#socket-dir).
+
+## `pdns_control`
+To communicate with PowerDNS Authoritative Server over the controlsocket, the
+`pdns_control` command is used. The syntax is simple: `pdns_control command arguments`.
+Currently this is most useful for telling backends to rediscover domains or to
+force the transmission of notifications. See [Master Operation](../authoritative/modes-of-operation.md#master-operation).
+
+For all supported `pdns_control` commands and options, see [the manpage](../manpages/pdns_control.1)
+and the output of `pdns_control --help` on your system.
+
+# The SysV init
+This script supplied with the PowerDNS source accepts the following commands:
+
+* `monitor`: Monitor is a special way to view the daemon. It executes PowerDNS in the foreground with a lot of logging turned on, which helps in determining startup problems. Besides running in the foreground, the raw PowerDNS control socket is made available. All external communication with the daemon is normally sent over this socket. While useful, the control console is not an officially supported feature. Commands which work are: `QUIT`, `SHOW *`, `SHOW varname`, `RPING`.
+* `start`: Start PowerDNS in the background. Launches the daemon but makes no special effort to determine success, as making database connections may take a while. Use `status` to query success. You can safely run `start` many times, it will not start additional PowerDNS instances.
+* `restart`: Restarts PowerDNS if it was running, starts it otherwise.
+* `status`: Query PowerDNS for status. This can be used to figure out if a launch was successful. The status found is prefixed by the PID of the main PowerDNS process.
+* `stop`: Requests that PowerDNS stop. Again, does not confirm success. Success can be ascertained with the `status` command.
+* `dump`: Dumps a lot of statistics of a running PowerDNS daemon. It is also possible to single out specific variable by using the `show` command.
+* `show variable`: Show a single statistic, as present in the output of the `dump`.
+* `mrtg`: Dump statistics in mrtg format. See the performance [monitoring](../common/logging.md#performance-monitoring) documentation.
+
+**Note**: Packages provided by Operating System vendors might support different
+or less commands.
+
+# Running in the foreground
+One can run PowerDNS in the foreground by invoking the `pdns_server` executable.
+Without any options, it will load the `pdns.conf` and run. To make sure PowerDNS
+starts in the foreground, add the `--daemon=no` option.
+
+All [settings](settings.md) can be added on the commandline. e.g. to test a new
+database config, you could start PowerDNS like this:
+
+```
+pdns_server --no-config --daemon=no --local-port=5300 --launch=gmysql --gmysql-user=my_user --gmysql-password=mypassword
+```
+
+This starts PowerDNS without loading on-disk config, in the foreground, on all
+network interfaces on port 5300 and starting the [gmysql](backend-generic-mysql.md)
+backend.
+
+## Commandline Parameters
+There are several important command-line switches for `pdns_server`. All [settings](settings.md)
+can also be added as a commandline option (e.g. `pdns_server --daemon=no`) and
+will overwrite any options set in pdns.conf.
+
+### `--help`
+Outputs all known parameters, including those of launched backends, see below.
+
+To run on the command line, use the `pdns_server` binary. For example, to see
+options for the gpgsql backend, use the following:
+
+```
+ $ /usr/sbin/pdns_server --launch=gpgsql --help=gpgsql
+```
+
+### `--list-modules`
+Will list all available modules, both compiled in and in dynamically loadable modules.
+
+### `--config`
+This will dump the config to standard out. Should you combine this with e.g. a
+[`launch`](settings.md#launch) statement (`pdns_server --launch=gpgsql --config`),
+all settings related to that backend (and their defaults) are included in the dump.
+
+# Virtual Hosting
+It may be advantageous to run multiple separate PowerDNS installations on a
+single host, for example to make sure that different customers cannot affect
+each others zones. PowerDNS fully supports running multiple instances on one host.
+
+To generate additional PowerDNS instances, create a `pdns-NAME.conf` in your
+configuration directory (usually `/etc/powerdns`), where `NAME` is the name of
+your virtual configuration.
+
+Following one of the following instructions, PowerDNS will read its configuration
+from the `pdns-NAME.conf` instead of `pdns.conf`.
+
+## Starting virtual instances with Sysv init-scripts
+Symlink the init.d script `pdns` to `pdns-NAME`, where `NAME` is the name of your
+virtual configuration. **Note**: `NAME` must not contain a '-' as this will
+confuse the script.
+
+Internally, the init script calls the binary with the
+[`config-name`](settings.md#config-name) option set to `name`, setting in motion
+the loading of separate configuration files.
+
+When you launch a virtual instance of PowerDNS, the pid-file is saved inside
+[`socket-dir`](settings.md#socket-dir) as `pdns-name.pid`.
+
+**Warning**: Be aware however that the init.d `force-stop` will kill all
+PowerDNS instances!
+
+## Starting virtual instances with systemd
+With systemd it is as simple as calling the correct service instance. Assuming your
+instance is called `myinstance` and `pdns-myinstance.conf` exists in the configuration
+directory, the following command will start the service:
+```
+systemctl start pdns@myinstance.service
+```
+
+Similarly you can enable it at boot:
+```
+systemctl enable pdns@myinstance.service
+```
+
+# Internals
+## How PowerDNS translates DNS queries into backend queries
+A DNS query is not a straightforward lookup. Many DNS queries need to check the
+backend for additional data, for example to determine if an unfound record should
+lead to an NXDOMAIN ('we know about this domain, but that record does not exist')
+or an unauthoritative response.
+
+Simplified, without CNAME processing, wildcards, referrals and DNSSEC, the
+algorithm is like this:
+
+When a query for a `qname`/`qtype` tuple comes in, PowerDNS queries backends to
+find the closest matching SOA, thus figuring out what backend owns this zone.
+When the right backend has been found, PowerDNS issues a `qname`/`ANY` query to
+the backend. If the response is empty, NXDOMAIN is concluded. If the response is
+not empty, any contents matching the original qtype are added to the list of
+records to return, and NOERROR is set.
+
+Each of these records is now investigated to see if it needs 'additional processing'.
+This holds for example for MX records which may point to hosts for which the PowerDNS
+backends also contain data. This involves further lookups for A or AAAA records.
+
+After all additional processing has been performed, PowerDNS sieves out all
+double records which may well have appeared. The resulting set of records is
+added to the answer packet, and sent out.
+
+A zone transfer works by looking up the `domain_id` of the SOA record of the
+name and then listing all records of that `domain_id`. This is why all records
+in a domain need to have the same domain\_id.
+
+If no SOA was found, a REFUSED is returned.
--- /dev/null
+# All Authoritative Server settings
+All PowerDNS Authoritative Server settings are listed here, excluding those that
+originate from backends, which are documented in the relevant chapters. These
+settings can be set inside `pdns.conf` or on the commandline when invoking the
+`pdns` binary.
+
+You can use `+=` syntax to set some variables incrementally, but this requires
+you to have at least one non-incremental setting for the variable to act as base
+setting. This is mostly useful for [`include-dir`](#include-dir) directive.
+
+For boolean settings, specifying the name of the setting without a value means
+`yes`.
+
+## `8bit-dns`
+* Allow 8 bit dns queries
+* Default: no
+* Available since: 4.0.0
+
+Allow 8 bit DNS queries.
+
+## `allow-axfr-ips`
+* IP ranges, separated by commas
+* Default: 127.0.0.0/8,::1
+
+If set, only these IP addresses or netmasks will be able to perform AXFR.
+
+## `allow-dnsupdate-from`
+* IP ranges, separated by commas
+
+Allow DNS updates from these IP ranges.
+
+## `allow-notify-from`
+* IP ranges, separated by commas
+* Default: 0.0.0.0/0,::/0
+* Available since: 3.5.0
+
+Allow AXFR NOTIFY from these IP ranges.
+Setting this to an empty string will drop all incoming notifies.
+
+## `allow-unsigned-notify`
+* Boolean
+* Default: yes
+* Available since: 4.0
+
+Turning this off requires all notifications that are received to be signed by valid TSIG signature for the zone.
+
+## `allow-unsigned-supermaster`
+* Boolean
+* Default: yes
+* Available since: 4.0
+
+Turning this off requires all supermaster notifications to be signed by valid TSIG signature. It will accept any existing key on slave.
+
+## `allow-recursion`
+* IP ranges, separated by commas
+* Default: 0.0.0.0/0
+
+By specifying `allow-recursion`, recursion can be restricted to netmasks
+specified. The default is to allow recursion from everywhere. Example:
+`allow-recursion=198.51.100.0/24, 10.0.0.0/8, 192.0.2.4`.
+
+## `also-notify`
+* IP adresses, separated by commas
+
+When notifying a domain, also notify these nameservers. Example:
+`also-notify=192.0.2.1, 203.0.113.167`. The IP adresses listed in `also-notify`
+always receive a notification. Even if they do not match the list in
+[`only-notify`](#also-notify).
+
+## `any-to-tcp`
+* Boolean
+* Default: yes (no, in <= 4.0.1)
+* Available since: 3.3
+
+Answer questions for the ANY on UDP with a truncated packet that refers the
+remote server to TCP. Useful for mitigating reflection attacks.
+
+## `api`
+* Boolean
+* Default: no
+* Available since: 4.0
+
+Enable/disable the [REST API](../httpapi/README.md). Must also enable `webserver`
+to use the API.
+
+## `api-key`
+* String
+* Available since: 4.0
+
+Static pre-shared authentication key for access to the REST API.
+
+## `api-readonly`
+* Boolean
+* Default: no
+* Available since: 4.0
+
+Disallow data modification through the REST API when set.
+
+## `axfr-lower-serial`
+* Boolean
+* Default: no
+* Available since: 4.0.4
+
+Also AXFR a zone from a master with a lower serial.
+
+## `cache-ttl`
+* Integer
+* Default: 20
+
+Seconds to store packets in the PacketCache. See
+["Packet Cache"](performance.md#packet-cache).
+
+## `carbon-ourname`
+
+* String
+* Default: the hostname of the server
+* Available since: 3.3.1
+
+If sending carbon updates, if set, this will override our hostname. Be careful not to include any dots in this setting, unless you know what you are doing. See
+["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `carbon-server`
+* IP Address
+* Available since: 3.3.1
+
+Send all available metrics to this server via the carbon protocol, which is used
+by graphite and metronome. It has to be an address (no hostnames).
+You may specify an alternate port by appending :port,
+ex: 127.0.0.1:2004. See
+["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `carbon-interval`
+* Integer
+* Default: 30
+* Available since: 3.3.1
+
+If sending carbon updates, this is the interval between them in seconds. See
+["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `chroot`
+* Path
+
+If set, chroot to this directory for more security. See
+["Security settings & considerations"](../common/security.md).
+
+Make sure that `/dev/log` is available from within the chroot. Logging will
+silently fail over time otherwise (on logrotate).
+
+When setting `chroot`, all other paths in the config (except for
+[`config-dir`](#config-dir) and [`module-dir`](#module-dir)) set in the configuration
+are relative to the new root.
+
+## `config-dir`
+* Path
+
+Location of configuration directory (`pdns.conf`). Usually `/etc/powerdns`, but
+this depends on `SYSCONFDIR` during compile-time.
+
+## `config-name`
+* String
+
+Name of this virtual configuration - will rename the binary image. See
+["Virtual hosting"](running.md#virtual-hosting).
+
+## `control-console`
+Debugging switch - don't use.
+
+## `daemon`
+* Boolean
+* Default: no
+
+Operate as a daemon.
+
+## `default-ksk-algorithms`
+* String
+* Default: ecdsa256
+
+The algorithm that should be used for the KSK when running
+[`pdnsutil secure-zone`](../manpages/pdnsutil.1.md).
+Must be one of:
+* rsamd5
+* dh
+* dsa
+* ecc
+* rsasha1
+* rsasha256
+* rsasha512
+* ecc-gost
+* ecdsa256 (ECDSA P-256 with SHA256)
+* ecdsa384 (ECDSA P-384 with SHA384)
+* ed25519
+
+## `default-ksk-size`
+* Integer
+* Default: whichever is default for `default-ksk-algorithms`
+
+The default keysize for the KSK generated with
+[`pdnsutil secure-zone`](../manpages/pdnsutil.1.md).
+
+## `default-soa-name`
+* String
+* Default: a.misconfigured.powerdns.server
+
+Name to insert in the SOA record if none set in the backend.
+
+## `default-soa-edit`
+* String
+* Default: empty
+* Available since: 3.4.7
+
+Use this soa-edit value for all zones if no [`SOA-EDIT`](domainmetadata.md#SOA-EDIT) metadata value is set.
+
+## `default-soa-edit-signed`
+* String
+* Default: empty
+* Available since: 3.4.7
+
+Use this soa-edit value for all signed zones if no [`SOA-EDIT`](domainmetadata.md#SOA-EDIT) metadata value is set. Overrides [`default-soa-edit`](#default-soa-edit)
+
+## `default-soa-mail`
+* String
+
+Mail address to insert in the SOA record if none set in the backend.
+
+## `default-ttl`
+* Integer
+* Default: 3600
+
+TTL to use when none is provided.
+
+## `default-zsk-algorithms`
+* String
+* Default: (empty)
+
+The algorithm that should be used for the ZSK when running
+[`pdnsutil secure-zone`](../manpages/pdnsutil.1.md).
+Must be one of:
+* rsamd5
+* dh
+* dsa
+* ecc
+* rsasha1
+* rsasha256
+* rsasha512
+* ecc-gost
+* ecdsa256 (ECDSA P-256 with SHA256)
+* ecdsa384 (ECDSA P-384 with SHA384)
+* ed25519
+
+## `default-zsk-size`
+* Integer
+* Default: whichever is default for `default-zsk-algorithms`
+
+The default keysize for the ZSK generated with
+[`pdnsutil secure-zone`](../manpages/pdnsutil.1.md).
+
+## `direct-dnskey`
+* Boolean
+* Default: no
+
+Read additional ZSKs from the records table/your BIND zonefile. If not set,
+DNSKEY recornds in the zonefiles are ignored.
+
+## `disable-axfr`
+* Boolean
+* Default: no
+
+Do not allow zone transfers.
+
+## `disable-axfr-rectify`
+* Boolean
+* Default: no
+
+Disable the rectify step during an outgoing AXFR. Only required for regression
+testing.
+
+## `disable-syslog`
+* Boolean
+* Default: no
+
+Do not log to syslog, only to stdout. Use this setting when running inside a
+supervisor that handles logging (like systemd). **Note**: do not use this setting
+in combination with [`daemon`](#daemon) as all logging will disappear.
+
+## `disable-tcp`
+* Boolean
+* Default: no
+
+Do not listen to TCP queries. Breaks RFC compliance.
+
+## `distributor-threads`
+* Integer
+* Default: 3
+
+Number of Distributor (backend) threads to start per receiver thread. See
+["Authoritative Server Performance"](performance.md).
+
+## `dname-processing`
+* Boolean
+* Default: no
+
+Synthesise CNAME records from DNAME records as required. This approximately
+doubles query load. **Do not combine with DNSSEC!**
+
+## `dnssec-key-cache-ttl`
+* Integer
+* Default: 30
+
+Seconds to cache DNSSEC keys from the database. A value of 0 disables caching.
+
+## `dnsupdate`
+* Boolean
+* Default: no
+
+Enable/Disable DNS update (RFC2136) support.
+
+## `do-ipv6-additional-processing`
+* Boolean
+* Default: yes
+
+Perform AAAA additional processing. This sends AAAA records in the ADDITIONAL
+section when sending a referral.
+
+## `domain-metadata-cache-ttl`
+* Integer
+* Default: 60
+
+Seconds to cache domain metadata from the database. A value of 0 disables caching.
+
+## `edns-subnet-processing`
+* Boolean
+* Default: no
+
+Enables EDNS subnet processing, for backends that support it.
+
+## `entropy-source`
+* Path
+* Default: /dev/urandom
+
+Entropy source file to use.
+
+## `forward-dnsupdate`
+* Boolean
+* Default: no
+
+Forward DNS updates sent to a slave to the master.
+
+## `guardian`
+* Boolean
+* Default: no
+
+Run within a guardian process. See ["Guardian"](running.md#guardian).
+
+## `include-dir`
+* Path
+
+Directory to scan for additional config files. All files that end with .conf are
+loaded in order using `POSIX` as locale.
+
+## `launch`
+* Backend names, separated by commas
+
+Which backends to launch and order to query them in. Launches backends. In its
+most simple form, supply all backends that need to be launched. e.g.
+
+```
+launch=bind,gmysql,remote
+```
+
+If you find that you need to a backend multiple times with different configuration,
+you can specify a name for later instantiations. e.g.:
+
+```
+launch=gmysql,gmysql:server2
+```
+
+In this case, there are 2 instances of the gmysql backend, one by the normal name
+and the second one is called 'server2'. The backend configuration item names
+change: e.g. `gmysql-host` is available to configure the `host` setting of the
+first or main instance, and `gmysql-server2-host` for the second one.
+
+## `load-modules`
+* Paths, seperated by commas
+
+If backends are available in nonstandard directories, specify their location here.
+Multiple files can be loaded if separated by commas. Only available in non-static
+distributions.
+
+## `local-address`
+* IPv4 Addresses, separated by commas or whitespace
+* Default: 0.0.0.0
+
+Local IP address to which we bind. It is highly advised to bind to specific
+interfaces and not use the default 'bind to any'. This causes big problems if
+you have multiple IP addresses. Unix does not provide a way of figuring out what
+IP address a packet was sent to when binding to any.
+
+## `non-local-bind`
+* Boolean
+* Default: no
+
+Bind to addresses even if one or more of the [`local-address`'s](#local-address)
+do not exist on this server. Setting this option will enable the needed socket
+options to allow binding to non-local addresses.
+This feature is intended to facilitate ip-failover setups, but it may also
+mask configuration issues and for this reason it is disabled by default.
+
+## `lua-axfr-script`
+
+* String
+* Default: empty
+* Available since: 4.0.4
+
+Script to be used to edit incoming AXFRs, see [Modifying a slave zone using a script](modes-of-operation.md#modifying-a-slave-zone-using-a-script).
+
+## `local-address-nonexist-fail`
+* Boolean
+* Default: no
+
+Fail to start if one or more of the [`local-address`'s](#local-address) do not
+exist on this server.
+
+## `local-ipv6`
+* IPv6 Addresses, separated by commas or whitespace
+* Default: ::
+
+Local IPv6 address to which we bind. It is highly advised to bind to specific
+interfaces and not use the default 'bind to any'. This causes big problems if
+you have multiple IP addresses.
+
+## `local-ipv6-nonexist-fail`
+* Boolean
+* Default: no
+
+Fail to start if one or more of the [`local-ipv6`](#local-ipv6) addresses do not
+exist on this server.
+
+## `local-port`
+* Integer
+* Default: 53
+
+The port on which we listen. Only one port possible.
+
+## `log-dns-details`
+* Boolean
+* Default: no
+
+If set to 'no', informative-only DNS details will not even be sent to syslog,
+improving performance. Available from 2.5 and onwards.
+
+## `logging-facility`
+If set to a digit, logging is performed under this LOCAL facility. See
+["Operational logging using syslog"](../common/logging.md#logging).
+Available from 1.99.9 and onwards. Do not pass names like 'local0'!
+
+## `loglevel`
+* Integer
+* Default: 4
+
+Amount of logging. Higher is more. Do not set below 3
+
+## `log-dns-queries`
+* Boolean
+* Default: no
+
+Tell PowerDNS to log all incoming DNS queries. This will lead to a lot of
+logging! Only enable for debugging! Set [`loglevel`](#loglevel) to at least 5
+to see the logs.
+
+## `lua-prequery-script`
+* Path
+
+Lua script to run before answering a query. This is a feature used internally
+for regression testing. The API of this functionality is not guaranteed to be
+stable, and is in fact likely to change.
+
+## `master`
+* Boolean
+* Default: no
+
+Turn on master support. See ["Modes of operation"](modes-of-operation.md#master-operation).
+
+## `max-cache-entries`
+* Integer
+* Default: 1000000
+
+Maximum number of cache entries. 1 million (the default) will generally suffice
+for most installations.
+
+## `max-ent-entries`
+* Integer
+* Default: 100000
+
+Maximum number of empty non-terminals to add to a zone. This is a protection
+measure to avoid database explosion due to long names.
+
+## `max-nsec3-iterations`
+* Integer
+* Default: 500
+
+Limit the number of NSEC3 hash iterations
+
+## `max-queue-length`
+* Integer
+* Default: 5000
+
+If this many packets are waiting for database attention, consider the situation
+hopeless and respawn.
+
+## `max-signature-cache-entries`
+* Integer
+* Default: 2^64 (on 64-bit systems)
+
+Maximum number of signatures cache entries
+
+## `max-tcp-connections`
+* Integer
+* Default: 20
+
+Allow this many incoming TCP DNS connections simultaneously.
+
+## `module-dir`
+* Path
+
+Directory for modules. Default depends on `PKGLIBDIR` during compile-time.
+
+## `negquery-cache-ttl`
+* Integer
+* Default: 60
+
+Seconds to store queries with no answer in the Query Cache. See
+["Query Cache"](performance.md#query-cache).
+
+## `no-config`
+* Boolean
+* Default: no
+
+Do not attempt to read the configuration file.
+
+## `no-shuffle`
+* Boolean
+* Default: no
+
+Do not attempt to shuffle query results, used for regression testing.
+
+## `overload-queue-length`
+* Integer
+* Default: 0 (disabled)
+
+If this many packets are waiting for database attention, answer any new
+questions strictly from the packet cache.
+
+## `reuseport`
+* Boolean
+* Default: No
+
+On Linux 3.9 and some BSD kernels the `SO_REUSEPORT` option allows each
+receiver-thread to open a new socket on the same port which allows for much
+higher performance on multi-core boxes. Setting this option will enable use of
+`SO_REUSEPORT` when available and seamlessly fall back to a single socket when
+it is not available. A side-effect is that you can start multiple servers on the
+same IP/port combination which may or may not be a good idea. You could use this
+to enable transparent restarts, but it may also mask configuration issues and
+for this reason it is disabled by default.
+
+## `security-poll-suffix`
+* String
+* Default: secpoll.powerdns.com.
+* Available since: 3.4.1
+
+Domain name from which to query security update notifications. Setting this to
+an empty string disables secpoll.
+
+## `server-id`
+* String
+* Default: The hostname of the server
+
+This is the server ID that will be returned on an EDNS NSID query.
+
+## `only-notify`
+* IP Ranges, separated by commas or whitespace
+* Default: 0.0.0.0/0, ::/0
+
+For type=MASTER zones (or SLAVE zones with slave-renotify enabled) PowerDNS
+automatically sends NOTIFYs to the name servers specified in the NS records.
+By specifying networks/mask as whitelist, the targets can be limited. The default
+is to notify the world. To completely disable these NOTIFYs set only-notify to an
+empty value. Independent of this setting, the IP addresses or netmasks in
+[`also-notify`](#also-notify) or ALSO-NOTIFY metadata always receive AXFR NOTIFY.
+
+Note: Even if NOTIFYs are limited by a netmask, PowerDNS first has to resolve all the
+hostnames to get IP addresses. Thus, PowerDNS relies on DNS. If the respective
+authoritative name servers are slow, PowerDNS becomes slow too. To avoid this, set
+only-notify to an empty value and specify the notification targets with ALSO-NOTIFY
+and also-notify.
+
+## `out-of-zone-additional-processing`
+* Boolean
+* Default: yes
+
+Do out of zone additional processing. This means that if a malicious user adds a
+'.com' zone to your server, it is not used for other domains and will not
+contaminate answers. Do not enable this setting if you run a public DNS service
+with untrusted users.
+
+The docs had previously indicated that the default was "no", but the default has
+been "yes" since 2005.
+
+## `outgoing-axfr-expand-alias`
+* Boolean
+* Default: no
+
+If this is enabled, ALIAS records are expanded (synthesised to their A/AAAA)
+during outgoing AXFR. This means slaves will not automatically follow changes
+in those A/AAAA records unless you AXFR regularly!
+
+If this is disabled (the default), ALIAS records are sent verbatim during
+outgoing AXFR. Note that if your slaves do not support ALIAS, they will return
+NODATA for A/AAAA queries for such names.
+
+## `pipebackend-abi-version`
+* Integer
+* Default: 1
+* Removed in: 4.0.0 (is now specific to the backend)
+
+ABI version to use for the pipe backend. See
+["PipeBackend protocol"](backend-pipe.md#pipebackend-protocol).
+
+## `prevent-self-notification`
+* Boolean
+* Default: yes
+* Available since: 3.3
+
+PowerDNS Authoritative Server attempts to not send out notifications to itself
+in master mode. In very complicated situations we could guess wrong and not
+notify a server that should be notified. In that case, set
+prevent-self-notification to "no".
+
+## `query-cache-ttl`
+* Integer
+* Default: 20
+
+Seconds to store queries with an answer in the Query Cache. See
+["Query Cache"](performance.md#query-cache).
+
+## `query-local-address`
+* IPv4 Address
+* Default: 0.0.0.0
+
+The IP address to use as a source address for sending queries. Useful if you
+have multiple IPs and PowerDNS is not bound to the IP address your operating
+system uses by default for outgoing packets.
+
+## `query-local-address6`
+* IPv6 Address
+* Default: ::
+
+Source IP address for sending IPv6 queries.
+
+## `query-logging`
+* Boolean
+* Default: no
+
+Boolean, hints to a backend that it should log a textual representation of
+queries it performs. Can be set at runtime.
+
+## `queue-limit`
+* Integer
+* Default: 1500
+
+Maximum number of milliseconds to queue a query. See
+["Authoritative Server Performance"](performance.md).
+
+## `receiver-threads`
+* Integer
+* Default: 1
+
+Number of receiver (listening) threads to start. See
+["Authoritative Server Performance"](performance.md) for tuning details.
+
+## `recursive-cache-ttl`
+* Integer
+* Default: 10
+
+Seconds to store recursive packets in the PacketCache. See
+["Packet Cache"](performance.md#packet-cache).
+
+## `recursor`
+* IP Address
+
+If set, recursive queries will be handed to the recursor specified here. See
+["Recursion"](recursion.md).
+
+## `retrieval-threads`
+* Integer
+* Default: 2
+
+Number of AXFR slave threads to start.
+
+## `setgid`
+* String
+
+If set, change group id to this gid for more security. See
+["Security settings & considerations"](../common/security.md).
+
+## `setuid`
+* String
+
+If set, change user id to this uid for more security. See
+["Security settings & considerations](../common/security.md).
+
+## `slave`
+* Boolean
+* Default: no
+
+Turn on slave support. See ["Modes of operation"](modes-of-operation.md#slave-operation).
+
+## `slave-cycle-interval`
+* Integer
+* 60
+
+On a master, this is the amounts of seconds between the master checking the SOA
+serials in its database to determine to send out NOTIFYs to the slaves. On slaves,
+this is the number of seconds between the slave checking for updates to zones.
+
+## `slave-renotify`
+* Boolean
+* Default: no
+
+This setting will make PowerDNS renotify the slaves after an AXFR is *received*
+from a master. This is useful when using when running a signing-slave.
+
+## `signing-threads`
+* Integer
+* Default: 3
+
+Tell PowerDNS how many threads to use for signing. It might help improve signing
+speed by changing this number.
+
+## `soa-expire-default`
+* Integer
+* Default: 604800
+
+Default [SOA](../types.md#soa) expire.
+
+## `soa-minimum-ttl`
+* Integer
+* Default: 3600
+
+Default [SOA](../types.md#soa) minimum ttl.
+
+## `soa-refresh-default`
+* Integer
+* Default: 10800
+
+Default [SOA](../types.md#soa) refresh.
+
+## `soa-retry-default`
+* Integer
+* Default: 3600
+
+Default [SOA](../types.md#soa) retry.
+
+## `socket-dir`
+* Path
+
+Where the controlsocket will live. The default depends on `LOCALSTATEDIR` during
+compile-time (usually `/var/run` or `/run`). See
+["Controlsocket"](running.md#controlsocket).
+
+This path will also contain the pidfile for this instance of PowerDNS called
+`pdns.pid` by default. See [`config-name`](#config-name) and
+[Virtual Hosting](running.md#virtual-hosting) how this can differ.
+
+## `tcp-control-address`
+* IP Address
+
+Address to bind to for TCP control.
+
+## `tcp-control-port`
+* Integer
+* Default: 53000
+
+Port to bind to for TCP control.
+
+## `tcp-control-range`
+* IP Ranges, separated by commas or whitespace
+
+Limit TCP control to a specific client range.
+
+## `tcp-control-secret`
+* String
+
+Password for TCP control.
+
+## `traceback-handler`
+* Boolean
+* Default: yes
+
+Enable the Linux-only traceback handler.
+
+## `trusted-notification-proxy`
+* String
+
+IP address of incoming notification proxy
+
+## `udp-truncation-threshold`
+* Integer
+* Default: 1680
+
+EDNS0 allows for large UDP response datagrams, which can potentially raise
+performance. Large responses however also have downsides in terms of reflection
+attacks. Up till PowerDNS Authoritative Server 3.3, the truncation limit was set
+at 1680 bytes, regardless of EDNS0 buffer size indications from the client.
+Beyond 3.3, this setting makes our truncation limit configurable. Maximum value
+is 65535, but values above 4096 should probably not be attempted.
+
+## `version-string`
+* Any of: `anonymous`, `powerdns`, `full`, String
+* Default: full
+
+When queried for its version over DNS
+(`dig chaos txt version.bind @pdns.ip.address`), PowerDNS normally responds
+truthfully. With this setting you can overrule what will be returned. Set the
+`version-string` to `full` to get the default behaviour, to `powerdns` to just
+make it state `served by PowerDNS - http://www.powerdns.com`. The `anonymous`
+setting will return a ServFail, much like Microsoft nameservers do. You can set
+this response to a custom value as well.
+
+## `webserver`
+* Boolean
+* Default: no
+
+Start a webserver for monitoring (and REST API if enabled). See
+["Performance Monitoring"](../common/logging.md#performance-monitoring).
+
+## `webserver-address`
+* IP Address
+* Default: 127.0.0.1
+
+IP Address of webserver to listen on. See
+["Performance Monitoring"](../common/logging.md#performance-monitoring).
+
+## `webserver-allow-from`
+* IP ranges, separated by commas or whitespace
+
+Webserver access is only allowed from these subnets
+
+## `webserver-password`
+* String
+
+The plaintext password required for accessing the webserver. See
+["Performance Monitoring"](../common/logging.md#performance-monitoring).
+
+## `webserver-port`
+* Integer
+* Default: 8001
+
+The port where webserver to listen on. See ["Performance Monitoring"](../common/logging.md#performance-monitoring).
+
+## `webserver-print-arguments`
+* Boolean
+* Default: no
+
+If the webserver should print arguments. See ["Performance Monitoring"](../common/logging.md#performance-monitoring).
+
+## `write-pid`
+* Boolean
+* Default: yes
+
+If a PID file should be written. Available since 4.0.
+
+## `xfr-max-received-mbytes`
+* Integer
+* Default: 100
+
+Specifies the maximum number of received megabytes allowed on an incoming AXFR/IXFR update, to prevent
+resource exhaustion. A value of 0 means no restriction.
--- /dev/null
+# TSIG: shared secret authorization and authentication
+TSIG, as defined in [RFC 2845](http://tools.ietf.org/html/rfc2845), is a method
+for signing DNS messages using shared secrets. Each TSIG shared secret has a name,
+and PowerDNS can be told to allow zone transfer of a domain if the request is
+signed with an authorized name.
+
+In PowerDNS, TSIG shared secrets are stored by the various backends. In case of
+the [`Generic SQL backends`](backend-generic-sql.md), they can be found in the
+'tsigkeys' table. The name can be chosen freely, but the algorithm name will
+typically be 'hmac-md5'. Other supported algorithms are 'hmac-sha1', 'hmac-shaX'
+where X is 224, 256, 384 or 512. The content is a Base64-encoded secret.
+
+**Note**: Most backends require DNSSEC support enabled to support TSIG. For the
+Generic SQL Backend make sure to use the DNSSEC enabled schema and to turn on
+the relevant '-dnssec' flag (for example, gmysql-dnssec)!
+
+## Provisioning outbound AXFR access
+To actually provision a named secret permission to AXFR a zone, set a metadata
+item in the 'domainmetadata' table called `TSIG-ALLOW-AXFR` with the key name in
+the content field. For example:
+
+```
+insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
+select id from domains where name='powerdnssec.org';
+5
+insert into domainmetadata (domain_id, kind, content) values (5, 'TSIG-ALLOW-AXFR', 'test');
+
+$ dig -t axfr powerdnssec.org @127.0.0.1 -y 'test:kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys='
+```
+
+To ease interoperability, the equivalent configuration above in BIND would look like this:
+
+```
+key test. {
+ algorithm hmac-md5;
+ secret "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=";
+};
+
+zone "powerdnssec.org" {
+ type master;
+ file "powerdnssec.org";
+ allow-transfer { key test.; };
+};
+```
+
+A packet authorized and authenticated by a TSIG signature will gain access to a
+zone even if the remote IP address is not otherwise allowed to AXFR a zone.
+
+## Provisioning signed notification and AXFR requests
+To configure PowerDNS to send out TSIG signed AXFR requests for a zone to its
+master(s), set the `AXFR-MASTER-TSIG` metadata item for the relevant domain to
+the key that must be used.
+
+The actual TSIG key must also be provisioned, as outlined in the previous section.
+
+For the Generic SQL backends, configuring the use of TSIG for AXFR requests could
+be achieved as follows:
+
+```
+insert into tsigkeys (name, algorithm, secret) values ('test', 'hmac-md5', 'kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=');
+select id from domains where name='powerdnssec.org';
+5
+insert into domainmetadata (domain_id, kind, content) values (5, 'AXFR-MASTER-TSIG', 'test');
+```
+
+This setup corresponds to the `TSIG-ALLOW-AXFR` access rule defined in the previous section.
+
+In the interest of interoperability, the configuration above is (not quite)
+similar to the following BIND statements:
+
+```
+key test. {
+ algorithm hmac-md5;
+ secret "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=";
+};
+
+server 127.0.0.1 {
+ keys { test.; };
+};
+
+zone "powerdnssec.org" {
+ type slave;
+ masters { 127.0.0.1; };
+ file "powerdnssec.org";
+};
+```
+
+Except that in this case, TSIG will be used for all communications with the master,
+not just those about AXFR requests.
+
+# GSS-TSIG support
+GSS-TSIG allows authentication and authorization of DNS updates or AXFR using
+Kerberos with TSIG signatures.
+
+**Note**: this feature is experimental and subject to change on future releases.
+
+## Prerequisites
+
+- Working Kerberos environment. Please refer to your Kerberos vendor documentation on how to setup it.
+- Principal (such as `DNS/<your.dns.server.name>@REALM`) in either per-user keytab or system keytab.
+
+In particular, if something does not work, read logs and ensure that your kerberos
+environment is ok before filing an issue. Most common problems are time
+synchronization or changes done to the principal.
+
+## Setting up
+To allow AXFR / DNS update to work, you need to configure `GSS-ACCEPTOR-PRINCIPAL`
+in [`domain metadata`](domainmetadata.md). This will define the principal that is
+used to accept any GSS context requests. This *must* match to your keytab. Next
+you need to define one or more `GSS-ALLOW-AXFR-PRINCIPAL` entries for AXFR, or
+`TSIG-ALLOW-DNSUPDATE` entries for DNS update. These must be set to the exact
+initiator principal names you intend to use. No wildcards accepted.
--- /dev/null
+Before proceeding, it is advised to check the release notes for your PowerDNS version, as specified in the name of the distribution file.
+
+Please upgrade to the PowerDNS Authoritative Server 4.0.0 from 3.4.2+. See the [3.X](https://doc.powerdns.com/3/authoritative/upgrading/) upgrade notes if your version is older than 3.4.2.
+
+# 3.4.X to 4.0.0
+
+## Database changes
+No changes have been made to the database schema.
+However, several superfluous queries have been dropped from the SQL backend.
+If you use a non-standard SQL schema, please review the new defaults.
+
+ - `insert-ent-query`, `insert-empty-non-terminal-query`, `insert-ent-order-query` have been replaced by one query named `insert-empty-non-terminal-order-query`
+ - `insert-record-order-query` has been dropped, `insert-record-query` now sets the ordername (or NULL)
+ - `insert-slave-query` has been dropped, `insert-zone-query` now sets the type of zone
+
+## Changed options
+Several options have been removed or renamed, for the full overview of all options, see [settings](settings.md).
+
+### Renamed options
+The following options have been renamed:
+
+ * `experimental-json-interface` ==> [`api`](settings.md#api)
+ * `experimental-api-readonly` ==> [`api-readonly`](settings.md#api-readonly)
+ * `experimental-api-key` ==> [`api-key`](settings.md#api-key)
+ * `experimental-dname-processing` ==> [`dname-processing`](settings.md#dname-processing)
+ * `experimental-dnsupdate` ==> [`dnsupdate`](settings.md#dnsupdate)
+ * `allow-dns-update-from` ==> [`allow-dnsupdate-from`](settings.md#allow-dnsupdate-from)
+ * `forward-dnsupdates` ==> [`forward-dnsupdate`](settings.md#forward-dnsupdate)
+
+### Changed defaults
+
+ * [`default-ksk-algorithms`](settings.md#default-ksk-algorithms) changed from rsasha256 to ecdsa256
+ * [`default-zsk-algorithms`](settings.md#default-zsk-algorithms) changed from rsasha256 to empty
+
+### Removed options
+The following options are removed:
+
+ * `pipebackend-abi-version`, it now a setting per-pipe backend.
+ * `strict-rfc-axfrs`
+ * `send-root-referral`
+
+## API
+The API path has changed to `/api/v1`.
+
+Incompatible change: `SOA-EDIT-API` now follows `SOA-EDIT-DNSUPDATE` instead of `SOA-EDIT` (incl. the fact that it now has a default value of `DEFAULT`).
+You must update your existing `SOA-EDIT-API` metadata (set `SOA-EDIT` to your previous `SOA-EDIT-API` value, and `SOA-EDIT-API` to `SOA-EDIT` to keep the old behaviour).
--- /dev/null
+**Note**: Beyond PowerDNS 2.9.20, the Authoritative Server and Recursor are released separately.
+
+# PowerDNS Recursor 4.0.2
+Released August 26th 2016
+
+This release fixes a regression in 4.x where CNAME records for DNSSEC signed domains were not sorted before the final answers, leading to some clients (notably some versions of Chrome) not being able to extract the required answer from the packet. This happened exclusively for DNSSEC signed domains, but the problem happens even for clients not requesting DNSSEC validation.
+
+Further fixes and changes can be found below:
+
+## Bug fixes
+
+ - [#4264](https://github.com/PowerDNS/pdns/pull/4264): Set `dq.rcode` before calling postresolve
+ - [#4294](https://github.com/PowerDNS/pdns/pull/4294): Honor PIE flags.
+ - [#4310](https://github.com/PowerDNS/pdns/pull/4310): Fix build with LibreSSL, for which OPENSSL_VERSION_NUMBER is irrelevant
+ - [#4340](https://github.com/PowerDNS/pdns/pull/4340): Don't shuffle CNAME records.
+ - [#4354](https://github.com/PowerDNS/pdns/pull/4354): Fix delegation-only
+
+## Additions and enhancements
+
+ - [#4288](https://github.com/PowerDNS/pdns/pull/4288): Respect the timeout when connecting to a protobuf server
+ - [#4300](https://github.com/PowerDNS/pdns/pull/4300): allow newDN to take a DNSName in; document missing methods
+ - [#4301](https://github.com/PowerDNS/pdns/pull/4301): expose SMN toString to lua
+ - [#4318](https://github.com/PowerDNS/pdns/pull/4318): Anonymize the protobuf ECS value as well
+ - [#4324](https://github.com/PowerDNS/pdns/pull/4324): Allow Lua access to the result of the Policy Engine decision, skip RPZ, finish RPZ implementation
+ - [#4349](https://github.com/PowerDNS/pdns/pull/4349): Remove unused `DNSPacket::d_qlen`
+ - [#4351](https://github.com/PowerDNS/pdns/pull/4351): RPZ: Use query-local-address(6) by default
+ - [#4357](https://github.com/PowerDNS/pdns/pull/4357): Move the root DNSSEC data to a header file
+
+# PowerDNS Recursor 4.0.1
+Released July 29th 2016
+
+This release has several improvements with regards to DNSSEC validation and it improves interoperability with DNSSEC clients that expect an AD-bit on validated data when they query with only the DO-bit set.
+
+## Bug fixes
+
+ - [#4119](https://github.com/PowerDNS/pdns/pull/4119) Improve DNSSEC record skipping for non dnssec queries (Kees Monshouwer)
+ - [#4162](https://github.com/PowerDNS/pdns/pull/4162) Don't validate zones from the local auth store, go one level down while validating when there is a CNAME
+ - [#4187](https://github.com/PowerDNS/pdns/pull/4187):
+ * Don't go bogus on islands of security
+ * Check all possible chains for Insecures
+ * Don't go Bogus on a CNAME at the apex
+ - [#4215](https://github.com/PowerDNS/pdns/pull/4215) RPZ: default policy should also override local data RRs
+ - [#4243](https://github.com/PowerDNS/pdns/pull/4243) Fix a crash when the next name in a chained query is empty and `rec_control current-queries` is invoked
+
+## Improvements
+
+ - [#4056](https://github.com/PowerDNS/pdns/pull/4056) OpenSSL 1.1.0 support (Christian Hofstaedtler)
+ - [#4133](https://github.com/PowerDNS/pdns/pull/4133) Add limits to the size of received {A,I}XFR (CVE-2016-6172)
+ - [#4140](https://github.com/PowerDNS/pdns/pull/4140) Fix warnings with gcc on musl-libc (James Taylor)
+ - [#4160](https://github.com/PowerDNS/pdns/pull/4160) Also validate on +DO
+ - [#4164](https://github.com/PowerDNS/pdns/pull/4164) Fail to start when the lua-dns-script does not exist
+ - [#4168](https://github.com/PowerDNS/pdns/pull/4168) Add more Netmask methods for Lua (Aki Tuomi)
+ - [#4210](https://github.com/PowerDNS/pdns/pull/4210) Validate DNSSEC for security polling
+ - [#4217](https://github.com/PowerDNS/pdns/pull/4217) Turn on root-nx-trust by default and log-common-errors=off
+ - [#4207](https://github.com/PowerDNS/pdns/pull/4207) Allow for multiple trust anchors per zone
+ - [#4242](https://github.com/PowerDNS/pdns/pull/4242) Fix compilation warning when building without Protobuf
+
+# PowerDNS Authoritative Server 4.0.1
+Released July 29th 2016
+
+This release fixes two small issues and adds a setting to limit AXFR and IXFR sizes, in response to [CVE-2016-6172](http://www.openwall.com/lists/oss-security/2016/07/06/4).
+
+## Bug fixes
+
+ - [#4126](https://github.com/PowerDNS/pdns/pull/4126) Wait for the connection to the carbon server to be established
+ - [#4206](https://github.com/PowerDNS/pdns/pull/4206) Don't try to deallocate empty PG statements
+ - [#4245](https://github.com/PowerDNS/pdns/pull/4245) Send the correct response when queried for an NSEC directly (Kees Monshouwer)
+ - [#4252](https://github.com/PowerDNS/pdns/pull/4252) Don't include bind files if length <= 2 or > sizeof(filename)
+ - [#4255](https://github.com/PowerDNS/pdns/pull/4255) Catch runtime_error when parsing a broken MNAME
+
+## Improvements
+
+ - [#4044](https://github.com/PowerDNS/pdns/pull/4044) Make DNSPacket return a ComboAddress for local and remote (Aki Tuomi)
+ - [#4056](https://github.com/PowerDNS/pdns/pull/4056) OpenSSL 1.1.0 support (Christian Hofstaedtler)
+ - [#4169](https://github.com/PowerDNS/pdns/pull/4169) Fix typos in a logmessage and exception (Christian Hofsteadtler)
+ - [#4183](https://github.com/PowerDNS/pdns/pull/4183) pdnsutil: Remove checking of ctime and always diff the changes (Hannu Ylitalo)
+ - [#4192](https://github.com/PowerDNS/pdns/pull/4192) dnsreplay: Only add Client Subnet stamp when asked
+ - [#4250](https://github.com/PowerDNS/pdns/pull/4250) Use toLogString() for ringAccount (Kees Monshouwer)
+
+## Additions
+
+ - [#4133](https://github.com/PowerDNS/pdns/pull/4133) Add limits to the size of received {A,I}XFR (CVE-2016-6172)
+ - [#4142](https://github.com/PowerDNS/pdns/pull/4142) Add used filedescriptor statistic (Kees Monshouwer)
+
+# PowerDNS Recursor 4.0.0
+Released July 11th 2016
+
+PowerDNS Recursor 4.0.0 is part of [the great 4.x "Spring Cleaning"](http://blog.powerdns.com/2015/11/28/powerdns-spring-cleaning/) of PowerDNS which lasted through the end of 2015.
+
+As part of the general cleanup, we did the following:
+
+- Moved to C++ 2011, a cleaner more powerful version of C++ that has allowed us to [improve the quality of implementation](http://bert-hubert.blogspot.nl/2015/01/on-c2011-quality-of-implementation.html) in many places.
+- Implemented dedicated infrastructure for dealing with DNS names that is fully "DNS Native" and needs less escaping and unescaping
+- Switched to binary storage of DNS records in all places
+- Moved ACLs to a dedicated Netmask Tree
+- Implemented a version of [RCU](https://en.wikipedia.org/wiki/Read-copy-update) for configuration changes
+- Instrumented our use of the memory allocator, reduced number of malloc calls substantially.
+- The Lua hook infrastructure was redone using LuaWrapper; old scripts will no longer work, but new scripts are easier to write under the new interface.
+
+In addition to this cleanup, which has many internal benefits and solves longstanding issues with escaped domain names, 4.0.0 brings the following major new features:
+
+- RPZ aka Response Policy Zone support
+- IXFR slaving in the PowerDNS Recursor for RPZ
+- DNSSEC processing in Recursor (Authoritative has had this for years)
+- DNSSEC validation (without NSEC(3) proof validation)
+- EDNS Client Subnet support in PowerDNS Recursor (Authoritative has had this for years)
+- Lua asynchronous queries for per-IP/per-domain status
+- Caches that can now be wiped per whole zone instead of per name
+- Statistics on authoritative server response times (split for IPv4 and IPv6)
+- APIs are no longer marked as 'experimental' and had one final URL change
+- New metric: tcp-answer-bytes to measure DNS TCP/IP bandwidth, and many other new metrics
+
+Please be aware that beyond the items listed here, there have been heaps of tiny changes. As always, please carefully test a new release before deploying it.
+
+This release features the following fixes compared to rc1:
+
+ - [#3989](https://github.com/PowerDNS/pdns/pull/3989) Fix usage of std::distance() in DNSName::isPartOf() (signed/unsigned comparisons)
+ - [#4017](https://github.com/PowerDNS/pdns/pull/4017) Fix building without Lua. Add `isTcp` to `dq`.
+ - [#4023](https://github.com/PowerDNS/pdns/pull/4023) Actually log on dnssec=log-fail
+ - [#4028](https://github.com/PowerDNS/pdns/pull/4028) DNSSEC fixes (NSEC casing, send DO-bit over TCP, DNSSEC trace additions)
+ - [#4052](https://github.com/PowerDNS/pdns/pull/4052) Don't fail configure on missing fcontext.hpp
+ - [#4096](https://github.com/PowerDNS/pdns/pull/4096) Don't call `commit()` if we skipped all the records
+
+It has the following improvements:
+
+ - [#3400](https://github.com/PowerDNS/pdns/pull/3400) Enable building on OpenIndiana
+ - [#4016](https://github.com/PowerDNS/pdns/pull/4016) Log protobuf messages for cache hits. Add policy tags in gettag()
+ - [#4040](https://github.com/PowerDNS/pdns/pull/4040) Allow DNSSEC validation when chrooted
+ - [#4094](https://github.com/PowerDNS/pdns/pull/4094) Sort included html files for improved reproducibility (Christian Hofstaedtler)
+
+And these additions:
+
+ - [#3981](https://github.com/PowerDNS/pdns/pull/3981) Import Javascript sources for libs shipped with Recursor (Christian Hofstaedtler)
+ - [#4012](https://github.com/PowerDNS/pdns/pull/4012) add tags support to ProtobufLogger.py
+ - [#4032](https://github.com/PowerDNS/pdns/pull/4032) Set the existing policy tags in `dq` for `{pre,post}resolve`
+ - [#4077](https://github.com/PowerDNS/pdns/pull/4077) Add DNSSEC validation statistics
+ - [#4090](https://github.com/PowerDNS/pdns/pull/4090) Allow reloading the lua-config-file at runtime
+ - [#4097](https://github.com/PowerDNS/pdns/pull/4097) Allow logging DNSSEC bogus in any mode
+ - [#4125](https://github.com/PowerDNS/pdns/pull/4125) Add protobuf fields for the query's time in the response
+
+## PowerDNS Recursor 4.0.0-rc1
+Released June 9th 2016
+
+This first (and hopefully last) Release Candidate contains the finishing touches
+to the experimental DNSSEC support by adding (Negative) Trust Anchor support and
+fixing a possible issue with DNSSEC and forwarded domains:
+
+- [#3910](https://github.com/PowerDNS/pdns/pull/3910) Add (Negative) Trust Anchor management
+- [#3926](https://github.com/PowerDNS/pdns/pull/3926) Set +CD on forwarded recursive queries
+
+Other changes:
+
+- [#3941](https://github.com/PowerDNS/pdns/pull/3941) Ensure delegations from local auth zones are followed
+- [#3924](https://github.com/PowerDNS/pdns/pull/3924) Add a virtual hosting unit-file
+- [#3929](https://github.com/PowerDNS/pdns/pull/3929) Set the FDs in the unit file to a sane value
+
+Bug fixes:
+
+- [#3961](https://github.com/PowerDNS/pdns/pull/3961) Fix building on EL6 i386
+- [#3957](https://github.com/PowerDNS/pdns/pull/3957) Add error reporting when parsing forward-zones(-recurse) (Aki Tuomi)
+
+## PowerDNS Recursor 4.0.0-beta1
+Released May 27th 2016
+
+This release fixes a bug in the DNSSEC implementation where a name would we validated as bogus when talking to non-compliant authoritative servers:
+
+- [#3875](https://github.com/PowerDNS/pdns/pull/3875) Disable DNSSEC for domain where the auth responds with FORMERR or NOTIMP
+
+## Improvements
+
+- [#3866](https://github.com/PowerDNS/pdns/pull/3866) Increase max FDs in systemd unit file
+- [#3905](https://github.com/PowerDNS/pdns/pull/3905) Add a dnssec=process-no-validate option and make it default
+
+## Bug fixes
+
+- [#3881](https://github.com/PowerDNS/pdns/pull/3881) Fix the `noEdnsOutQueries` counter
+- [#3892](https://github.com/PowerDNS/pdns/pull/3892) support `clock_gettime` for platforms that require -lrt
+
+## PowerDNS Recursor 4.0.0-alpha3
+Released May 10th 2016
+
+This release features several leaps in the correctness and stability of the DNSSEC implementation.
+
+Notable changes are:
+
+- [#3752](https://github.com/PowerDNS/pdns/pull/3752) Correct handling of query flags in conformance with [RFC 6840](https://tools.ietf.org/html/rfc6840)
+
+## Bug fixes
+
+- [#3804](https://github.com/PowerDNS/pdns/pull/3804) Fix a memory leak in DNSSEC validation
+- [#3785](https://github.com/PowerDNS/pdns/pull/3785) and [#3390](https://github.com/PowerDNS/pdns/pull/3390) Correctly validate insecure delegations
+- [#3606](https://github.com/PowerDNS/pdns/pull/3606) Various DNSSEC fixes, disabling DNSSEC on forward-zones
+- [#3681](https://github.com/PowerDNS/pdns/pull/3681) Catch exception with a malformed DNSName in `rec_control wipe-cache`
+- [#3779](https://github.com/PowerDNS/pdns/pull/3779), [#3768](https://github.com/PowerDNS/pdns/pull/3768), [#3766](https://github.com/PowerDNS/pdns/pull/3766), [#3783](https://github.com/PowerDNS/pdns/pull/3783) and [#3789](https://github.com/PowerDNS/pdns/pull/3789) DNSName and other hardening improvements
+
+## Improvements
+
+- [#3801](https://github.com/PowerDNS/pdns/pull/3801) Add missing Lua rcodes bindings
+- [#3587](https://github.com/PowerDNS/pdns/pull/3587) Update L-Root addresses
+
+## PowerDNS Recursor 4.0.0-alpha2
+Released March 9th 2016
+
+Note that the DNSSEC implementation has several bugs in this release, it is advised to set `dnssec=off` in your recursor.conf.
+
+This release features many low-level performance fixes. Other notable changes since 4.0.0-alpha1 are:
+
+- [#3259](https://github.com/PowerDNS/pdns/pull/3259), [#3280](https://github.com/PowerDNS/pdns/pull/3280) The PowerDNS Recursor now properly uses GNU autoconf and autotools for building and installing
+- OpenSSL crypto primitives are now used for DNSSEC validation
+- [#3313](https://github.com/PowerDNS/pdns/pull/3313) Implement the logic we need to generate EDNS MAC fields in dnsdist & read them in recursor ([blogpost](http://blog.powerdns.com/2016/01/27/per-device-dns-settings-selective-parental-control/)
+- [#3350](https://github.com/PowerDNS/pdns/pull/3350) Add lowercase-outgoing feature to Recursor
+- [#3410](https://github.com/PowerDNS/pdns/pull/3410) Recuweb is now built-in to the daemon
+- [#3230](https://github.com/PowerDNS/pdns/pull/3230) API: drop JSONP, add web security headers (Christian Hofstaedtler)
+- [#3485](https://github.com/PowerDNS/pdns/pull/3485) Allow multiple carbon-servers
+- [#3427](https://github.com/PowerDNS/pdns/pull/3427), [#3479](https://github.com/PowerDNS/pdns/pull/3479), [#3472](https://github.com/PowerDNS/pdns/pull/3472) MTasker modernization (Andrew Nelless)
+
+### Bug fixes
+
+- [#3444](https://github.com/PowerDNS/pdns/pull/3444), [#3442](https://github.com/PowerDNS/pdns/pull/3442) RPZ IXFR fixes
+- [#3448](https://github.com/PowerDNS/pdns/pull/3448) Remove edns-subnet-whitelist whitelist pointing to powerdns.com (Christian Hofstaedtler)
+- [#3293](https://github.com/PowerDNS/pdns/pull/3293) make asynchronous UDP Lua queries work again in 4.x
+- [#3365](https://github.com/PowerDNS/pdns/pull/3365) Apply rcode set in UDPQueryResponse callback (Jan Broers)
+- [#3244](https://github.com/PowerDNS/pdns/pull/3244) Fix the forward zones in the recursor
+- [#3135](https://github.com/PowerDNS/pdns/pull/3135) Use 56 bits instead of 64 in EDNS Client Subnet option (Winfried Angele)
+- [#3527](https://github.com/PowerDNS/pdns/pull/3527) Make the recursor counters atomic
+
+### Improvements
+
+- [#3435](https://github.com/PowerDNS/pdns/pull/3435) Add `toStringNoDot` and `chopOff` functions to Lua
+- [#3437](https://github.com/PowerDNS/pdns/pull/3352) Add `pdns.now` timeval struct to recursor Lua
+- [#3352](https://github.com/PowerDNS/pdns/pull/3352) Cache improvements
+- [#3502](https://github.com/PowerDNS/pdns/pull/3502) Make second argument to pdnslog optional (Thiago Farina)
+- [#3520](https://github.com/PowerDNS/pdns/pull/3520) Reduce log level of periodic statistics to notice (Jan Broers)
+
+## PowerDNS Recursor 4.0.0-alpha1
+Released December 24th 2015
+
+# PowerDNS Authoritative Server 4.0.0
+Released July 11th 2016
+
+PowerDNS Authoritative Server 4.0.0 is part of [the great 4.x "Spring Cleaning"](http://blog.powerdns.com/2015/11/28/powerdns-spring-cleaning/)
+of PowerDNS which lasted through the end of 2015.
+
+As part of the general cleanup and improvements, we did the following:
+
+- Moved to C++ 2011, a cleaner more powerful version of C++ that has allowed us to [improve the quality of implementation](http://bert-hubert.blogspot.nl/2015/01/on-c2011-quality-of-implementation.html) in many places.
+- Implemented dedicated infrastructure for dealing with DNS names that is fully "DNS Native" and needs less escaping and unescaping.
+- All backends derived from the Generic SQL backend use [prepared statements](authoritative/backend-generic-sql.md).
+- Both the server and `pdns_control` do the right thing when `chroot`'ed.
+
+In addition to this cleanup, 4.0.0 brings the following new features:
+
+- A revived ODBC backend ([godbc](authoritative/backend-generic-odbc.md)).
+- A revived LDAP backend ([ldap](authoritative/backend-ldap.md)).
+- Support for [CDS/CDNSKEY](authoritative/howtos.md#cds-cdnskey-key-rollover) and [RFC 7344](https://tools.ietf.org/html/rfc7344) key-rollovers.
+- Support for the [ALIAS](authoritative/howtos.md#using-alias-records) record.
+- The webserver and API are no longer marked experimental.
+ - The API-path has moved to `/api/v1`
+- DNSUpdate is no longer experimental.
+- Default ECDSA (algorithms 13 and 14) support without external dependencies.
+- Experimental support for ed25519 DNSSEC signatures (when compiled with libsodium support).
+- IXFR consumption support.
+- Many new `pdnsutil` commands
+ - `help` command now produces the help
+ - Warns if the configuration file cannot be read
+ - Does not check disabled records with `check-zone` unless verbose mode is enabled
+ - `create-zone` command creates a new zone
+ - `add-record` command to add records
+ - `delete-rrset` and `replace-rrset` commands to delete and add rrsets
+ - `edit-zone` command that spawns `$EDITOR` with the zone contents in zonefile format regardless of the backend used ([blogpost](http://blog.powerdns.com/2016/02/02/powerdns-authoritative-the-new-old-way-to-manage-domains/)
+
+The following backend have been dropped in 4.0.0:
+
+- LMDB.
+- Geo (use the improved [GeoIP](authoritative/backend-geoip.md) instead).
+
+Important changes:
+
+- `pdnssec` has been renamed to `pdnsutil`
+- PowerDNS Authoritative Server now listens by default on all IPv6 addresses.
+- The default for `pdnsutil secure-zone` has been changed from 1 2048 bit RSA KSK and 1 1024 bit RSA ZSK to a single 256 bit ECDSA (algorithm 13, ECDSAP256SHA256) key.
+- Several superfluous queries have been dropped from the SQL backend, if you use a non-standard SQL schema, please review the new defaults
+ - `insert-ent-query`, `insert-empty-non-terminal-query`, `insert-ent-order-query` have been replaced by one query named `insert-empty-non-terminal-order-query`
+ - `insert-record-order-query` has been dropped, `insert-record-query` now sets the ordername (or NULL)
+ - `insert-slave-query` has been dropped, `insert-zone-query` now sets the type of zone
+- Crypto++ and mbedTLS support is dropped, these are replaced by OpenSSL
+- The INCEPTION, INCEPTION-WEEK and EPOCH SOA-EDIT metadata values are marked as deprecated and will be removed in 4.1
+
+The final release has the following bug fixes compared to rc2:
+
+ - [#4071](https://github.com/PowerDNS/pdns/pull/4071) Abort on backend failures at startup and retry while running (Kees Monshouwer)
+ - [#4099](https://github.com/PowerDNS/pdns/pull/4099) Don't leak TCP connection descriptor if `pthread_create()` failed
+ - [#4137](https://github.com/PowerDNS/pdns/pull/4137) gsqlite3: Check whether foreign keys should be turned on (Aki Tuomi)
+
+And the following improvements:
+
+ - [#3051](https://github.com/PowerDNS/pdns/pull/3051) Better error message for unfound new slave domains
+ - [#4123](https://github.com/PowerDNS/pdns/pull/4123) check-zone: warn on mismatch between algo and NSEC mode
+
+## PowerDNS Authoritative Server 4.0.0-rc2
+Released June 29th 2016
+
+**note**: rc1 was tagged in git but never officially released.
+Kees Monshouwer discovered an issue in the gmysql backend that would terminate the daemon on a connection error, this fixed in rc2.
+
+This Release Candidate adds IXFR consumption and fixes some issues with prepared statements:
+
+ - [#3937](https://github.com/PowerDNS/pdns/pull/3937) GSQL: use lazy prepared statements (Aki Tuomi)
+ - [#3949](https://github.com/PowerDNS/pdns/pull/3949) Implement IXFR-based slaving for Authoritative, fix duplicate AXFRs
+ - [#4066](https://github.com/PowerDNS/pdns/pull/4066) Don't die on a mysql timeout (Kees Monshouwer)
+
+Other improvements:
+
+ - [#4061](https://github.com/PowerDNS/pdns/pull/4061) Various fixes, a MySQL-query fix that improves performance and one that allows shorter best matches in getAuth()
+ - [#3962](https://github.com/PowerDNS/pdns/pull/3962) Fix OpenBSD support
+ - [#3972](https://github.com/PowerDNS/pdns/pull/3972) API: change PATCH/PUT on zones to return 204 No Content instead of full zone (Christian Hofstaedtler)
+ - [#3917](https://github.com/PowerDNS/pdns/pull/3917) Remotebackend: Add getAllDomains call (Aki Tuomi)
+
+Bug fixes and changes:
+
+ - [#3998](https://github.com/PowerDNS/pdns/pull/3998) remove gsql::isOurDomain for now (Kees Monshouwer)
+ - [#3989](https://github.com/PowerDNS/pdns/pull/3989) Fix usage of std::distance() in DNSName::isPartOf()
+ - [#4001](https://github.com/PowerDNS/pdns/pull/4001) re enable validDNSName() check (Kees Monshouwer)
+ - [#3930](https://github.com/PowerDNS/pdns/pull/3930) Have pdns_control bind-add-zone check for zonefile
+ - [#3400](https://github.com/PowerDNS/pdns/pull/3400) Fix building on OpenIndiana
+ - [#3961](https://github.com/PowerDNS/pdns/pull/3961) Allow building on CentOS 6 i386
+ - [#3940](https://github.com/PowerDNS/pdns/pull/3940) auth: Don't build dnsbulktest and dnstcpbench if boost is too old, fixes building on CentOS 6
+ - [#3931](https://github.com/PowerDNS/pdns/pull/3931) Rename `notify` to `pdns_notify` (Christian Hofstaedtler)
+
+## PowerDNS Authoritative Server 4.0.0-beta1
+Released May 27th 2016
+
+This release features several small fixes and deprecations.
+
+## Improvements and Additions
+
+- [#3851](https://github.com/PowerDNS/pdns/pull/3851) Disable algorithm 13 and 14 if OpenSSL does not support ecdsa or the required curves (Kees Monshouwer)
+- [#3857](https://github.com/PowerDNS/pdns/pull/3857) Add simple stubquery tool for testing the stubresolver
+- [#3859](https://github.com/PowerDNS/pdns/pull/3859) build scripts: Stop patching config-dir in pdns.conf (Christian Hofstaedtler)
+- [#3872](https://github.com/PowerDNS/pdns/pull/3872) Add support for multiple carbon servers
+- [#3901](https://github.com/PowerDNS/pdns/pull/3901) Add support for virtual hosting with systemd
+
+## Bug fixes
+
+- [#3856](https://github.com/PowerDNS/pdns/pull/3856) Deal with unset name in nproxy replies
+
+## PowerDNS Authoritative Server 4.0.0-alpha3
+Released May 11th 2016
+
+Notable changes since 4.0.0-alpha2
+
+- [#3415](https://github.com/PowerDNS/pdns/pull/3415) pdnsutil: add clear-zone command
+- [#3586](https://github.com/PowerDNS/pdns/pull/3415) Remove send-root-referral option
+- [#3578](https://github.com/PowerDNS/pdns/pull/3415) Add disable-syslog option
+- [#3733](https://github.com/PowerDNS/pdns/pull/3415) ALIAS improvements: DNSSEC and optional on-AXFR expansion of records
+- [#3764](https://github.com/PowerDNS/pdns/pull/3764) Notify support for systemd
+- [#3807](https://github.com/PowerDNS/pdns/pull/3807) Add TTL settings for DNSSECKeeper's caches
+
+### Bug fixes
+
+- [#3553](https://github.com/PowerDNS/pdns/pull/3553) pdnsutil: properly show key sizes for presigned zones in show-zone
+- [#3507](https://github.com/PowerDNS/pdns/pull/3507) webserver: mask out the api-key setting (Christian Hofstaedtler)
+- [#3580](https://github.com/PowerDNS/pdns/pull/3580) bindbackend: set domain in list() (Kees Monshouwer)
+- [#3595](https://github.com/PowerDNS/pdns/pull/3595) pdnsutil: add NS record without trailing dot with create-zone
+- [#3653](https://github.com/PowerDNS/pdns/pull/3653) Allow tabs as whitespace in zonefiles
+- [#3666](https://github.com/PowerDNS/pdns/pull/3666) Restore recycle backend behaviour (Kees Monshouwer)
+- [#3612](https://github.com/PowerDNS/pdns/pull/3612) Prevent segfault in PostgreSQL backend
+- [#3779](https://github.com/PowerDNS/pdns/pull/3779), [#3768](https://github.com/PowerDNS/pdns/pull/3768), [#3766](https://github.com/PowerDNS/pdns/pull/3766), [#3783](https://github.com/PowerDNS/pdns/pull/3783) and [#3789](https://github.com/PowerDNS/pdns/pull/3789) DNSName and other hardening improvements
+- [#3784](https://github.com/PowerDNS/pdns/pull/3784) fix SOA caching with multiple backends (Kees Monshouwer)
+- [#3827](https://github.com/PowerDNS/pdns/pull/3827) Force NSEC3PARAM algorithm to 1, fixes validation issues when set to not 1
+
+### Improvements
+
+- [#3637](https://github.com/PowerDNS/pdns/pull/3637), [#3678](https://github.com/PowerDNS/pdns/pull/3678), [#3740](https://github.com/PowerDNS/pdns/pull/3740) Correct root-zone slaving and serving (Kees Monshouwer and others)
+- [#3495](https://github.com/PowerDNS/pdns/pull/3495) API: Add discovery endpoint (Christian Hofstaedtler)
+- [#3389](https://github.com/PowerDNS/pdns/pull/3389) pdnsutil: support chroot
+- [#3596](https://github.com/PowerDNS/pdns/pull/3396) Remove botan-based ecdsa and rsa signers (Kees Monshouwer)
+- [#3478](https://github.com/PowerDNS/pdns/pull/3478), [#3603](https://github.com/PowerDNS/pdns/pull/3603), [#3628](https://github.com/PowerDNS/pdns/pull/3628) Various build system improvements (Ruben Kerkhof)
+- [#3621](https://github.com/PowerDNS/pdns/pull/3621) Always lowercase when inserting into the database
+- [#3651](https://github.com/PowerDNS/pdns/pull/3651) Rename PUBLISH\_\* to PUBLISH-\* domainmetadata
+- [#3656](https://github.com/PowerDNS/pdns/pull/3656) API: clean up cryptokeys resource (Christian Hofstaedtler)
+- [#3632](https://github.com/PowerDNS/pdns/pull/3632) pdnsutil: Fix exit statuses to constants and return 0 when success (saltsa)
+- [#3655](https://github.com/PowerDNS/pdns/pull/3655) API: Fix set-ptr to honor SOA-EDIT-API (Christian Hofstaedtler)
+- [#3720](https://github.com/PowerDNS/pdns/pull/3720) Many fixes for dnswasher (Robert Edmonds)
+- [#3707](https://github.com/PowerDNS/pdns/pull/3707), [#3788](https://github.com/PowerDNS/pdns/pull/3788) Make MySQL timeout configurable (Kees Monshouwer and Brynjar Eide)
+- [#3806](https://github.com/PowerDNS/pdns/pull/3806) Move key validity check out of `fromISCMap()`, improves DNSSEC performance
+- [#3820](https://github.com/PowerDNS/pdns/pull/3806) pdnsutil load-zone: ignore double SOA
+
+## PowerDNS Authoritative Server 4.0.0-alpha2
+Released February 25th 2016
+
+Notable changes since 4.0.0-alpha1
+
+- [#3037](https://github.com/PowerDNS/pdns/pull/3037) Remove superfluous gsql queries and stop relying on schema defaults
+- [#3176](https://github.com/PowerDNS/pdns/pull/3176), [#3139](https://github.com/PowerDNS/pdns/pull/3139) OpenSSL support (Christian Hofstaedtler and Kees Monshouwer)
+- [#3128](https://github.com/PowerDNS/pdns/pull/3128) ECDSA support to DNSSEC infra via OpenSSL (Kees Monshouwer)
+- [#3281](https://github.com/PowerDNS/pdns/pull/3281), [#3283](https://github.com/PowerDNS/pdns/pull/3283), [#3363](https://github.com/PowerDNS/pdns/pull/3363) Remove Crypto++ and mbedTLS support
+- [#3298](https://github.com/PowerDNS/pdns/pull/3298) Implement pdnsutil create-zone zone nsname, add-record, delete-rrset, replace-rrset
+- [#3407](https://github.com/PowerDNS/pdns/pull/3407) API: Permit wildcard manipulation (Aki Tuomi)
+- [#3230](https://github.com/PowerDNS/pdns/pull/3230) API: drop JSONP, add web security headers (Christian Hofstaedtler)
+- [#3428](https://github.com/PowerDNS/pdns/pull/3428) API: Fix zone/records design mistake (Christian Hofstaedtler)
+ - **Note**: this is a breaking change from alpha1, please review the [API documentation](httpapi/api_spec.md)
+
+### Bug fixes
+
+- [#3124](https://github.com/PowerDNS/pdns/pull/3124) Fix several bugs with introduced with the change to a single signing key (e.g. the SEP bit is set on these single keys)
+- [#3151](https://github.com/PowerDNS/pdns/pull/3151) Catch DNSName build errors in dynhandler (Christian Hofstaedtler)
+- [#3264](https://github.com/PowerDNS/pdns/pull/3264) GeoIP backend: Use correct id numbers for domains (Aki Tuomi)
+- [#3271](https://github.com/PowerDNS/pdns/pull/3271) ZoneParser: Throw PDNSException on too many SOA data elements
+- [#3302](https://github.com/PowerDNS/pdns/pull/3302) Fix bindbackend's feedRecord to handle being slave for the root
+- [#3399](https://github.com/PowerDNS/pdns/pull/3399) Report OpenSSL RSA keysize in bits (Kees Monshouwer)
+
+### Improvements
+
+- [#3119](https://github.com/PowerDNS/pdns/pull/3119) Show DNSSEC keys for slaved zone (Aki Tuomi)
+- [#3255](https://github.com/PowerDNS/pdns/pull/3255) Don't log authentication errors before sending HTTP basic auth challenge (Jan Broer)
+- [#3338](https://github.com/PowerDNS/pdns/pull/3338) Add weight feature to GeoIP backend (Aki Tuomi)
+- [#3364](https://github.com/PowerDNS/pdns/pull/3364) Shrink PacketID by 10% by eliminating padding. (Andrew Nelless)
+- [#3443](https://github.com/PowerDNS/pdns/pull/3443) Many speedup and correctness fixes
+
+## PowerDNS Authoritative Server 4.0.0-alpha1
+Released December 24th 2015
+
+
+# PowerDNS Authoritative Server 3.4.9
+Released 17th of May 2016
+
+This is a minor bugfix and performance release. Two contributions by Kees Monshouwer make 3.4.9 fully compatible with the new single key ECDSA default that is coming in version 4.0.0.
+
+Changes since 3.4.8:
+
+- [commit 4627ea0](https://github.com/PowerDNS/pdns/commit/4627ea0), [commit 8350828](https://github.com/PowerDNS/pdns/commit/8350828): use OpenSSL for ECDSA signing where available (Kees Monshouwer)
+- [commit 558ff84](https://github.com/PowerDNS/pdns/commit/558ff84): allow common signing key (Kees Monshouwer)
+- [commit 280d665](https://github.com/PowerDNS/pdns/commit/280d665): Add a disable-syslog setting
+- [commit 58d6ab6](https://github.com/PowerDNS/pdns/commit/58d6ab6): fix SOA caching with multiple backends (Kees Monshouwer)
+- [commit e9e413f](https://github.com/PowerDNS/pdns/commit/e9e413f), [commit 6af4652](https://github.com/PowerDNS/pdns/commit/6af4652): whitespace-related zone parsing fixes [ticket #3568](https://github.com/PowerDNS/pdns/issues/3568)
+- [commit 7473a5e](https://github.com/PowerDNS/pdns/commit/7473a5e): bindbackend: fix, set domain in list() (Kees Monshouwer)
+
+# PowerDNS Authoritative Server 3.4.8
+Released 3rd of February 2016
+
+This is a small bugfix release. Additionally, the deb/RPM packages on downloads.powerdns.com (those with -static in the name) for 3.4.8 have been built against Botan 1.10.11 instead of Botan 1.10.3 like previous packages. Please see [the Botan Security page](http://botan.randombit.net/security.html) for more information on the fixes in Botan 1.10.11. As a PowerDNS user, these issues only affect you if you ran our -static packages *and* allowed your users to upload private keys to your configuration.
+
+Changes since 3.4.7:
+
+- [commit edfa60a](https://github.com/PowerDNS/pdns/commit/edfa60a): Use AC_SEARCH_LIBS (Ruben Kerkhof)
+- [commit 7b7a3af](https://github.com/PowerDNS/pdns/commit/7b7a3af): Check for inet_aton in libresolv (Ruben Kerkhof)
+- [commit 9322aee](https://github.com/PowerDNS/pdns/commit/9322aee): Remove hardcoded -lresolv, -lnsl and -lsocket (Ruben Kerkhof)
+- [commit 23d26d8](https://github.com/PowerDNS/pdns/commit/23d26d8): pdnssec: don't check disabled records (Pieter Lexis)
+- [commit ce92ff1](https://github.com/PowerDNS/pdns/commit/ce92ff1): pdnssec: check all records (including disabled ones) only in verbose mode (Kees Monshouwer)
+- [commit f745312](https://github.com/PowerDNS/pdns/commit/f745312): traling dot in DNAME content (Kees Monshouwer)
+- [commit ed02761](https://github.com/PowerDNS/pdns/commit/ed02761): Fix luabackend compilation on FreeBSD i386 (RvdE)
+- [commit 07ea6ac](https://github.com/PowerDNS/pdns/commit/07ea6ac): silence g++ 6.0 warnings and error (Kees Monshouwer)
+- [commit c6077b1](https://github.com/PowerDNS/pdns/commit/c6077b1): add gcc 5.3 and 6.0 support to boost.m4 (Kees Monshouwer)
+
+# PowerDNS Authoritative Server 3.4.7
+Released 3rd of November 2015
+
+This is a security release fixing [Security Advisory
+2015-03](security/powerdns-advisory-2015-03.md)
+
+Bug fixes:
+
+- [commit b0c04ba](https://github.com/PowerDNS/pdns/commit/b0c04ba): Ignore invalid/empty TKEY and TSIG records (Christian Hofstaedtler)
+- [commit 8044a5d](https://github.com/PowerDNS/pdns/commit/8044a5d): Don't reply to truncated queries (Christian Hofstaedtler)
+- [commit 6a65ae9](https://github.com/PowerDNS/pdns/commit/6a65ae9): don't log out-of-zone ents during AXFR in (Kees Monshouwer)
+- [commit 416d252](https://github.com/PowerDNS/pdns/commit/416d252): Prevent XSS by escaping user input. Thanks to Pierre Jaury and Damien Cauquil at Sysdream for pointing this out.
+- [commit df76bda](https://github.com/PowerDNS/pdns/commit/df76bda): Handle NULL and boolean properly in gPGSql (Aki Tuomi)
+- commits [b998fc0](https://github.com/PowerDNS/pdns/commit/b998fc0),
+ [88516fd](https://github.com/PowerDNS/pdns/commit/88516fd),
+ [ef80925](https://github.com/PowerDNS/pdns/commit/ef80925),
+ [4549a72](https://github.com/PowerDNS/pdns/commit/4549a72): Improve negative caching (Kees Monshouwer)
+- [commit be27a9c](https://github.com/PowerDNS/pdns/commit/be27a9c): Do not divide timeout twice (Aki Tuomi)
+- commits [ca1d29c](https://github.com/PowerDNS/pdns/commit/ca1d29c),
+ [df2d20a](https://github.com/PowerDNS/pdns/commit/df2d20a),
+ [2358eea](https://github.com/PowerDNS/pdns/commit/2358eea): Correctly sort records with a priority.
+
+
+Improvements:
+
+- commits [791bc37](https://github.com/PowerDNS/pdns/commit/791bc37),
+ [e3301ca](https://github.com/PowerDNS/pdns/commit/e3301ca),
+ [9862779](https://github.com/PowerDNS/pdns/commit/9862779),
+ [b59a7e3](https://github.com/PowerDNS/pdns/commit/b59a7e3),
+ [4ca7a06](https://github.com/PowerDNS/pdns/commit/4ca7a06),
+ [7736530](https://github.com/PowerDNS/pdns/commit/7736530),
+ [69ea1a6](https://github.com/PowerDNS/pdns/commit/69ea1a6): Direct query answers and correct zone-rectification in the GeoIP backend (Aki Tuomi)
+- commits [83e0e53](https://github.com/PowerDNS/pdns/commit/83e0e53),
+ [0ff3037](https://github.com/PowerDNS/pdns/commit/0ff3037),
+ [9910908](https://github.com/PowerDNS/pdns/commit/9910908) Use token names to identify PKCS#11 keys (Aki Tuomi)
+- [commit a3801b2](https://github.com/PowerDNS/pdns/commit/a3801b2): Fix typo in an error message (Arjen Zonneveld)
+- [commit d33ba8e](https://github.com/PowerDNS/pdns/commit/d33ba8e): limit NSEC3 iterations in bindbackend (Kees Monshouwer)
+- [commit 0acca87](https://github.com/PowerDNS/pdns/commit/0acca87): Initialize minbody (Aki Tuomi)
+
+
+New features:
+
+- commits [4d51e96](https://github.com/PowerDNS/pdns/commit/4d51e96),
+ [6873a07](https://github.com/PowerDNS/pdns/commit/6873a07),
+ [b972356](https://github.com/PowerDNS/pdns/commit/b972356),
+ [46294b5](https://github.com/PowerDNS/pdns/commit/46294b5),
+ [6277b14](https://github.com/PowerDNS/pdns/commit/6277b14): OPENPGPKEY record-type (James Cloos and Kees Monshouwer)
+- [commit ec0ded7](https://github.com/PowerDNS/pdns/commit/ec0ded7): add global soa-edit settings (Kees Monshouwer)
+
+# PowerDNS Authoritative Server 3.4.6
+Released 28th of August 2015
+
+This is a security release fixing [Security Advisory
+2015-02](security/powerdns-advisory-2015-02.md)
+
+Bug fixes:
+
+- commits [c849701](https://github.com/PowerDNS/pdns/commit/c849701) and
+[8c91e2c](https://github.com/PowerDNS/pdns/commit/8c91e2c): Avoid
+superfluous backend recycling
+- commits [463fcff](https://github.com/PowerDNS/pdns/commit/463fcff),
+[0fc08e8](https://github.com/PowerDNS/pdns/commit/0fc08e8),
+[0fbe69c](https://github.com/PowerDNS/pdns/commit/0fbe69c),
+[1a6af1c](https://github.com/PowerDNS/pdns/commit/1a6af1c) and
+[07f69d3](https://github.com/PowerDNS/pdns/commit/07f69d3): Removal of
+dnsdist from the authoritative server distribution (Kees Monshouwer among others).
+- commits [5cfea4c](https://github.com/PowerDNS/pdns/commit/5cfea4c) and
+[ef011d9](https://github.com/PowerDNS/pdns/commit/ef011d9): Add EDNS
+unknown version handling and tests EDNS unknown version handling (Aki Tuomi)
+
+Improvements:
+
+- commits [88dd8a7](https://github.com/PowerDNS/pdns/commit/88dd8a7) and
+[dc6c63d](https://github.com/PowerDNS/pdns/commit/dc6c63d): Update
+YaHTTP to v0.1.7 (Aki Tuomi)
+- [commit 0a344bc](https://github.com/PowerDNS/pdns/commit/0a344bc): Make
+trailing/leading spaces stand out in `pdnssec check_zone`
+- commits [2e982ad](https://github.com/PowerDNS/pdns/commit/2e982ad) and
+[09bec1f](https://github.com/PowerDNS/pdns/commit/09bec1f): GCC 5.2 support
+and sync boost.m4 macro with upstream (Kees Monshouwer among others)
+- [commit 1ad4e44](https://github.com/PowerDNS/pdns/commit/1ad4e44): Log
+answer packets only if log-dns-details is enabled (Kees Monshouwer)
+
+# PowerDNS Recursor 3.6.4
+Released 9th of June 2015
+
+This is a security release fixing [Security Advisory
+2015-01](security/powerdns-advisory-2015-01.md)
+
+Bug fixes:
+
+- [commit bccd068](https://github.com/PowerDNS/pdns/commit/bccd068): Limit the
+maximum length of a qname
+
+# PowerDNS Recursor 3.7.3
+Released 9th of June 2015
+
+Bug fixes:
+
+- [commit 92f7b2b](https://github.com/PowerDNS/pdns/commit/92f7b2b): Limit the
+maximum length of a qname
+
+This is a security release fixing [Security Advisory
+2015-01](security/powerdns-advisory-2015-01.md)
+
+Improvements:
+
+- [commit 46366a5](https://github.com/PowerDNS/pdns/commit/46366a5),
+[commit f318a7d](https://github.com/PowerDNS/pdns/commit/f318a7d): pdnssec:
+check for glue and delegations in parent zones (Kees Monshouwer)
+
+# PowerDNS Authoritative Server 3.3.3
+Released 9th of June 2015
+
+This is a security release fixing [Security Advisory
+2015-01](security/powerdns-advisory-2015-01.md)
+
+Bug fixes:
+
+- [commit a0a1482](https://github.com/PowerDNS/pdns/commit/a0a1482): Limit the
+maximum length of a qname
+
+# PowerDNS Authoritative Server 3.4.5
+Released 9th of June 2015
+
+This is a security release fixing [Security Advisory
+2015-01](security/powerdns-advisory-2015-01.md)
+
+Bug fixes:
+
+- [commit ffaae2b](https://github.com/PowerDNS/pdns/commit/ffaae2b): be
+careful reading empty lines in our config parser and prevent integer overflow.
+- [commit 8e30209](https://github.com/PowerDNS/pdns/commit/8e30209): prevent
+crash after --list-modules (Ruben Kerkhof)
+- [commit 6cf71cf](https://github.com/PowerDNS/pdns/commit/6cf71cf): Limit the
+maximum length of a qname
+
+Improvements:
+
+- [commit 28ba3fc](https://github.com/PowerDNS/pdns/commit/28ba3fc),
+[commit 61b316f](https://github.com/PowerDNS/pdns/commit/61b316f): Support
+/etc/default for our debian/ubuntu packages (Aki Tuomi)
+- [commit d80e2b6](https://github.com/PowerDNS/pdns/commit/d80e2b6): Detect
+GCC 5.1 for boost (Ruben Kerkhof)
+- [commit 68b4834](https://github.com/PowerDNS/pdns/commit/68b4834),
+[commit 3b14545](https://github.com/PowerDNS/pdns/commit/3b14545),
+[commit 2356d5c](https://github.com/PowerDNS/pdns/commit/2356d5c),
+[commit 432808b](https://github.com/PowerDNS/pdns/commit/432808b):
+Various PKCS#11 fixes and improvements (Aki Tuomi)
+- [commit bf357ff](https://github.com/PowerDNS/pdns/commit/bf357ff),
+[commit 2433d2e](https://github.com/PowerDNS/pdns/commit/2433d2e),
+[commit 8fabf4d](https://github.com/PowerDNS/pdns/commit/8fabf4d): Fix
+Coverity issues (Aki Tuomi)
+- [commit 5d02d01](https://github.com/PowerDNS/pdns/commit/5d02d01)
+[commit 7798aa3](https://github.com/PowerDNS/pdns/commit/7798aa3),
+[commit 9f6e411](https://github.com/PowerDNS/pdns/commit/9f6e411),
+[commit e25a09c](https://github.com/PowerDNS/pdns/commit/e25a09c): Fix
+building on OpenBSD (Florian Obser and Ruben Kerkhof)
+- [commit 5c8bba2](https://github.com/PowerDNS/pdns/commit/5c8bba2): Look for
+mbedtls before polarssl (Ruben Kerkhof)
+- [commit 5abd150](https://github.com/PowerDNS/pdns/commit/5abd150): Let
+pkg-config determine botan dependency libs (Ruben Kerkhof)
+- [commit ba4d623](https://github.com/PowerDNS/pdns/commit/ba4d623): kill some
+further mallocs and add note to remind us not to add them back
+- [commit 50346d8](https://github.com/PowerDNS/pdns/commit/50346d8): Move
+remotebackend-unix test socket to testsdir (Aki Tuomi)
+- [commit 32e9512](https://github.com/PowerDNS/pdns/commit/32e9512): Defer
+launch of coprocess until first question (Aki Tuomi)
+- [commit d9b3ecb](https://github.com/PowerDNS/pdns/commit/d9b3ecb),
+[commit 561373e](https://github.com/PowerDNS/pdns/commit/561373e): pdnssec:
+check for glue and delegations in parent zones (Kees Monshouwer)
+
+# PowerDNS Authoritative Server 3.3.2
+
+Released 1st of May, 2015
+
+Among other bug fixes and improvements (as listed below), this release
+incorporates a fix for CVE-2015-1868, as detailed in [PowerDNS Security
+Advisory 2015-01](security/powerdns-advisory-2015-01.md)
+
+If you are running DNSSEC with version 3.3.1 or below, and you cannot
+currently upgrade to 3.4.4, please consider upgrading to 3.3.2; it has a lot
+of improvements and bug fixes and tremendously increases compliance.
+
+We want to explicitly thank Kees Monshouwer for digging up all the DNSSEC
+improvements and porting them back to this release.
+
+When upgrading, please run "pdnssec rectify-all-zones" and trigger an AXFR for
+all DNSSEC zones to make sure you benefit from all the compliance improvements
+present in this version.
+
+Security fixes:
+
+- [commit 9df4944](https://github.com/PowerDNS/pdns/commit/9df4944): import CVE-2015-1868 patch (Peter van Dijk)
+- [commit dbedfc5](https://github.com/PowerDNS/pdns/commit/dbedfc5): kill some further mallocs and add note to remind us not to add them back (bert hubert)
+
+Improvements:
+
+- [commit d0af589](https://github.com/PowerDNS/pdns/commit/d0af589)
+, [commit c45b6db](https://github.com/PowerDNS/pdns/commit/c45b6db)
+, [commit 88c1f21](https://github.com/PowerDNS/pdns/commit/88c1f21)
+, [commit 2a4c620](https://github.com/PowerDNS/pdns/commit/2a4c620)
+, [commit 4a4597e](https://github.com/PowerDNS/pdns/commit/4a4597e)
+, [commit 9fa7373](https://github.com/PowerDNS/pdns/commit/9fa7373)
+, [commit 8115a83](https://github.com/PowerDNS/pdns/commit/8115a83):
+implement security polling for auth
+- [commit 5bbd868](https://github.com/PowerDNS/pdns/commit/5bbd868): import suck() from master (Kees Monshouwer)
+- [commit 194f4d2](https://github.com/PowerDNS/pdns/commit/194f4d2): respond REFUSED instead of NOERROR for "unknown zone" situations (Peter van Dijk)
+- [commit 55b0653](https://github.com/PowerDNS/pdns/commit/55b0653): set AA on CNAME into referral, fixes [ticket #589](https://github.com/PowerDNS/pdns/issues/589) (Peter van Dijk)
+- [commit 71232aa](https://github.com/PowerDNS/pdns/commit/71232aa): update l.root ip (Kees Monshouwer)
+
+Bug fixes:
+
+- [commit 88c52fe](https://github.com/PowerDNS/pdns/commit/88c52fe): make makeRelative() case insensitive (Kees Monshouwer)
+
+DNSSEC improvements:
+
+- [commit b3dec9c](https://github.com/PowerDNS/pdns/commit/b3dec9c): change default for add-superfluous-nsec3-for-old-bind config option (Kees Monshouwer)
+- [commit 017a78b](https://github.com/PowerDNS/pdns/commit/017a78b): limit the number of NSEC3 iterations RFC5155 10.3 (Kees Monshouwer)
+- [commit d768d7f](https://github.com/PowerDNS/pdns/commit/d768d7f): NSEC3 and related RRSIGS are not part of the dnstree (Kees Monshouwer)
+- [commit 3a36a1c](https://github.com/PowerDNS/pdns/commit/3a36a1c): import bindbackend rectify code from master (Kees Monshouwer)
+- [commit 1ee7e22](https://github.com/PowerDNS/pdns/commit/1ee7e22): limit mode 0 closest provable encloser to optout (Kees Monshouwer)
+- [commit bbc0bc5](https://github.com/PowerDNS/pdns/commit/bbc0bc5): fix for errata 3441 of RFC5155 (Kees Monshouwer)
+- [commit e8bfa7b](https://github.com/PowerDNS/pdns/commit/e8bfa7b): allow covering NSEC3 record in NODATA response (Kees Monshouwer)
+- [commit f0b3b24](https://github.com/PowerDNS/pdns/commit/f0b3b24): return NOTIMP for direct RRSIG request (Kees Monshouwer)
+- [commit c79addc](https://github.com/PowerDNS/pdns/commit/c79addc): import pdnssec checkZone() from master (Kees Monshouwer)
+- [commit 2f1fec7](https://github.com/PowerDNS/pdns/commit/2f1fec7): import pdnssec rectifyZone() from master (Kees Monshouwer)
+
+# PowerDNS Recursor 3.7.2
+
+Released 23rd of April, 2015
+
+Among other bug fixes and improvements (as listed below), this release incorporates a fix for
+CVE-2015-1868, as detailed in [PowerDNS Security Advisory 2015-01](security/powerdns-advisory-2015-01.md)
+
+Bug fixes:
+
+- [commit adb10be](https://github.com/PowerDNS/pdns/commit/adb10be) [commit 3ec3e0f](https://github.com/PowerDNS/pdns/commit/3ec3e0f) [commit dc02ebf](https://github.com/PowerDNS/pdns/commit/dc02ebf) Fix handling of forward references in label compressed packets; fixes CVE-2015-1868
+- [commit a7be3f1](https://github.com/PowerDNS/pdns/commit/a7be3f1): make sure
+we never call sendmsg with msg_control!=NULL && msg_controllen>0. Fixes
+[ticket #2227](https://github.com/PowerDNS/pdns/issues/2227)
+- [commit 9d835ed](https://github.com/PowerDNS/pdns/commit/9d835ed): Improve
+robustness of root-nx-trust.
+
+Improvements:
+
+- [commit 99c595b](https://github.com/PowerDNS/pdns/commit/99c595b): Silence
+warnings that always occur on FreeBSD (Ruben Kerkhof)
+
+# PowerDNS Recursor 3.6.3
+
+Released 23rd of April, 2015
+
+The only difference between Recursor 3.6.2 and 3.6.3 is a fix for CVE-2015-1868, as detailed in [PowerDNS Security Advisory 2015-01](security/powerdns-advisory-2015-01.md)
+
+# PowerDNS Authoritative Server 3.4.4
+
+Released 23rd of April, 2015
+
+**Warning**: Version 3.4.4 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Additionally, if you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+Among other bug fixes and improvements (as listed below), this release incorporates a fix for
+CVE-2015-1868, as detailed in [PowerDNS Security Advisory 2015-01](security/powerdns-advisory-2015-01.md)
+
+Bug fixes:
+
+- [commit ac3ae09](https://github.com/PowerDNS/pdns/commit/ac3ae09): fix rectify-(all)-zones for mixed case domain names
+- [commit 2dea55e](https://github.com/PowerDNS/pdns/commit/2dea55e), [commit 032d565](https://github.com/PowerDNS/pdns/commit/032d565), [commit 55f2dbf](https://github.com/PowerDNS/pdns/commit/55f2dbf): fix CVE-2015-1868
+- [commit 21cdbe5](https://github.com/PowerDNS/pdns/commit/21cdbe5): Blocking
+IO in busy-wait for remote backend (Wieger Opmeer)
+- [commit cc7b2ac](https://github.com/PowerDNS/pdns/commit/cc7b2ac): fix
+double dot for root MX/SRV in bind slave zone files (Kees Monshouwer)
+- [commit c40307b](https://github.com/PowerDNS/pdns/commit/c40307b): Properly
+lock lmdb database, fixes [ticket #1954](https://github.com/PowerDNS/pdns/issues/1954)
+(Aki Tuomi)
+- [commit 662e76d](https://github.com/PowerDNS/pdns/commit/662e76d): Fix
+segfault in zone2lmdb (Ruben Kerkhof)
+
+New Features:
+
+- [commit 5ae212e](https://github.com/PowerDNS/pdns/commit/5ae212e): pdnssec: warn for insecure wildcards in opt-out zones
+- commits [cd3f21c](https://github.com/PowerDNS/pdns/commit/cd3f21c),
+[8b582f6](https://github.com/PowerDNS/pdns/commit/8b582f6),
+[0b7e766](https://github.com/PowerDNS/pdns/commit/0b7e766),
+[f743af9](https://github.com/PowerDNS/pdns/commit/f743af9),
+[dcde3c8](https://github.com/PowerDNS/pdns/commit/dcde3c8) and
+[f12fcf7](https://github.com/PowerDNS/pdns/commit/f12fcf7):
+TKEY record type (Aki Tuomi)
+- commits [0fda1d9](https://github.com/PowerDNS/pdns/commit/0fda1d9),
+[3dd139d](https://github.com/PowerDNS/pdns/commit/3dd139d),
+[ba146ce](https://github.com/PowerDNS/pdns/commit/ba146ce),
+[25109e2](https://github.com/PowerDNS/pdns/commit/25109e2),
+[c011a01](https://github.com/PowerDNS/pdns/commit/c011a01),
+[0600350](https://github.com/PowerDNS/pdns/commit/0600350),
+[fc96b5e](https://github.com/PowerDNS/pdns/commit/fc96b5e),
+[4414468](https://github.com/PowerDNS/pdns/commit/4414468),
+[c163d41](https://github.com/PowerDNS/pdns/commit/c163d41),
+[f52c7f6](https://github.com/PowerDNS/pdns/commit/f52c7f6),
+[8d56a31](https://github.com/PowerDNS/pdns/commit/8d56a31),
+[7821417](https://github.com/PowerDNS/pdns/commit/7821417),
+[ea62bd9](https://github.com/PowerDNS/pdns/commit/ea62bd9),
+[c5ababd](https://github.com/PowerDNS/pdns/commit/c5ababd),
+[91c8351](https://github.com/PowerDNS/pdns/commit/91c8351) and
+[073ac49](https://github.com/PowerDNS/pdns/commit/073ac49): Many
+PKCS#11 improvements (Aki Tuomi)
+- commits [6f0d4f1](https://github.com/PowerDNS/pdns/commit/6f0d4f1) and
+[5eb33cb](https://github.com/PowerDNS/pdns/commit/5eb33cb): Introduce
+xfrBlobNoSpaces and use them for TSIG (Aki Tuomi)
+
+Improvements:
+
+- [commit e4f48ab](https://github.com/PowerDNS/pdns/commit/e4f48ab): allow "pdnssec set-nsec3 ZONE" for insecure zones; this saves on one rectify when securing a NSEC3 zone
+- commits [cce95b9](https://github.com/PowerDNS/pdns/commit/cce95b9),
+[e2e9243](https://github.com/PowerDNS/pdns/commit/e2e9243) and
+[e82da97](https://github.com/PowerDNS/pdns/commit/e82da97): Improvements
+to the config-file parsing (Aki Tuomi)
+- [commit 2180e21](https://github.com/PowerDNS/pdns/commit/2180e21):
+postgresql check should not touch LDFLAGS (Ruben Kerkhof)
+- [commit 0481021](https://github.com/PowerDNS/pdns/commit/0481021): Log error
+when remote cannot do AXFR (Aki Tuomi)
+- [commit 1ecc3a5](https://github.com/PowerDNS/pdns/commit/1ecc3a5): Speed
+improvements when AXFR is disabled (Christian Hofstaedtler)
+- commits [1f7334e](https://github.com/PowerDNS/pdns/commit/1f7334e) and
+[b17799a](https://github.com/PowerDNS/pdns/commit/b17799a): NSEC3 and
+related RRSIGS are not part of the dnstree (Kees Monshouwer)
+- commits [dd943dd](https://github.com/PowerDNS/pdns/commit/dd943dd) and
+[58c4834](https://github.com/PowerDNS/pdns/commit/58c4834): Change
+ifdef to check for `__GLIBC__` instead of `__linux__` to prevent errors with other
+libc's (James Taylor)
+- [commit c929d50](https://github.com/PowerDNS/pdns/commit/c929d50): Try to
+raise open files before dropping privileges (Aki Tuomi)
+- [commit 69fd3dc](https://github.com/PowerDNS/pdns/commit/69fd3dc): Add
+newline to carbon error message on auth (Aki Tuomi)
+- [commit 3064f80](https://github.com/PowerDNS/pdns/commit/3064f80): Make sure
+we send servfail on error (Aki Tuomi)
+- [commit b004529](https://github.com/PowerDNS/pdns/commit/b004529): Ship
+lmdb-example.pl in tarball (Ruben Kerkhof)
+- [commit 9e6b24f](https://github.com/PowerDNS/pdns/commit/9e6b24f): Allocate
+TCP buffer dynamically, decreasing stack usage
+- [commit 267fdde](https://github.com/PowerDNS/pdns/commit/267fdde): throw if getSOA gets non-SOA record
+
+# PowerDNS Authoritative Server 3.4.3
+
+**Warning**: Version 3.4.3 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Additionally, if you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+Released March 2nd, 2015
+
+Find the downloads [on our download page](https://www.powerdns.com/downloads.html).
+
+Bug fixes:
+
+- [commit ceb49ce](https://github.com/PowerDNS/pdns/commit/ceb49ce):
+pdns_control: exit 1 on unknown command (Ruben Kerkhof)
+- [commit 1406891](https://github.com/PowerDNS/pdns/commit/1406891): evaluate
+KSK ZSK pairs per algorithm (Kees Monshouwer)
+- [commit 3ca050f](https://github.com/PowerDNS/pdns/commit/3ca050f): always
+set di.notified_serial in getAllDomains (Kees Monshouwer)
+- [commit d9d09e1](https://github.com/PowerDNS/pdns/commit/d9d09e1):
+pdns_control: don't open socket in /tmp (Ruben Kerkhof)
+
+New features:
+
+- [commit 2f67952](https://github.com/PowerDNS/pdns/commit/2f67952): Limit who
+can send us AXFR notify queries (Ruben Kerkhof)
+
+Improvements:
+
+- [commit d7bec64](https://github.com/PowerDNS/pdns/commit/d7bec64): respond
+REFUSED instead of NOERROR for "unknown zone" situations
+- [commit ebeb9d7](https://github.com/PowerDNS/pdns/commit/ebeb9d7): Check for
+Lua 5.3 (Ruben Kerkhof)
+- [commit d09931d](https://github.com/PowerDNS/pdns/commit/d09931d): Check
+compiler for relro support instead of linker (Ruben Kerkhof)
+- [commit c4b0d0c](https://github.com/PowerDNS/pdns/commit/c4b0d0c): Replace
+PacketHandler with UeberBackend where possible (Christian Hofstaedtler)
+- [commit 5a85152](https://github.com/PowerDNS/pdns/commit/5a85152):
+PacketHandler: Share UeberBackend with DNSSECKeeper (Christian Hofstaedtler)
+- [commit 97bd444](https://github.com/PowerDNS/pdns/commit/97bd444): fix
+building with GCC 5
+
+Experimental API changes (Christian Hofstaedtler):
+
+- [commit ca44706](https://github.com/PowerDNS/pdns/commit/ca44706): API: move
+shared DomainInfo reader into it's own function
+- [commit 102602f](https://github.com/PowerDNS/pdns/commit/102602f): API:
+allow writing to domains.account field
+- [commit d82f632](https://github.com/PowerDNS/pdns/commit/d82f632): API: read
+and expose domain account field
+- [commit 2b06977](https://github.com/PowerDNS/pdns/commit/2b06977): API: be
+more strict when parsing record contents
+- [commit 2f72b7c](https://github.com/PowerDNS/pdns/commit/2f72b7c): API:
+Reject unknown types (TYPE0)
+- [commit d82f632](https://github.com/PowerDNS/pdns/commit/d82f632): API: read
+and expose domain account field
+
+# PowerDNS Authoritative Server 3.4.2
+
+**Warning**: Version 3.4.2 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Additionally, if you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+Released February 3rd, 2015
+
+Find the downloads [on our download page](https://www.powerdns.com/downloads.html).
+
+This is a performance and bugfix update to 3.4.1 and any earlier version. For high traffic setups, including
+those using DNSSEC, upgrading to 3.4.2 may show tremendous performance increases.
+
+A list of changes since 3.4.1 follows.
+
+Improvements:
+
+- [commit 73004f1](https://github.com/PowerDNS/pdns/commit/73004f1): implement CORS for the HTTP API
+- [commit 4d9c289](https://github.com/PowerDNS/pdns/commit/4d9c289): qtype is now case insensitive in API and database
+- [commit 13af5d8](https://github.com/PowerDNS/pdns/commit/13af5d8), [commit 223373a](https://github.com/PowerDNS/pdns/commit/223373a), [commit 1d5a68d](https://github.com/PowerDNS/pdns/commit/1d5a68d), [commit 705a73f](https://github.com/PowerDNS/pdns/commit/705a73f), [commit b418d52](https://github.com/PowerDNS/pdns/commit/b418d52): Allow (optional) PIE hardening
+- [commit 2f86f20](https://github.com/PowerDNS/pdns/commit/2f86f20): json-api: remove priority from json
+- [commit cefcf9f](https://github.com/PowerDNS/pdns/commit/cefcf9f): backport remotebackend fixes
+- [commit 920f987](https://github.com/PowerDNS/pdns/commit/920f987), [commit dd8853c](https://github.com/PowerDNS/pdns/commit/dd8853c): Support Lua 5.3
+- [commit 003aae5](https://github.com/PowerDNS/pdns/commit/003aae5): support single-type ZSK signing
+- [commit 1c57e1d](https://github.com/PowerDNS/pdns/commit/1c57e1d): Potential fix for [ticket #1907](https://github.com/PowerDNS/pdns/issues/1907), we now try to trigger libgcc_s.so.1 to load before we chroot. I can't reproduce the bug on my local system, but this "should" help. Seriously.
+- [commit 031ab21](https://github.com/PowerDNS/pdns/commit/031ab21): update polarssl to 1.3.9
+
+Bug fixes:
+
+- [commit 60b2b7c](https://github.com/PowerDNS/pdns/commit/60b2b7c), [commit d962fbc](https://github.com/PowerDNS/pdns/commit/d962fbc): refuse overly long labels in names
+- [commit a64fd6a](https://github.com/PowerDNS/pdns/commit/a64fd6a): auth: limit long version strings to 63 characters and catch exceptions in secpoll
+- [commit fa52e02](https://github.com/PowerDNS/pdns/commit/fa52e02): pdnssec: fix ttl check for RRSIG records
+- [commit 0678b25](https://github.com/PowerDNS/pdns/commit/0678b25): fix up latency reporting for sub-millisecond latencies (would clip to 0)
+- [commit d45c1f1](https://github.com/PowerDNS/pdns/commit/d45c1f1): make sure we don't throw an exception on "pdns_control show" of an unknown variable
+- [commit 63c8088](https://github.com/PowerDNS/pdns/commit/63c8088): fix startup race condition with carbon thread already trying to broadcast uninitialized data
+- [commit 796321c](https://github.com/PowerDNS/pdns/commit/796321c): make qsize-q more robust
+- [commit 407867c](https://github.com/PowerDNS/pdns/commit/407867c): mind04 discovered we count corrupt packets and EAGAIN situations as validly received packets, skewing the udp questions/answers graphs on auth.
+- [commit f06d069](https://github.com/PowerDNS/pdns/commit/f06d069): make latency & qsize reporting 'live'. Plus fix that we only reported the qsize of the first distributor.
+- [commit 2f3498e](https://github.com/PowerDNS/pdns/commit/2f3498e): fix up statbag for carbon protocol and function pointers
+- [commit 0f2f999](https://github.com/PowerDNS/pdns/commit/0f2f999): get priority from table in Lua axfrfilter; fixes [ticket #1857](https://github.com/PowerDNS/pdns/issues/1857)
+- [commit 96963e2](https://github.com/PowerDNS/pdns/commit/96963e2), [commit bbcbbbe](https://github.com/PowerDNS/pdns/commit/bbcbbbe), [commit d5c9c07](https://github.com/PowerDNS/pdns/commit/d5c9c07): various backends: fix records pointing at root
+- [commit e94c2c4](https://github.com/PowerDNS/pdns/commit/e94c2c4): remove additional layer of trailing . stripping, which broke MX records to the root in the BIND backend. Should close [ticket #1243](https://github.com/PowerDNS/pdns/issues/1243).
+- [commit 8f35ba2](https://github.com/PowerDNS/pdns/commit/8f35ba2): api: use uncached results for getKeys()
+- [commit c574336](https://github.com/PowerDNS/pdns/commit/c574336): read ALLOW-AXFR-FROM from the backend with the metadata
+
+Minor changes:
+
+- [commit 1e39b4c](https://github.com/PowerDNS/pdns/commit/1e39b4c): move manpages to section 1
+- [commit b3992d9](https://github.com/PowerDNS/pdns/commit/b3992d9): secpoll: Replace ~ with _
+- [commit 9799ef5](https://github.com/PowerDNS/pdns/commit/9799ef5): only zones with an active ksk are secure
+- [commit d02744f](https://github.com/PowerDNS/pdns/commit/d02744f): api: show keys for zones without active ksk
+
+New features:
+
+- [commit 1b97ba0](https://github.com/PowerDNS/pdns/commit/1b97ba0): add signatures metric to auth, so we can plot signatures/second
+- [commit 92cef2d](https://github.com/PowerDNS/pdns/commit/92cef2d): pdns_control: make it posible to notify all zones at once
+- [commit f648752](https://github.com/PowerDNS/pdns/commit/f648752): JSON API: provide flush-cache, notify, axfr-retrieve
+- [commit 02653a7](https://github.com/PowerDNS/pdns/commit/02653a7): add 'bench-db' to do very simple database backend performance benchmark
+- [commit a83257a](https://github.com/PowerDNS/pdns/commit/a83257a): enable callback based metrics to statbas, and add 5 such metrics: uptime, sys-msec, user-msec, key-cache-size, meta-cache-size, signature-cache-size
+
+Performance improvements:
+
+- [commit a37fe8c](https://github.com/PowerDNS/pdns/commit/a37fe8c): better key for packetcache
+- [commit e5217bb](https://github.com/PowerDNS/pdns/commit/e5217bb): don't do time(0) under signature cache lock
+- [commit d061045](https://github.com/PowerDNS/pdns/commit/d061045), [commit 135db51](https://github.com/PowerDNS/pdns/commit/135db51), [commit 7d0f392](https://github.com/PowerDNS/pdns/commit/7d0f392): shard the packet cache, closing [ticket #1910](https://github.com/PowerDNS/pdns/issues/1910).
+- [commit d71a712](https://github.com/PowerDNS/pdns/commit/d71a712): with thanks to Jack Lloyd, this works around the default Botan allocator slowing down for us during production use.
+
+
+# PowerDNS Recursor 3.7.0
+
+Unreleased, please see the 3.7.1 changelog below.
+
+# PowerDNS Recursor 3.7.1
+
+Released February 12th, 2015.
+
+This version contains a mix of speedups and improvements, the combined effect of which is vastly
+improved resilience against traffic spikes and malicious query overloads.
+
+Of further note is the massive community contribution, mostly over
+Christmas. Especially Ruben Kerkhof, Pieter Lexis, Kees Monshouwer and Aki
+Tuomi delivered a lot of love. Thanks!
+
+Minor changes:
+
+- Removal of dead code here and there 04dc6d618734fc630122de4c56dff641ebaf0988
+- Per-qtype response counters are now 64 bit 297bb6acf7902068693a4aae1443c424d0e8dd52 on 64 bit systems
+- Add IPv6 addresses for b and c.root-servers.net hints efc2595423c9a1be6f2d8f4da25445198ceb8b57
+- Add IP address to logging about terminated queries 37aa9904d1cc967ba4b5d5e17dbe41485f8cdece
+- Improve qtype name logging fab3ed3453e15ae88e29a0e4071b214eb19caad9 (Aki Tuomi)
+- Redefine 'BAD_NETS' for dont-query based on newer IANA guidance 12cd44ee0fcde5893f85dccc499bfc35152c5fff (lochiiconnectivity)
+- Add documentation links to systemd unit eb154adfdffa5c78624e2ea98e938d7b5787119e (Ruben Kerkhof)
+
+Improvements:
+
+- Upgrade embedded PolarSSL to 1.3.9: d330a2ea1a93d7675ef680311f8aa0306aeefcf1
+- yahttp upgrade c290975778942ed1082ca66918695a5bd2d6bac4 c65a57e888ee48eaa948e590c90c51420bffa847 (Aki Tuomi)
+- Replace . in hostnames by - for Carbon so as not to confuse Metronome 46541751ed1c3bc051d78217543d5fc76733e212
+- Manpages got a lot of love and are now built from Markdown (Pieter Lexis)
+- Move to PolarSSL base64 488360551009784ab35c43ee4580e773a2a8a227 (Kees Monshouwer)
+- The quiet=no query logging is now more informative 461df9d20c560d240285f772c09b3beb89d46daa
+- We can finally bind to 0.0.0.0 and :: and guarantee answers from the correct source b71b60ee73ef3c86f80a2179981eda2e61c4363f
+- We use per-packet timestamps to drop ancient traffic in case of overload b71b60ee73ef3c86f80a2179981eda2e61c4363f, non-Linux portability in d63f0d83631c41eff203d30b0b7c475a88f1db59
+- Builtin webserver can be queried with the API key in the URL again c89f8cd022c4a9409b95d22ffa3b03e4e98dc400
+- Ringbuffers are now available via API c89f8cd022c4a9409b95d22ffa3b03e4e98dc400
+- Lua 5.3 compatibility 59c6fc3e3931ca87d484337daee512e716bc4cf4 (Kees Monshouwer)
+- No longer leave a stale UNIX domain socket around from rec_control if the recursor was down 524e4f4d81f4ed9eb218715cbc8a59f0b9868234,
+ ticket #2061
+- Running with 'quiet=no' would strangely actually prevent debug messages from being logged f48d7b657ec32517f8bfcada3bfe6353ca313314
+- Webserver now implements CORS for the API ea89a97e864c43c1cb03f2959ad04c4ebe7580ad, fixing ticket #1984
+- Houskeeping thread would sometimes run multiple times simultaneously, which worked, but was odd cc59bce675e62e2b9657b42614ce8be3312cae82
+
+New features:
+
+- New `root-nx-trust` flag makes PowerDNS generalize NXDOMAIN responses from the root-servers 01402d56846a3a61811ebd4e6bc97e53f908e568
+- `getregisteredname()` for Lua, which turns 'www.bbc.co.uk' into 'bbc.co.uk' 8cd4851beb78bc6ab320926fb5cb6a09282016b1
+- Lua preoutquery filter 3457a2a0ec41d3b3aff7640f30008788e1228a6e
+- Lua IP-based filter (ipfilter) before parsing packets 4ea949413c495254acb0bd19335142761c1efc0c
+- `iputils` class for Lua, to quickly process IP addresses and netmasks in their native format
+- `getregisteredname` function for Lua, to find the registered domain for a given name
+- Various new ringbuffers: top-servfail-remotes, top-largeanswer-remotes, top-servfail-queries
+
+Speedups:
+
+- Remove unneeded malloc traffic 93d4a89096e64d53740790f58fadec56f6a0af14 8682c32bc45b6ffa7c0f6da778e1b223ae7f03ce a903b39cfe7364c56324038264d3db50b8cece87
+- Our nameserver-loop detection carried around a lot of baggage for complex domain names, plus did not differentiate IPv4 and IPv6 well enough 891fbf888ccac074e3edc38864641ca774f2f03c
+- Prioritize new queries over nameserver responses, improving latency under query bursts bf3b0cec366c090af000b066267b6f6bbb3a512a
+- Remove escaping in case there was nothing to escape 83b746fd1d94c8742d8bd87a44beb44c154230c7
+- Our logging infrastructure had a lot of locking d1449e4d073595e1e1581804f121fc90e37158bf
+- Reduce logging level of certain common messages, which locked up synchronously logging systems 854d44e31c76aa650520e6d462dd3a02b5936f7a
+- Add limit on total wall-clock time spent on a query 9de3e0340fa066d4c59449e1643a1de8c343f8f2
+- Packet cache is now case-insensitive, which increases hitrate 90974597aadaf1096e3fd0dc450be7422ea591a5
+
+Security relevant:
+
+- Check for PIE, RELRO and stack protector during configure 8d0354b189c12e1e14f5309d3b49935c17f9eeb0 (Aki Tuomi)
+- Testing for support of PIE etc was improved in b2053c28ccb9609e2ce7bcb6beda83f98a062aa3 and beyond, fixes #2125 (Ruben Kerkhof)
+- Max query-per-query limit (max-qperq) is now configurable 173d790ead08f67733010ca4c6fc404a040fe699
+
+Bugs fixed:
+
+- IPv6 outgoing queries had a disproportionate effect on our query load. Fixed in 76f190f2a0877cd79ede2994124c1a58dc69ae49 and beyond.
+- rec_control gave incorrect output on a timeout 12997e9d800734da51b808767e1e2477244c30eb
+- When using the webserver AND having an error in the Lua script, recursor could crash during startup 62f0ae62984adadab687c23fe1b287c1f219b2cb
+- Hugely long version strings would trip up security polling 18b7333828a1275ae5f5574a9c8330290d8557ff (Kees Monshouwer)
+- The 'remotes' ringbuffer was sized incorrectly f8f243b01215d6adcb59389f09ef494f1309041f
+- Cache sizes had an off-by-one scaling problem, with the wrong number of entries allocated per thread f8f243b01215d6adcb59389f09ef494f1309041f
+- Our automatic file descriptor limit raising was attempted *after* setuid, which made it a lot less effective. Found and fixed by Aki Tuomi
+ a6414fdce9b0ec32c340d1f2eea2254f3fedc1c1
+- Timestamps used for dropping packets were occasionaly wrong 183eb8774e4bc2569f06d5894fec65740f4b70b6 and 4c4765c104bacc146533217bcc843efb244a8086
+ (RC2) with thanks to Winfried for debugging.
+- In RC1, our new DoS protection measures would crash the Recursor if too many root servers were unreachable.
+ 6a6fb05ad81c519b4002ed1db00f3ed9b7bce6b4. Debugging and testing by Fusl.
+
+
+Various other documentation changes by Christian Hofstaedtler and Ruben
+Kerkhof. Lots of improvements all over the place by Kees Monshouwer.
+
+# PowerDNS Recursor 3.6.2
+
+**Note**: Version 3.6.2 is a bugfix update to 3.6.1. Released on the 30th of October 2014.
+
+[Official download page](https://www.powerdns.com/downloads.html)
+
+A list of changes since 3.6.1 follows.
+
+- [commit ab14b4f](https://github.com/PowerDNS/pdns/commit/ab14b4f): expedite servfail generation for ezdns-like failures (fully abort query resolving if we hit more than 50 outqueries). This also prevents the issue documented in [PowerDNS Security Advisory 2014-02](security/powerdns-advisory-2014-02/) (CVE-2014-8601)
+- [commit 42025be](https://github.com/PowerDNS/pdns/commit/42025be): PowerDNS now polls the security status of a release at startup and periodically. More detail on this feature, and how to turn it off, can be found in [Security polling](common/security.md#security-polling).
+- [commit 5027429](https://github.com/PowerDNS/pdns/commit/5027429): We did not transmit the right 'local' socket address to Lua for TCP/IP queries in the recursor. In addition, we would attempt to lookup a filedescriptor that wasn't there in an unlocked map which could conceivably lead to crashes. Closes [ticket 1828](https://github.com/PowerDNS/pdns/issues/1828), thanks Winfried for reporting
+- [commit 752756c](https://github.com/PowerDNS/pdns/commit/752756c): Sync embedded yahttp copy. API: Replace HTTP Basic auth with static key in custom header
+- [commit 6fdd40d](https://github.com/PowerDNS/pdns/commit/6fdd40d): add missing `#include <pthread.h>` to rec-channel.hh (this fixes building on OS X).
+
+# PowerDNS Authoritative Server 3.4.1
+
+**Warning**: Version 3.4.1 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Additionally, if you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+Released October 30th, 2014
+
+Find the downloads [on our download page](https://www.powerdns.com/downloads.html).
+
+This is a bugfix update to 3.4.0 and any earlier version.
+
+A list of changes since 3.4.0 follows.
+
+- [commit dcd6524](https://github.com/PowerDNS/pdns/commit/dcd6524), [commit a8750a5](https://github.com/PowerDNS/pdns/commit/a8750a5), [commit 7dc86bf](https://github.com/PowerDNS/pdns/commit/7dc86bf), [commit 2fda71f](https://github.com/PowerDNS/pdns/commit/2fda71f): PowerDNS now polls the security status of a release at startup and periodically. More detail on this feature, and how to turn it off, can be found in [Security polling](common/security.md#security-polling).
+- [commit 5fe6dc0](https://github.com/PowerDNS/pdns/commit/5fe6dc0): API: Replace HTTP Basic auth with static key in custom header (X-API-Key)
+- [commit 4a95ab4](https://github.com/PowerDNS/pdns/commit/4a95ab4): Use transaction for pdnssec increase-serial
+- [commit 6e82a23](https://github.com/PowerDNS/pdns/commit/6e82a23): Don't empty ordername during pdnssec increase-serial
+- [commit 535f4e3](https://github.com/PowerDNS/pdns/commit/535f4e3): honor SOA-EDIT while considering "empty IXFR" fallback, fixes [ticket 1835](https://github.com/PowerDNS/pdns/issues/1835). This fixes slaving of signed zones to IXFR-aware slaves like NSD or BIND.
+
+# PowerDNS Authoritative Server 3.4.0
+Released September 30th, 2014
+
+This is a performance, feature, bugfix and conformity update to 3.3.1 and any earlier version. It contains a huge amount of work by various contributors, to whom we are very grateful.
+
+**Warning**: Version 3.4.0 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Additionally, if you are coming from any 3.x version (including 3.3.1), there is a mandatory SQL schema upgrade. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+## Downloads
+Find the downloads [on our download page](https://www.powerdns.com/downloads.html).
+
+A list of changes since 3.3.1 follows.
+
+Changes between RC2 and 3.4.0:
+
+- [commit ad189c9](https://github.com/PowerDNS/pdns/commit/ad189c9), [commit 445d93c](https://github.com/PowerDNS/pdns/commit/445d93c): also distribute the dnsdist manual page
+- [commit b5a276d](https://github.com/PowerDNS/pdns/commit/b5a276d), [commit 0b346e9](https://github.com/PowerDNS/pdns/commit/0b346e9), [commit 74caf87](https://github.com/PowerDNS/pdns/commit/74caf87), [commit 642fd2e](https://github.com/PowerDNS/pdns/commit/642fd2e): Make sure all backends actually work as dynamic modules
+- [commit 14b11c4](https://github.com/PowerDNS/pdns/commit/14b11c4): raise log level on dlerror(), fixes [ticket 1734](https://github.com/PowerDNS/pdns/issues/1734), thanks @James-TR
+- [commit 016d810](https://github.com/PowerDNS/pdns/commit/016d810): improve postgresql detection during ./configure
+- [commit dce1e90](https://github.com/PowerDNS/pdns/commit/dce1e90): DNAME: don't sign the synthesised CNAME
+- [commit 25e7af3](https://github.com/PowerDNS/pdns/commit/25e7af3): send empty SERVFAIL after a backend throws a DBException, instead of including useless content
+
+Changes between RC1 and RC2:
+
+- [commit bb6e54f](https://github.com/PowerDNS/pdns/commit/bb6e54f): document udp6-queries, udp4-queries, add rd-queries, recursion-unanswered metrics & document. Closes [ticket 1400](https://github.com/PowerDNS/pdns/issues/1400).
+- [commit 4a23af7](https://github.com/PowerDNS/pdns/commit/4a23af7): init script: support DAEMON\_ARGS; [commit 7e5b3a0](https://github.com/PowerDNS/pdns/commit/7e5b3a0): init script: ensure socket dir exists
+- [commit dd930ed](https://github.com/PowerDNS/pdns/commit/dd930ed): don't import supermaster ips from other accounts
+- [commit ed3afdf](https://github.com/PowerDNS/pdns/commit/ed3afdf): fall back to central bind if reuseport bind fails; improves [ticket 1715](https://github.com/PowerDNS/pdns/issues/1715)
+- [commit 709ca59](https://github.com/PowerDNS/pdns/commit/709ca59): GeoIP backend implementation. This is a new backend, still experimental!
+- [commit bf5a484](https://github.com/PowerDNS/pdns/commit/bf5a484): support EVERY future version of OS X, fixes [ticket 1702](https://github.com/PowerDNS/pdns/issues/1702)
+- [commit 4dbaec6](https://github.com/PowerDNS/pdns/commit/4dbaec6): Check for \_\_FreeBSD\_kernel\_\_ as per https://lists.debian.org/debian-bsd/2006/03/msg00127.html, fixes [ticket 1684](https://github.com/PowerDNS/pdns/issues/1684); [commit 74f389d](https://github.com/PowerDNS/pdns/commit/74f389d): \_\_FreeBSD\_kernel\_\_ is defined but empty on systems with FreeBSD kernels, breaking compile. Thanks pawal
+- [commit 2e6bbd8](https://github.com/PowerDNS/pdns/commit/2e6bbd8): Catch PDNSException in Signingpiper::helperWorker to avoid abort
+- [commit 0ffd51d](https://github.com/PowerDNS/pdns/commit/0ffd51d): improve error reporting on malformed labels
+- [commit c48dec7](https://github.com/PowerDNS/pdns/commit/c48dec7): Fix forwarded TSIG message issue
+- [commit dad70f2](https://github.com/PowerDNS/pdns/commit/dad70f2): skip TCP\_DEFER\_ACCEPT on platforms that do not have it (like FreeBSD); fixes [ticket 1658](https://github.com/PowerDNS/pdns/issues/1658)
+- [commit c7287b6](https://github.com/PowerDNS/pdns/commit/c7287b6): should fix [ticket 1662](https://github.com/PowerDNS/pdns/issues/1662), reloading while checking for domains that need to be notified in BIND, causing lock
+- [commit 3e67ea8](https://github.com/PowerDNS/pdns/commit/3e67ea8): allow OPT pseudo record type in IXFR query
+- [commit a1caa8b](https://github.com/PowerDNS/pdns/commit/a1caa8b): webserver: htmlescape VERSION and config name
+- [commit df9d980](https://github.com/PowerDNS/pdns/commit/df9d980): Remove "log-failed-updates" leftover
+- [commit a1fe72a](https://github.com/PowerDNS/pdns/commit/a1fe72a): Remove unused "soa-serial-offset" option
+
+Changes between 3.3.1 and 3.4.0-RC1 follow.
+
+## DNSSEC changes
+- [commit bba8413](https://github.com/PowerDNS/pdns/commit/bba8413): add option (max-signature-cache-entries) to limit the maximum number of cached signatures.
+- [commit 28b66a9](https://github.com/PowerDNS/pdns/commit/28b66a9): limit the number of NSEC3 iterations (see RFC5155 10.3), with the max-nsec3-iterations option.
+- [commit b50efd6](https://github.com/PowerDNS/pdns/commit/b50efd6): drop the 'superfluous NSEC3' option that old BIND validators need.
+- The bindbackend 'hybrid' mode was reintroduced by Kees Monshouwer. Enable it with bind-hybrid.
+- Aki Tuomi contributed experimental PKCS\#11 support for DNSSEC key management with a (Soft)HSM.
+- Direct RRSIG queries now return NOTIMP.
+- [commit fa37777](https://github.com/PowerDNS/pdns/commit/fa37777): add secure-all-zones command to pdnssec
+- Unrectified zones can now get rectified 'on the fly' during outgoing AXFR. This makes it possible to run a hidden signing master without rectification.
+- [commit 82fb538](https://github.com/PowerDNS/pdns/commit/82fb538): AXFR in: don't accept zones with a mixture of Opt-Out NSEC3 RRs and non-Opt-Out NSEC3 RRs
+- Various minor bugfixes, mostly from the unstoppable Kees Monshouwer.
+- [commit 0c4c552](https://github.com/PowerDNS/pdns/commit/0c4c552): set non-zero exit status in pdnssec if an exception was thrown, for easier automatic usage.
+- [commit b8bd119](https://github.com/PowerDNS/pdns/commit/b8bd119): pdnssec -v show-zone: Print all keys instead of just entry point keys.
+- [commit 52e0d78](https://github.com/PowerDNS/pdns/commit/52e0d78): answer direct NSEC queries without DO bit
+- [commit ca2eb01](https://github.com/PowerDNS/pdns/commit/ca2eb01): output ZSK DNSKEY records if experimental-direct-dnskey support is enabled
+- [commit 83609e2](https://github.com/PowerDNS/pdns/commit/83609e2): SOA-EDIT: fix INCEPTION-INCREMENT handling
+- [commit ac4a2f1](https://github.com/PowerDNS/pdns/commit/ac4a2f1): AXFR-out can handle secure and insecure NSEC3 optout delegations
+- [commit ff47302](https://github.com/PowerDNS/pdns/commit/ff47302): AXFR-in can handle secure and insecure NSEC3 optout delegations
+
+## New features
+- DNAME support. Enable with experimental-dname-processing.
+- PowerDNS can now send stats directly to Carbon servers. Enable with carbon-server, tweak with carbon-ourname and carbon-interval.
+- [commit 767da1a](https://github.com/PowerDNS/pdns/commit/767da1a): Add list-zone capability to pdns\_control
+- [commit 51f6bca](https://github.com/PowerDNS/pdns/commit/51f6bca): Add delete-zone to pdnssec.
+- The gsql backends now support record comments, and disabling records.
+- The new reuseport config option allows setting SO\_REUSEPORT, which allows for some performance improvements.
+- local-address-nonexist-fail and local-ipv6-nonexist-fail allow pdns to start up even if some addresses fail to bind.
+- 'AXFR-SOURCE' in domainmetadata sets the source address for an AXFR retrieval.
+- [commit 451ba51](https://github.com/PowerDNS/pdns/commit/451ba51): Implement pdnssec get-meta/set-meta
+- Experimental RFC2136/DNS UPDATE support from Ruben d'Arco, with extensive testing by Kees Monshouwer.
+- pdns\_control bind-add-zone
+- New option bind-ignore-broken-records ignores out-of-zone records while loading zone files.
+- pdnssec now has commands for TSIG key management.
+- We now support other algorithms than MD5 for TSIG.
+- [commit ba7244a](https://github.com/PowerDNS/pdns/commit/ba7244a): implement pdns\_control qtypes
+- Support for += syntax for options
+
+## Bugfixes
+- We verify the algorithm used for TSIG queries, and use the right algorithm in signing if there is possible confusion. Plus a few minor TSIG-related fixes.
+- [commit ff99a74](https://github.com/PowerDNS/pdns/commit/ff99a74): making *-threads settings empty now yields a default of one instead of zero.
+- [commit 9215e60](https://github.com/PowerDNS/pdns/commit/9215e60): we had a deadly embrace in getUpdatedMasters in bindbackend reimplementation, thanks to Winfried for detailed debugging!
+- [commit 9245fd9](https://github.com/PowerDNS/pdns/commit/9245fd9): don't addSuckRequest after supermaster zone creation to avoid one cause of simultaneous AXFR for the same zone
+- [commit 719f902](https://github.com/PowerDNS/pdns/commit/719f902): fix dual-stack superslave when multiple namservers share a ip
+- [commit 33966bf](https://github.com/PowerDNS/pdns/commit/33966bf): avoid address truncation in doNotifications
+- [commit eac85b1](https://github.com/PowerDNS/pdns/commit/eac85b1): prevent duplicate slave notications caused by different ipv6 address formatting
+- [commit 3c8a711](https://github.com/PowerDNS/pdns/commit/3c8a711): make notification queue ipv6 compatible
+- [commit 0c13e45](https://github.com/PowerDNS/pdns/commit/0c13e45): make isMaster ip check more tolerant for different ipv6 notations
+- Various fixes for possible issues reported by Coverity Scan ([commit f17c93b](https://github.com/PowerDNS/pdns/commit/f17c93b), )
+- [commit 9083987](https://github.com/PowerDNS/pdns/commit/9083987): don't rely on included polarssl header files when using system polarssl. Spotted by Oden Eriksson of Mandriva, thanks!
+- Various users reported pdns\_control hangs, especially when using the guardian. We are confident that all causes of these hangs are now gone.
+- Decreasing the webserver ringbuffer size could cause crashes.
+- [commit 4c89cce](https://github.com/PowerDNS/pdns/commit/4c89cce): nproxy: Add missing chdir("/") after chroot()
+- [commit 016a0ab](https://github.com/PowerDNS/pdns/commit/016a0ab): actually notice timeout during AXFR retrieve, thanks hkraal
+
+## REST API changes
+- The REST API was much improved and is nearing stability, thanks to Christian Hofstaedtler and others.
+- Mark Schouten at Tuxis contributed a zone importer.
+
+## Other changes
+- Our tarballs and packages now include *.sql schema files for the SQL backends.
+- The webserver (including API) now has an ACL (webserver-allow-from).
+- Webserver (including API) is now powered by YaHTTP.
+- Various autotools usage improvements from Ruben Kerkhof.
+- The dist tarball is now bzip2-compressed instead of gzip.
+- Various remotebackend updates, including replacing curl with (included) yahttp.
+- Dynamic module loading is now allowed on Mac OS X.
+- The AXFR ACL (allow-axfr-ips) now defaults to 127.0.0.0/8,::1 instead of the whole world.
+- [commit ba91c2f](https://github.com/PowerDNS/pdns/commit/ba91c2f): remove unused gpgsql-socket option and document postgres socket usage
+- Improved support for Lua 5.2.
+- The edns-subnet option code is now fixed at 8, and the edns-subnet-option-numbers option has been removed.
+- geobackend now has very limited edns-subnet support - it will use the 'real' remote if available.
+- pipebackend ABI v4 adds the zone name to the AXFR command.
+- We now [avoid getaddrinfo()](http://blog.powerdns.com/2014/05/21/a-surprising-discovery-on-converting-ipv6-addresses-we-no-longer-prefer-getaddrinfo/) as much as possible.
+- The packet cache now handles (forwarded) recursive answers better, including TTL aging and respecting allow-recursion.
+- [commit ff5ba4f](https://github.com/PowerDNS/pdns/commit/ff5ba4f): pdns\_server --help no longer exits with 1.
+- Mark Zealey contributed an experimental LMDB backend. Kees Monshouwer added experimental DNSSEC support to it. Thanks, both!
+- [commit 81859ba](https://github.com/PowerDNS/pdns/commit/81859ba): No longer attempt to answer questions coming in from port 0, reply would not reach them anyhow. Thanks to Niels Bakker and sid3windr for insight & debugging. Closes [ticket 844](https://github.com/PowerDNS/pdns/issues/844).
+- RCodes are now reported in text in various places, thanks Aki.
+- Kees Monshouwer set up automatic testing for the oracle and goracle backends, and fixed various issues in them.
+- Leftovers of previous support for Windows have been removed, thanks to Kees Monshouwer, Aki Tuomi.
+- Bundled PolarSSL has been upgraded to 1.3.2
+- PolarSSL replaced previously bundled implementations of AES ([commit e22d9b4](https://github.com/PowerDNS/pdns/commit/e22d9b4)) and SHA ([commit 9101035](https://github.com/PowerDNS/pdns/commit/9101035))
+- bindbackend is now a module
+- [commit 14a2e52](https://github.com/PowerDNS/pdns/commit/14a2e52): Use the inet data type for supermasters.ip on postgrsql.
+- We now send an empty SERVFAIL when a CNAME chain is too long, instead of including the partial chain.
+- [commit 3613a51](https://github.com/PowerDNS/pdns/commit/3613a51): Show built-in features in --version output
+- [commit 4bd7d35](https://github.com/PowerDNS/pdns/commit/4bd7d35): make domainmetadata queries case insensitive
+- [commit 088c334](https://github.com/PowerDNS/pdns/commit/088c334): output warning message when no to be notified NS's are found
+- [commit 5631b44](https://github.com/PowerDNS/pdns/commit/5631b44): gpsqlbackend: use empty defaults for dbname and user; libpq will use the current user name for both by default
+- [commit d87ded3](https://github.com/PowerDNS/pdns/commit/d87ded3): implement udp-truncation-threshold to override the previous 1680 byte maximum response datagram size - no matter what EDNS0 said. Plus document it.
+- Implement udp-truncation-threshold to override the previous 1680 byte maximum response datagram size - no matter what EDNS0 said.
+- Removed settings related to fancy records, as we haven't supported those since version 3.0
+- Based on earlier work by Mark Zealey, Kees Monshouwer increased our packet cache performance between 200% and 500% depending on the situation, by simplifying some code in [commit 801812e](https://github.com/PowerDNS/pdns/commit/801812e) and [commit 8403ade](https://github.com/PowerDNS/pdns/commit/8403ade).
+
+# PowerDNS Recursor 3.6.1
+**Warning**: Version 3.6.1 is a mandatory security upgrade to 3.6.0! Released on the 10th of September 2014.
+
+PowerDNS Recursor 3.6.0 could crash with a specific sequence of packets. For more details, see [the advisory](security/powerdns-advisory-2014-01.md). PowerDNS Recursor 3.6.1 was very well tested, and is in full production already, so it should be a safe upgrade.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+
+In addition to various fixes related to this potential crash, 3.6.1 fixes a few minor issues and adds a debugging feature:
+
+- We could not encode IPv6 AAAA records that mapped to IPv4 addresses in some cases (:ffff.1.2.3.4). Fixed in [commit c90fcbd](https://github.com/PowerDNS/pdns/commit/c90fcbd) , closing [ticket 1663](https://github.com/PowerDNS/pdns/issues/1663).
+- Improve systemd startup timing with respect to network availability ([commit cf86c6a](https://github.com/PowerDNS/pdns/commit/cf86c6a)), thanks to Morten Stevens.
+- Realtime telemetry can now be enabled at runtime, for example with 'rec\_control carbon-server 82.94.213.34 ourname1234'. This ties in to our existing carbon-server and carbon-ourname settings, but now at runtime. This specific invocation will make your stats appear automatically on our [public telemetry server](http://xs.powerdns.com/metronome/?server=pdns.xs.recursor&beginTime=-3600).
+
+# PowerDNS Recursor version 3.6.0
+This is a performance, feature and bugfix update to 3.5/3.5.3. It contains important fixes for slightly broken domain names, which your users expect to work anyhow. It also brings robust resilience against certain classes of attacks.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](https://www.monshouwer.eu/download/3rd_party/pdns-recursor/)
+
+## Changes between RC1 and release
+- [commit 30b13ef](https://github.com/PowerDNS/pdns/commit/30b13ef): do not apply some of our filters to root and gtlds, plus remove some useless {}
+- [commit cc81d90](https://github.com/PowerDNS/pdns/commit/cc81d90): fix yahttp copy in dist-recursor for BSD cp
+- [commit b798618](https://github.com/PowerDNS/pdns/commit/b798618): define \_\_APPLE\_USE\_RFC\_3542 during recursor build on Darwin, fixes [ticket 1449](https://github.com/PowerDNS/pdns/issues/1449)
+- [commit 1d7f863](https://github.com/PowerDNS/pdns/commit/1d7f863): Merge pull request [ticket 1443](https://github.com/PowerDNS/pdns/issues/1443) from zeha/recursor-nostrip
+- [commit 5cdeede](https://github.com/PowerDNS/pdns/commit/5cdeede): remove (non-working) [aaaa-]additional-processing flags from the recursor. Closes [ticket 1448](https://github.com/PowerDNS/pdns/issues/1448)
+- [commit 984d747](https://github.com/PowerDNS/pdns/commit/984d747): Support building recursor on kFreeBSD and Hurd
+- [commit 79240f1](https://github.com/PowerDNS/pdns/commit/79240f1): Allow not stripping of binaries in recursor's make install
+- [commit e9c2ad3](https://github.com/PowerDNS/pdns/commit/e9c2ad3): document pdns.DROP for recursor, add policy-drops metric for it
+
+## New features
+- [commit aadceba](https://github.com/PowerDNS/pdns/commit/aadceba): Implement minimum-ttl-override config setting, plus runtime configurability via 'rec\_control set-minimum-ttl'.
+- Lots of work on the JSON API, which is exposed via Aki Tuomi's 'yahttp'. Massive thanks to Christian Hofstaedtler for delivering this exciting new functionality. Documentation & demo forthcoming, but code to use it is available [on GitHub](https://github.com/powerdns/pdnscontrol).
+- Lua modules can now use 'pdnslog(INFO..'), as described in [ticket 1074](https://github.com/PowerDNS/pdns/issues/1074), implemented in [commit 674a305](https://github.com/PowerDNS/pdns/commit/674a305)
+- Adopt any-to-tcp feature to the recursor. Based on a patch by Winfried Angele. Closes [ticket 836](https://github.com/PowerDNS/pdns/issues/836), [commit 56b4d21](https://github.com/PowerDNS/pdns/commit/56b4d21) and [commit e661a20](https://github.com/PowerDNS/pdns/commit/e661a20).
+- [commit 2c78bd5](https://github.com/PowerDNS/pdns/commit/2c78bd5): implement built-in statistics dumper using the 'carbon' protocol, which is also understood by metronome (our mini-graphite). Use 'carbon-server', 'carbon-ourname' and 'carbon-interval' settings.
+- New setting 'udp-truncation-threshold' to configure from how many bytes we should truncate. [commit a09a8ce](https://github.com/PowerDNS/pdns/commit/a09a8ce).
+- Proper support for CHaos class for CHAOS TXT queries. [commit c86e1f2](https://github.com/PowerDNS/pdns/commit/c86e1f2), addition for lua in [commit f94c53d](https://github.com/PowerDNS/pdns/commit/f94c53d), some warnings in [commit 438db54](https://github.com/PowerDNS/pdns/commit/438db54) however.
+- Added support for Lua scripts to drop queries w/o further processing. [commit 0478c54](https://github.com/PowerDNS/pdns/commit/0478c54).
+- Kevin Holly added qtype statistics to recursor and rec\_control (get-qtypelist) ([commit 79332bf](https://github.com/PowerDNS/pdns/commit/79332bf))
+- Add support for include-files in configuration, also reload ACLs and zones defined in them ([commit 829849d](https://github.com/PowerDNS/pdns/commit/829849d), [commit 242b90e](https://github.com/PowerDNS/pdns/commit/242b90e), [commit 302df81](https://github.com/PowerDNS/pdns/commit/302df81)).
+- Paulo Anes contributed server-down-max-fails which helps combat Recursive DNS based amplification attacks. Described in [this post](http://blog.powerdns.com/2014/04/03/further-dos-guidance-packages-and-patches-available/). Also comes with new metric 'failed-host-entries' in [commit 406f46f](https://github.com/PowerDNS/pdns/commit/406f46f).
+- [commit 21e7976](https://github.com/PowerDNS/pdns/commit/21e7976): Implement "followCNAMERecords" feature in the Lua hooks.
+
+## Improvements
+- [commit 06ea901](https://github.com/PowerDNS/pdns/commit/06ea901): make pdns-distributes-queries use a hash so related queries get sent to the same thread. Original idea by Winfried Angele. Astoundingly effective, approximately halves CPU usage!
+- [commit b13e737](https://github.com/PowerDNS/pdns/commit/b13e737): --help now writes to stdout instead of stderr. Thanks Winfried Angele.
+- To aid in limiting DoS attacks, when truncating a response, we actually truncate all the way so only the question remains. Suggested in [ticket 1092](https://github.com/PowerDNS/pdns/issues/1092), code in [commit add935a](https://github.com/PowerDNS/pdns/commit/add935a).
+- No longer experimental, the switch 'pdns-distributes-queries' can improve multi-threaded performance on Linux (various cleanup commits).
+- Update to embedded PolarSSL, plus remove previous AES implementation and shift to PolarSSL ([commit e22d9b4](https://github.com/PowerDNS/pdns/commit/e22d9b4), [commit 990ad9a](https://github.com/PowerDNS/pdns/commit/990ad9a))
+- [commit 92c0733](https://github.com/PowerDNS/pdns/commit/92c0733) moves various Lua magic constants into an enum namespace.
+- set group and supplementary groups before chroot ([commit 6ee50ce](https://github.com/PowerDNS/pdns/commit/6ee50ce), [ticket 1198](https://github.com/PowerDNS/pdns/issues/1198)).
+- [commit 4e9a20e](https://github.com/PowerDNS/pdns/commit/4e9a20e): raise our socket buffer setting so it no longer generates a warning about lowering it.
+- [commit 4e9a20e](https://github.com/PowerDNS/pdns/commit/4e9a20e): warn about Linux suboptimal IPv6 settings if we detect them.
+- SIGUSR2 turns on a 'trace' of all DNS traffic, a second SIGUSR2 now turns it off again. [commit 4f217ce](https://github.com/PowerDNS/pdns/commit/4f217ce).
+- Various fixes for Lua 5.2.
+- [commit 81859ba](https://github.com/PowerDNS/pdns/commit/81859ba): No longer attempt to answer questions coming in from port 0, reply would not reach them anyhow. Thanks to Niels Bakker and 'sid3windr' for insight & debugging. Closes [ticket 844](https://github.com/PowerDNS/pdns/issues/844).
+- [commit b1a2d6c](https://github.com/PowerDNS/pdns/commit/b1a2d6c): now, I'm not one to get OCD over things, but that log message about stats based on 1801 seconds got to me. 1800 now.
+
+## Fixes
+- 0c9de4fc: stay away from getaddrinfo unless we really can't help it for ascii ipv6 conversions to binary
+- [commit 08f3f63](https://github.com/PowerDNS/pdns/commit/08f3f63): fix average latency calculation, closing [ticket 424](https://github.com/PowerDNS/pdns/issues/424).
+- [commit 75ba907](https://github.com/PowerDNS/pdns/commit/75ba907): Some of our counters were still 32 bits, now 64.
+- [commit 2f22827](https://github.com/PowerDNS/pdns/commit/2f22827): Fix statistics and stability when running with pdns-distributes-queries.
+- [commit 6196f90](https://github.com/PowerDNS/pdns/commit/6196f90): avoid merging old and new additional data, fixes an issue caused by weird (but probably legal) Akamai behaviour
+- [commit 3a8a4d6](https://github.com/PowerDNS/pdns/commit/3a8a4d6): make sure we don't exceed the number of available filedescriptors for mthreads. Raises performance in case of DoS. See [this post](http://blog.powerdns.com/2014/02/06/related-to-recent-dos-attacks-recursor-configuration-file-guidance/) for further details.
+- [commit 7313fe6](https://github.com/PowerDNS/pdns/commit/7313fe6): implement indexed packet cache wiping for recursor, orders of magnitude faster. Important when reloading all zones, which causes massive cache cleaning.
+- rec\_control get-all would include 'cache-bytes' and 'packetcache-bytes', which were expensive operations, too expensive for frequent polling. Removed in [commit 8e42d27](https://github.com/PowerDNS/pdns/commit/8e42d27).
+- All old workarounds for supporting Windows of the XP era have been removed.
+- Fix issues on S390X based systems which have unsigned characters ([commit 916a0fd](https://github.com/PowerDNS/pdns/commit/916a0fd))
+
+# PowerDNS Authoritative Server version 3.3.1
+Released December 17th, 2013
+
+This is a bugfix update to 3.3.
+
+## Downloads
+- [Official download page](http://www.powerdns.com/content/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-server/)
+
+## Changes since 3.3
+- direct-dnskey is no longer experimental, thanks Kees Monshouwer & co for extensive testing ([commit e4b36a4](https://github.com/PowerDNS/pdns/commit/e4b36a4)).
+- Handle signals during poll ([commit 5dde2c6](https://github.com/PowerDNS/pdns/commit/5dde2c6)).
+- [commit 7538e56](https://github.com/PowerDNS/pdns/commit/7538e56): Fix zone2{sql,json} exit codes
+- [commit 7593c40](https://github.com/PowerDNS/pdns/commit/7593c40): geobackend: fix possible nullptr deref
+- [commit 3506cc6](https://github.com/PowerDNS/pdns/commit/3506cc6): gpsqlbackend: don't append empty dbname=/user= values to connect string
+- gpgsql queries were simplified through the use of casting ([commit 9a6e39c](https://github.com/PowerDNS/pdns/commit/9a6e39c)).
+- [commit a7aa9be](https://github.com/PowerDNS/pdns/commit/a7aa9be): Replace hardcoded make with variable
+- [commit e4fe901](https://github.com/PowerDNS/pdns/commit/e4fe901): make sure to run PKG\_PROG\_PKG\_CONFIG before the first PKG\_* usage
+- [commit 29bf169](https://github.com/PowerDNS/pdns/commit/29bf169): fix hmac-md5 TSIG key lookup
+- [commit c4e348b](https://github.com/PowerDNS/pdns/commit/c4e348b): fix 64+ character TSIG keys
+- [commit 00a7b25](https://github.com/PowerDNS/pdns/commit/00a7b25): Fix comparison between signed and unsigned by using uint32\_t for inception on INCEPTION-EPOCH
+- [commit d3f6432](https://github.com/PowerDNS/pdns/commit/d3f6432): fix building on os x 10.9, thanks Martijn Bakker.
+- We now allow building against Lua 5.2 ([commit bef3000](https://github.com/PowerDNS/pdns/commit/bef3000), [commit 2bdd03b](https://github.com/PowerDNS/pdns/commit/2bdd03b), [commit 88d9e99](https://github.com/PowerDNS/pdns/commit/88d9e99)).
+- [commit fa1f845](https://github.com/PowerDNS/pdns/commit/fa1f845): autodetect MySQL 5.5+ connection charset
+- When misconfigured using 'right' timezones, a bug in (g)libc gmtime breaks our signatures. Fixed in [commit e4faf74](https://github.com/PowerDNS/pdns/commit/e4faf74) by Kees Monshouwer by implementing our own gmtime\_r.
+- When sending SERVFAIL due to a CNAME loop, don't uselessly include the CNAMEs ([commit dfd1b82](https://github.com/PowerDNS/pdns/commit/dfd1b82)).
+- Build fixes for platforms with 'weird' types (like s390/s390x): [commit c669f7c](https://github.com/PowerDNS/pdns/commit/c669f7c) ([details](http://blog.powerdns.com/2013/10/28/on-ragel-and-char-types/)), [commit 07b904e](https://github.com/PowerDNS/pdns/commit/07b904e) and [commit 2400764](https://github.com/PowerDNS/pdns/commit/2400764).
+- Support for += syntax for options, [commit 98dd325](https://github.com/PowerDNS/pdns/commit/98dd325) and others.
+- [commit f8f29f4](https://github.com/PowerDNS/pdns/commit/f8f29f4): nproxy: Add missing chdir("/") after chroot()
+- [commit 2e6e9ad](https://github.com/PowerDNS/pdns/commit/2e6e9ad): fix for "missing" libmysqlclient on RHEL/CentOS based systems
+- pdnssec check-zone improvements in [commit 5205892](https://github.com/PowerDNS/pdns/commit/5205892), [commit edb255f](https://github.com/PowerDNS/pdns/commit/edb255f), [commit 0dde9d0](https://github.com/PowerDNS/pdns/commit/0dde9d0), [commit 07ee700](https://github.com/PowerDNS/pdns/commit/07ee700), [commit 79a3091](https://github.com/PowerDNS/pdns/commit/79a3091), [commit 08f3452](https://github.com/PowerDNS/pdns/commit/08f3452), [commit bcf9daf](https://github.com/PowerDNS/pdns/commit/bcf9daf), [commit c9a3dd7](https://github.com/PowerDNS/pdns/commit/c9a3dd7), [commit 6ebfd08](https://github.com/PowerDNS/pdns/commit/6ebfd08), [commit fd53bd0](https://github.com/PowerDNS/pdns/commit/fd53bd0), [commit 7eaa83a](https://github.com/PowerDNS/pdns/commit/7eaa83a), [commit e319467](https://github.com/PowerDNS/pdns/commit/e319467), ,
+- NSEC/NSEC3 fixes in [commit 3191709](https://github.com/PowerDNS/pdns/commit/3191709), [commit f75293f](https://github.com/PowerDNS/pdns/commit/f75293f), [commit cd30e94](https://github.com/PowerDNS/pdns/commit/cd30e94), [commit 74baf86](https://github.com/PowerDNS/pdns/commit/74baf86), [commit 1fa8b2b](https://github.com/PowerDNS/pdns/commit/1fa8b2b)
+- The webserver could crash when the ring buffers were resized, fixed in [commit 3dfb45f](https://github.com/PowerDNS/pdns/commit/3dfb45f).
+- [commit 213ec4a](https://github.com/PowerDNS/pdns/commit/213ec4a): add constraints for name to pg schema
+- [commit f104427](https://github.com/PowerDNS/pdns/commit/f104427): make domainmetadata queries case insensitive
+- [commit 78fc378](https://github.com/PowerDNS/pdns/commit/78fc378): no label compression for name in TSIG records
+- [commit 15d6ffb](https://github.com/PowerDNS/pdns/commit/15d6ffb): pdnssec now outputs ZSK DNSKEY records if experimental-direct-dnskey support is enabled (renamed to direct-dnskey before release!)
+- [commit ad67d0e](https://github.com/PowerDNS/pdns/commit/ad67d0e): drop cryptopp from static build as libcryptopp.a is broken on Debian 7, which is what we build on
+- [commit 7632dd8](https://github.com/PowerDNS/pdns/commit/7632dd8): support polarssl 1.3 externally.
+- Remotebackend was fully updated in various commits.
+- [commit 82def39](https://github.com/PowerDNS/pdns/commit/82def39): SOA-EDIT: fix INCEPTION-INCREMENT handling
+- [commit a3a546c](https://github.com/PowerDNS/pdns/commit/a3a546c): add innodb-read-committed option to gmysql settings.
+- [commit 9c56e16](https://github.com/PowerDNS/pdns/commit/9c56e16): actually notice timeout during AXFR retrieve, thanks hkraal
+
+# PowerDNS Recursor version 3.5.3
+Released September 17th, 2013
+
+This is a bugfix and performance update to 3.5.2. It brings serious performance improvements for dual stack users.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-recursor/)
+
+## Changes since 3.5.2
+- 3.5 replaced our ANY query with A+AAAA for users with IPv6 enabled. Extensive measurements by Darren Gamble showed that this change had a non-trivial performance impact. We now do the ANY query like before, but fall back to the individual A+AAAA queries when necessary. Change in [commit 1147a8b](https://github.com/PowerDNS/pdns/commit/1147a8b).
+- The IPv6 address for d.root-servers.net was added in [commit 66cf384](https://github.com/PowerDNS/pdns/commit/66cf384), thanks Ralf van der Enden.
+- We now drop packets with a non-zero opcode (i.e. special packets like DNS UPDATE) earlier on. If the experimental pdns-distributes-queries flag is enabled, this fix avoids a crash. Normal setups were never susceptible to this crash. Code in [commit 35bc40d](https://github.com/PowerDNS/pdns/commit/35bc40d), closes [ticket 945](https://github.com/PowerDNS/pdns/issues/945).
+- TXT handling was somewhat improved in [commit 4b57460](https://github.com/PowerDNS/pdns/commit/4b57460), closing [ticket 795](https://github.com/PowerDNS/pdns/issues/795).
+
+# PowerDNS Recursor version 3.5.2
+Released June 7th, 2013
+
+This is a stability and bugfix update to 3.5.1. It contains important fixes that improve operation for certain domains.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-recursor/)
+
+## Changes since 3.5.1
+- Responses without the QR bit set now get matched up to an outstanding query, so that resolution can be aborted early instead of waiting for a timeout. Code in [commit ee90f02](https://github.com/PowerDNS/pdns/commit/ee90f02).
+- The depth limiter changes in 3.5.1 broke some legal domains with lots of indirection. Improved in [commit d393c2d](https://github.com/PowerDNS/pdns/commit/d393c2d).
+- Slightly improved logging to aid debugging. Code in [commit 437824d](https://github.com/PowerDNS/pdns/commit/437824d) and [commit 182005e](https://github.com/PowerDNS/pdns/commit/182005e).
+
+# PowerDNS Authoritative Server version 3.3
+Released on July 5th 2013
+
+This a stability, bugfix and conformity update to 3.2. It improves interoperability with various validators, either through bugfixes or by catering to their needs beyond the specifications.
+
+**Warning**: Version 3.3 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. There are also some important changes if you are coming from 3.0, 3.1 or 3.2. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+## Downloads
+- [Official download page](http://www.powerdns.com/content/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-server/)
+
+## Changes between RC2 and final
+- pdnssec rectify-zone now refuses to operate on presigned zones, as rectification already happens during incoming transfer. Patch by Kees Monshouwer in [commit 9bd211e](https://github.com/PowerDNS/pdns/commit/9bd211e).
+- We now handle zones with a mix of NSEC3 opt-out and non-opt-out ranges correctly during inbound and outbound AXFR. Many thanks to Kees Monshouwer. Code in [commit 5aa7003](https://github.com/PowerDNS/pdns/commit/5aa7003) and [commit d3e7b17](https://github.com/PowerDNS/pdns/commit/d3e7b17).
+- More remotebackend fixes ([commit 32d4f44](https://github.com/PowerDNS/pdns/commit/32d4f44), [commit 44c2ee8](https://github.com/PowerDNS/pdns/commit/44c2ee8), [commit 1fcc7b7](https://github.com/PowerDNS/pdns/commit/1fcc7b7), [commit 0b1a3b2](https://github.com/PowerDNS/pdns/commit/0b1a3b2), [commit 9a319b1](https://github.com/PowerDNS/pdns/commit/9a319b1)), thanks Aki Tuomi.
+- Some compiler warnings were squashed ([commit ed554db](https://github.com/PowerDNS/pdns/commit/ed554db)), thanks Morten Stevens.
+- Fix broken memory access in LOC parser ([commit 4eec51b](https://github.com/PowerDNS/pdns/commit/4eec51b), [commit bea513c](https://github.com/PowerDNS/pdns/commit/bea513c)), thanks Aki Tuomi.
+- DNSSEC: DS queries at the apex of a zone for which we are not hosting the parent, would wrongly get an 'unauth NOERROR'. Fixed by Kees Monshouwer in [commit 34479a6](https://github.com/PowerDNS/pdns/commit/34479a6).
+
+## Changes between RC1 and RC2
+- Added dnstcpbench tool, by popular demand.
+- We always shipped a static tools RPM; we now have a similar Debian package. All packages have been cleaned up a bit, and the binary collections are now consistent between RPM and Deb. New: pass --enable-tools to configure to have the tools included in 'make all' and 'make install'.
+- [commit 4d2e3f5](https://github.com/PowerDNS/pdns/commit/4d2e3f5): add selinux policy files
+- We would sometimes send a single NULL byte, or nothing at all, instead of an OPT record. Fixed in [commit bf7f822](https://github.com/PowerDNS/pdns/commit/bf7f822), [commit 063076b](https://github.com/PowerDNS/pdns/commit/063076b), [commit 90d361d](https://github.com/PowerDNS/pdns/commit/90d361d).
+- [commit 2ee9ba2](https://github.com/PowerDNS/pdns/commit/2ee9ba2): expand any-to-tcp to direct RRSIG queries
+- [commit 5fff084](https://github.com/PowerDNS/pdns/commit/5fff084), [commit e38ef51](https://github.com/PowerDNS/pdns/commit/e38ef51): drop no-op flag strict-rfc-axfrs, thanks Jelte Jansen.
+- [commit f3d8902](https://github.com/PowerDNS/pdns/commit/f3d8902), [commit 7c0b859](https://github.com/PowerDNS/pdns/commit/7c0b859), [commit 5eea730](https://github.com/PowerDNS/pdns/commit/5eea730): Implement MINFO qtype for better interaction when slaving zones from NSD (that contain MINFO). Thanks to Jelte Jansen.
+- [commit 8655a42](https://github.com/PowerDNS/pdns/commit/8655a42), [commit bf79c6a](https://github.com/PowerDNS/pdns/commit/bf79c6a), [commit 38c941b](https://github.com/PowerDNS/pdns/commit/38c941b): SRV record can have a '.' as final field, from which we would dutifully strip the trailing ., leaving void, confusing everything. We now remove the trailing . in the right place, and not if we are trying to server '.'. Again thanks to Jelte & SIDN for catching this.
+- [commit 70d5a66](https://github.com/PowerDNS/pdns/commit/70d5a66): improve error message in ill formed unknown record type, thanks Jelte Jansen for reporting.
+- [commit 3640473](https://github.com/PowerDNS/pdns/commit/3640473): Built in webserver can now listen on IPv6, fixes [ticket 843](https://github.com/PowerDNS/pdns/issues/843). Also silences some useless messages about timeouts.
+- [commit 7db735c](https://github.com/PowerDNS/pdns/commit/7db735c), [commit d72166c](https://github.com/PowerDNS/pdns/commit/d72166c): CHANGES BEHAVIOUR: before we launch, check if we can connect to the controlsocket we are about to obliterate. If it works, abort. Fixes [ticket 841](https://github.com/PowerDNS/pdns/issues/841) and changes standing behaviour. There might be circumstances where PowerDNS now refuses to start, where it previously would. However, starting and making our previous instance mute wasn't good.
+- [commit 9130f9e](https://github.com/PowerDNS/pdns/commit/9130f9e): correctly refuse out-of-zone data in bindbackend, closes [ticket 845](https://github.com/PowerDNS/pdns/issues/845)
+- [commit 3363ef7](https://github.com/PowerDNS/pdns/commit/3363ef7): initialise server-id after all parsing is done, instead of half way through. Fixes situations where server-id was emptied explicitly. Reported by Wouter de Jong
+- [commit cd4f253](https://github.com/PowerDNS/pdns/commit/cd4f253): bump boost requirement, thanks Wouter de Jong
+- [commit 58cad74](https://github.com/PowerDNS/pdns/commit/58cad74): Update pdns auth init script so it works on wheezy
+- [commit 8714c9c](https://github.com/PowerDNS/pdns/commit/8714c9c): clang fixes by Aki Tuomi, thanks!
+- [commit 146601d](https://github.com/PowerDNS/pdns/commit/146601d): stretch supermasters.ip for IPv6, thanks Dennis Krul
+- [commit 1a5c5f9](https://github.com/PowerDNS/pdns/commit/1a5c5f9): various remotebackend improvements by Aki Tuomi
+- [commit 6ab1a11](https://github.com/PowerDNS/pdns/commit/6ab1a11): make sure systemd starts PowerDNS after relevant databases have been started, thanks Morten Stevens.
+- [commit 606018f](https://github.com/PowerDNS/pdns/commit/606018f), [commit ee5e175](https://github.com/PowerDNS/pdns/commit/ee5e175), [commit c76f6f4](https://github.com/PowerDNS/pdns/commit/c76f6f4): check scopeMask of answer packet, not of query packet!
+- [commit 2b18bcf](https://github.com/PowerDNS/pdns/commit/2b18bcf): Added warning if trailing dot is used, thanks Aki Tuomi.
+- [commit 16cf913](https://github.com/PowerDNS/pdns/commit/16cf913): make superfluous 'bind' NSEC3 record optional
+
+## New features and important changes since 3.2 (these changes are in RC1 and up)
+- [commit 04576ee](https://github.com/PowerDNS/pdns/commit/04576ee), [commit b0e15c8](https://github.com/PowerDNS/pdns/commit/b0e15c8): Implement pdnssec increase-serial, thanks Ruben d'Arco.
+- [commit cee857b](https://github.com/PowerDNS/pdns/commit/cee857b): PowerDNS now sets additional groups while dropping privileges.
+- [commit 7796a3b](https://github.com/PowerDNS/pdns/commit/7796a3b): Merge support for include-dir directive, thanks Aki Tuomi!
+- [commit d725755](https://github.com/PowerDNS/pdns/commit/d725755): make pdns-static Conflict with pdns-server, closes [ticket 640](https://github.com/PowerDNS/pdns/issues/640)
+- [commit c0d5504](https://github.com/PowerDNS/pdns/commit/c0d5504): pdnssec now emits 'INSERT INTO domain ..' queries when running without named.conf, thanks Ruben d'Arco.
+- [commit a1d6b0c](https://github.com/PowerDNS/pdns/commit/a1d6b0c): Older versions of the BIND 9 validating recursor need a superfluous NSEC3 record on positive wildcard responses. We now send this extra NSEC3. Closes [ticket 814](https://github.com/PowerDNS/pdns/issues/814).
+- [commit 07bf35d](https://github.com/PowerDNS/pdns/commit/07bf35d): catch a lot more errors in pdnssec and report them. Fixes [ticket 588](https://github.com/PowerDNS/pdns/issues/588).
+- [commit 032e390](https://github.com/PowerDNS/pdns/commit/032e390): make pdnssec exit with 1 on some error conditions, closes [ticket 677](https://github.com/PowerDNS/pdns/issues/677)
+- [commit 4af49b8](https://github.com/PowerDNS/pdns/commit/4af49b8), [commit 4cec6ac](https://github.com/PowerDNS/pdns/commit/4cec6ac): add ability to create an 'active' or inactive key using add-zone-key and import-zone-key, plus silenced some debugging. Fixes [ticket 707](https://github.com/PowerDNS/pdns/issues/707).
+- [commit fae4167](https://github.com/PowerDNS/pdns/commit/fae4167): Compiling against Lua 5.2 (--with-lua=lua5.2) now disables some code used for regression testing, instead of breaking during compile. This means that Lua 5.2 can be used in production.
+- [commit abc8f3f](https://github.com/PowerDNS/pdns/commit/abc8f3f), [357f6a7](https://github.com/PowerDNS/pdns/commit/357f6a7): Implement the new any-to-tcp option that, when set, always replies with a truncated response (TC=1) to ANY queries, forcing them to use TCP.
+- [commit 496073b](https://github.com/PowerDNS/pdns/commit/496073b): Since 3.0, pdnssec secure-zone has always generated 3 keys: one KSK and two ZSK, with one ZSK active. For most, if not almost all, users, this inactive ZSK is never used. We now no longer generate this useless ZSK. The resulting smaller DNSKEY RRset improves interoperability with certain validators. Closes [ticket 824](https://github.com/PowerDNS/pdns/issues/824).
+- [commit df55450](https://github.com/PowerDNS/pdns/commit/df55450): Non-DNSSEC ANY queries no longer get sent DNSSEC records. This improves interoperability with some old resolvers. Patch by Kees Monshouwer.
+- [commit 04b4bf6](https://github.com/PowerDNS/pdns/commit/04b4bf6): Merge support for not using opt-out with NSEC3. Many thanks to Kees Monshouwer.
+- [commit 8db49a6](https://github.com/PowerDNS/pdns/commit/8db49a6): We now try not to NOTIFY ourselves. In convoluted cases involving REUSE\_PORT and binding to 0.0.0.0 and ::, it might be possible that we guess wrong, in which case you can set prevent-self-notification to off.
+
+## Important bug fixes
+- [commit 63e365d](https://github.com/PowerDNS/pdns/commit/63e365d): don't mess up encoding when copying qname from question to answer in packetcache. Based on reports&debugging by Jimmy Bergman (sigint), Daniel Norman (Loopia) and the fine people at ISC. This avoids most issues related to BIND 9 erroneously blacklisting PowerDNS for lack of EDNS support.
+- [commit 3526186](https://github.com/PowerDNS/pdns/commit/3526186): fix backslash handling in TXT parser, includes test. Thanks Jan-Piet Mens.
+- [commit 830281f](https://github.com/PowerDNS/pdns/commit/830281f), [aef7330](https://github.com/PowerDNS/pdns/commit/aef7330): Accept chars \>127 ('high ASCII') in TXT records, closing [ticket 541](https://github.com/PowerDNS/pdns/issues/541) and [723](https://github.com/PowerDNS/pdns/issues/723).
+- [commit feef1ec](https://github.com/PowerDNS/pdns/commit/feef1ec): fix missing NSEC3 for secure delegation, thanks Kees Monshouwer, closes [ticket 682](https://github.com/PowerDNS/pdns/issues/682)
+- [commit b61e407](https://github.com/PowerDNS/pdns/commit/b61e407): around Thursday midnight, during signature rollovers, we would update the SOA serial too early. Fixed by reverting [commit d90efbf](https://github.com/PowerDNS/pdns/commit/d90efbf), adding 7 days margin to inception. Fix by Kees Monshouwer.
+- [commit ff64750](https://github.com/PowerDNS/pdns/commit/ff64750): make sure mixed-case queries get a correct apex NSEC3 type bitmap
+- [commit 4b153d8](https://github.com/PowerDNS/pdns/commit/4b153d8): always lowercase next name in NSEC to avoid interop troubles with validators, thanks Marco Davids&Matthijs Mekking.
+
+## Other changes
+- [commit 49977c6](https://github.com/PowerDNS/pdns/commit/49977c6): fix bug in boost.m4 where it insists on setting -L, causing useless RPATH in our binaries. Closes [ticket 728](https://github.com/PowerDNS/pdns/issues/728)
+- [commit 62ac758](https://github.com/PowerDNS/pdns/commit/62ac758): use PolarSSL for MD5 hashing instead of shipping our own copy of md5 hashing code, thanks Aki Tuomi.
+- [commit 775acd9](https://github.com/PowerDNS/pdns/commit/775acd9): give a better error on trying to add nsec3 parameters to a weird zone like "1 0 1 ab" (which indicates that you forgot to specify a zone name on the command line). Fixes [ticket 800](https://github.com/PowerDNS/pdns/issues/800).
+- [commit 315dd2e](https://github.com/PowerDNS/pdns/commit/315dd2e): Simplify socket listening code, and make sure we always set the nonblocking flag correctly. Patch by Mark Zealey, closes [ticket 664](https://github.com/PowerDNS/pdns/issues/664).
+- [commit b35da1b](https://github.com/PowerDNS/pdns/commit/b35da1b): if\_ether.h is in netinet/ not net/ on OpenBSD, thanks Florian Obser.
+- [commit 71301b6](https://github.com/PowerDNS/pdns/commit/71301b6): Replicate gsql backend feature of having separate -auth queries for DNSSEC into oraclebackend. Also lets you disable dnssec if you are not ready for it. Closes [ticket 527](https://github.com/PowerDNS/pdns/issues/527), patch by Aki Tuomi.
+- [commit 2125dac](https://github.com/PowerDNS/pdns/commit/2125dac): drop unused ignore-rd-bit flag
+- [commit 8c1a6d6](https://github.com/PowerDNS/pdns/commit/8c1a6d6): NSECx optimizations, thanks Kees Monshouwer.
+- [commit 664716a](https://github.com/PowerDNS/pdns/commit/664716a): drop unused variables in lua backend ( [ticket 653](https://github.com/PowerDNS/pdns/issues/653))
+- [commit d8ec70f](https://github.com/PowerDNS/pdns/commit/d8ec70f): fix db2 backend includes ( [ticket 653](https://github.com/PowerDNS/pdns/issues/653))
+- [commit 6477102](https://github.com/PowerDNS/pdns/commit/6477102): add goracle schema, thanks Aki Tuomi.
+- [commit 9118638](https://github.com/PowerDNS/pdns/commit/9118638): make goraclebackend "at least work", closes [ticket 729](https://github.com/PowerDNS/pdns/issues/729), thanks Aki Tuomi.
+- [commit e0ad7bb](https://github.com/PowerDNS/pdns/commit/e0ad7bb): add DS digest type 4 to show-zone output; add algorithm names. Based on a patch by Aki Tuomi, closes [ticket 744](https://github.com/PowerDNS/pdns/issues/744)
+- [commit 61a7fac](https://github.com/PowerDNS/pdns/commit/61a7fac): enable AM\_SILENT\_RULES, closing [ticket 647](https://github.com/PowerDNS/pdns/issues/647)
+- [commit 837f4b4](https://github.com/PowerDNS/pdns/commit/837f4b4): do a better job at escaping TXT, fixes [ticket 795](https://github.com/PowerDNS/pdns/issues/795)
+- [commit 6ca3fa7](https://github.com/PowerDNS/pdns/commit/6ca3fa7): add SOA-EDIT INCEPTION-INCREMENT mode, thanks stbuehler
+- [commit 6159c49](https://github.com/PowerDNS/pdns/commit/6159c49): Add connection info to sql-connect message
+- [commit 9f62e34](https://github.com/PowerDNS/pdns/commit/9f62e34), [commit 0fc965f](https://github.com/PowerDNS/pdns/commit/0fc965f), [commit 2035112](https://github.com/PowerDNS/pdns/commit/2035112): Added EUI48 and EUI64 record types
+- [commit f9cf6d9](https://github.com/PowerDNS/pdns/commit/f9cf6d9): cut the number of database queries in half for AXFR-in, thanks Kees Monshouwer.
+- [commit c87f987](https://github.com/PowerDNS/pdns/commit/c87f987): add default for SOA contact e-mail
+- [commit bb4a573](https://github.com/PowerDNS/pdns/commit/bb4a573): move random backend to modules, thanks Kees Monshouwer.
+- [commit 1071abd](https://github.com/PowerDNS/pdns/commit/1071abd): restyle builtin webserver page, thanks Christian Hofstaedtler.
+- [commit cd5e158](https://github.com/PowerDNS/pdns/commit/cd5e158): correct bogus use of poll(2) related constants, improving non-Linux portability. Thanks Wouter de Jong.
+- [commit 27ff60a](https://github.com/PowerDNS/pdns/commit/27ff60a): make sure our NSEC(3)s for names with spaces in them are correct. Reported by Jimmy Bergman. Includes test.
+- [commit 116e28a](https://github.com/PowerDNS/pdns/commit/116e28a): reduce log level of successful gpgsql/gsqlite3 connection to Info
+- [commit b23b90a](https://github.com/PowerDNS/pdns/commit/b23b90a): Metadata update is now in the same transaction as the AXFR. This improves slaving speed tremendously, especially for SQLite users. Patch by Kees Monshouwer.
+- [commit 4620e8a](https://github.com/PowerDNS/pdns/commit/4620e8a): Added zone2json, thanks Aki Tuomi.
+- [commit f0fa8b6](https://github.com/PowerDNS/pdns/commit/f0fa8b6): Fix remotebackend setdomainmetadata return value handling. Fix by Aki Tuomi, closes [ticket 740](https://github.com/PowerDNS/pdns/issues/740).
+- [commit 80e82d6](https://github.com/PowerDNS/pdns/commit/80e82d6): log control listener abort even more explicitly.
+- [commit 7c0cb15](https://github.com/PowerDNS/pdns/commit/7c0cb15), [a718d74](https://github.com/PowerDNS/pdns/commit/a718d74): support automake 1.12
+- [commit 3fe22eb](https://github.com/PowerDNS/pdns/commit/3fe22eb), [6707cb1](https://github.com/PowerDNS/pdns/commit/6707cb1): update autoconf/automake preamble to non-deprecated variant, thanks Morten Stevens
+- [commit 6c4e531](https://github.com/PowerDNS/pdns/commit/6c4e531): disarm dead code that causes gcc crashes on ARM, thanks Morten Stevens.
+- [commit 36855b5](https://github.com/PowerDNS/pdns/commit/36855b5): if we failed to make a new UDP socket, we'd report a confusing error about it.
+- [commit 1b8e5e6](https://github.com/PowerDNS/pdns/commit/1b8e5e6): autoconf support for oracle, thanks Aki Tuomi. Closes [ticket 726](https://github.com/PowerDNS/pdns/issues/726).
+- [commit 8ac0c06](https://github.com/PowerDNS/pdns/commit/8ac0c06): allow setting of some oracle env vars. Patch by Aki Tuomi, closes [ticket 725](https://github.com/PowerDNS/pdns/issues/725).
+- [commit 45e845b](https://github.com/PowerDNS/pdns/commit/45e845b): add example.rb sample script for remotebackend, thanks Aki Tuomi.
+- [commit 950bddd](https://github.com/PowerDNS/pdns/commit/950bddd): add pdnssec generate-zone-key command, thanks Aki. Closes [ticket 711](https://github.com/PowerDNS/pdns/issues/711).
+- [commit 2c03cde](https://github.com/PowerDNS/pdns/commit/2c03cde): Replace select with waitForData in remotebackend. Patch by Aki Tuomi, closes [ticket 715](https://github.com/PowerDNS/pdns/issues/715).
+- [commit 450292c](https://github.com/PowerDNS/pdns/commit/450292c): accept ANY responses during recursive forwarding, thanks Jan-Piet Mens.
+- [commit d9dd76b](https://github.com/PowerDNS/pdns/commit/d9dd76b): actually clean up unix domain sockets too after use.
+- [commit 36758d2](https://github.com/PowerDNS/pdns/commit/36758d2): merge [ticket 476](https://github.com/PowerDNS/pdns/issues/476) by Aki Tuomi, providing default-ksk/zsk-algorithms/size configuration parameters for pdnssec.
+- [commit 2f2b014](https://github.com/PowerDNS/pdns/commit/2f2b014): apply variant of code in [ticket 714](https://github.com/PowerDNS/pdns/issues/714) so we can lauch pipe backend scripts with parameters, plus add experimental code that if pipe-command is a unix domain socket, we use that.
+- [commit 9566683](https://github.com/PowerDNS/pdns/commit/9566683): merge patch from ticket 712 addressing memory leak in remotebackend, thanks Aki.
+- [commit fb6ed6f](https://github.com/PowerDNS/pdns/commit/fb6ed6f): explicitly set domain id during bindbackend superslave domain create, thanks Kees Monshouwer&Aki Tuomi.
+- [commit 69bae20](https://github.com/PowerDNS/pdns/commit/69bae20): use private temp dir when running under systemd, thanks Morten Stevens&Ruben Kerkhof.
+- [commit b26a48a](https://github.com/PowerDNS/pdns/commit/b26a48a): fix rapidjson usage in remotebackend, patch by Aki Tuomi. Closes [ticket 697](https://github.com/PowerDNS/pdns/issues/697).
+- [commit da8e6ae](https://github.com/PowerDNS/pdns/commit/da8e6ae): also answer questions with : in them.
+- [commit ef1c4bf](https://github.com/PowerDNS/pdns/commit/ef1c4bf): also spot trailing dots on CNAME content, thanks Jan-Piet Mens and Ruben d'Arco.
+- [commit fb31631](https://github.com/PowerDNS/pdns/commit/fb31631): only setCloseOnExec on valid sockets
+
+# PowerDNS Recursor version 3.5.1
+Released May 3rd, 2013
+
+This is a stability and bugfix update to 3.5. It contains important fixes that improve operation for certain domains.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-recursor/)
+
+## Changes since 3.5
+
+- We now abort earlier while following endless glue or CNAME chains. Fix in [commit 02d1742](https://github.com/PowerDNS/pdns/commit/02d1742).
+- Some unused code would crash certain gcc versions on ARM. Reported by Morten Stevens, fixed in [commit 5b188e8](https://github.com/PowerDNS/pdns/commit/5b188e8).
+- The 3.5 fix for [ticket 731](https://github.com/PowerDNS/pdns/issues/731) was too strict, causing trouble with at least one domain. Reported by Aki Tuomi, check slightly relaxed in [commit 4134690](https://github.com/PowerDNS/pdns/commit/4134690).
+- Automake/autoconf now use non-deprecated syntax. Reported by Morten Stevens, change in [commit ca17ef2](https://github.com/PowerDNS/pdns/commit/ca17ef2).
+
+# PowerDNS Recursor version 3.5
+Released April 15th, 2013
+
+This is a stability, security and bugfix update to 3.3/3.3.1. It contains important fixes for slightly broken domain names, which your users expect to work anyhow.
+**Note**: Because a semi-sanctioned 3.4-pre was distributed for a long time, and people have come to call that 3.4, we are skipping an actual 3.4 release to avoid confusion.
+
+## Downloads
+- [Official download page](https://www.powerdns.com/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-recursor/)
+
+## Changes between RC5 and the final 3.5 release
+- Winfried Angele reported that restarting a very busy recursor could lead to crashes. Fixed in r3153, closing [ticket 735](https://github.com/PowerDNS/pdns/issues/735).
+
+## Changes between RC4 and RC5
+- Bernd-René Predota of Liberty Global reported that Recursor 3.3 would treat empty non-AA NOERROR responses as authoritative NXDATA responses. This bug turned out to be in 3.5-RC4 too. Fixed in [commit 3146](http://wiki.powerdns.com/projects/trac/changeset/3146), related to [ticket 731](https://github.com/PowerDNS/pdns/issues/731).
+
+## Changes between RC3 (unreleased) and RC4
+- Winfried Angele spotted, even before release, that [commit 3132](http://wiki.powerdns.com/projects/trac/changeset/3132) in RC3 broke outgoing IPv6 queries. We are grateful for his attention to detail! Fixed in [commit 3141](http://wiki.powerdns.com/projects/trac/changeset/3141).
+Changes between RC2 and RC3 (unreleased)
+- Use private temp dir when running under systemd, thanks Morten Stevens and Ruben Kerkhof. Change in [commit 3105](http://wiki.powerdns.com/projects/trac/changeset/3105).
+- NSD mistakenly compresses labels for RP and other types, violating a MUST in RFC 3597. Recursor does not decompress these labels, violating a SHOULD in RFC3597. We now decompress these labels, and reportedly NSD will stop compressing them. Reported by Jan-Piet Mens, fixed in [commit 3109](http://wiki.powerdns.com/projects/trac/changeset/3109).
+- When forwarding to another recursor, we would handle responses to ANY queries incorrectly. Spotted by Jan-Piet Mens, fixed in [commit 3116](http://wiki.powerdns.com/projects/trac/changeset/3116), closes [ticket 704](https://github.com/PowerDNS/pdns/issues/704).
+- Our local-nets definition (used as a default for some settings) now includes the networks from RFC 3927 and RFC 6598. Reported by Maik Zumstrull, fixed in [commit 3122](http://wiki.powerdns.com/projects/trac/changeset/3122).
+- The RC1 change to stop using ANY queries to get A+AAAA for name servers in one go had a 5% performance impact. This impact is corrected in [commit 3132](http://wiki.powerdns.com/projects/trac/changeset/3132). Thanks to Winfried Angele for measuring and reporting this. Closees [ticket 710](https://github.com/PowerDNS/pdns/issues/710).
+- New command 'rec\_control dump-nsspeeds' will dump our NS speeds (latency) cache. Code in [commit 3131](http://wiki.powerdns.com/projects/trac/changeset/3131).
+
+## Changes between RC1 and RC2
+- While Recursor 3.3 was not vulnerable to the specific attack noted in 'Ghost Domain Names: Revoked Yet Still Resolvable' (more information at [A New DNS Exploitation Technique: Ghost Domain Names](http://resources.infosecinstitute.com/ghost-domain-names/)), further investigation showed that a variant of the attack could work. This was fixed in [commit 3085](http://wiki.powerdns.com/projects/trac/changeset/3085). This should also close the slightly bogus [CVE-2012-1193](http://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2012-1193). Closes [ticket 668](https://github.com/PowerDNS/pdns/issues/668).
+- The auth-can-lower-ttl flag was removed, as it did not have any effect in most situations, and thus did not operate as advertised. We now always comply with the related parts of RFC 2181. Change in [commit 3092](http://wiki.powerdns.com/projects/trac/changeset/3092), closing [ticket 88](https://github.com/PowerDNS/pdns/issues/88).
+
+## New features
+- The local zone server now understands wildcards, code in [commit 2062](http://wiki.powerdns.com/projects/trac/changeset/2062).
+- The Lua postresolve and nodata hooks, that had been distributed as a '3.3-hooks' snapshot earlier, have been merged. Code in [commit 2309](http://wiki.powerdns.com/projects/trac/changeset/2309).
+- A new feature, rec\_control trace-regex allows the tracing of lookups for specific names. Code in [commit 3044](http://wiki.powerdns.com/projects/trac/changeset/3044), [commit 3073](http://wiki.powerdns.com/projects/trac/changeset/3073).
+- A new setting, export-etc-hosts-search-suffix, adds a configurable suffix to names imported from /etc/hosts. Code in [commit 2544](http://wiki.powerdns.com/projects/trac/changeset/2544), [commit 2545](http://wiki.powerdns.com/projects/trac/changeset/2545).
+
+## Improvements
+- We now throttle queries that don't work less aggressively, code in [commit 1766](http://wiki.powerdns.com/projects/trac/changeset/1766).
+- Various improvements in tolerance against broken auths, code in [commit 1996](http://wiki.powerdns.com/projects/trac/changeset/1996), [commit 2188](http://wiki.powerdns.com/projects/trac/changeset/2188), [commit 3074](http://wiki.powerdns.com/projects/trac/changeset/3074) (thanks Winfried).
+- Additional processing is now optional, and disabled by default. Presumably this yields a performance improvement. Change in [commit 2542](http://wiki.powerdns.com/projects/trac/changeset/2542).
+- rec\_control reload-lua-script now reports errors. Code in [commit 2627](http://wiki.powerdns.com/projects/trac/changeset/2627), closing [ticket 278](https://github.com/PowerDNS/pdns/issues/278).
+- rec\_control help now lists commands. Code in [commit 2628](http://wiki.powerdns.com/projects/trac/changeset/2628).
+- rec\_control wipe-cache now also wipes the recursor's packet cache. Code in [commit 2880](http://wiki.powerdns.com/projects/trac/changeset/2880) from [ticket 333](https://github.com/PowerDNS/pdns/issues/333).
+- Morten Stevens contributed a systemd file. Import in [commit 2966](http://wiki.powerdns.com/projects/trac/changeset/2966), now part of the recursor tarball.
+- [commit 2990](http://wiki.powerdns.com/projects/trac/changeset/2990) updates the address of D.root-servers.net.
+- Winfried Angele implemented and documented the ipv6-questions metric. Merge in [commit 3034](http://wiki.powerdns.com/projects/trac/changeset/3034), closing [ticket 619](https://github.com/PowerDNS/pdns/issues/619).
+- We no longer use ANY to get A+AAAA for nameservers, because some auth operators have decided to break ANY lookups. As a bonus, we now track v4 and v6 latency separately. Change in [commit 3064](http://wiki.powerdns.com/projects/trac/changeset/3064).
+
+## Bugs fixed
+- Some unaligned memory access was corrected, code in [commit 2060](http://wiki.powerdns.com/projects/trac/changeset/2060), [commit 2122](http://wiki.powerdns.com/projects/trac/changeset/2122), [commit 2123](http://wiki.powerdns.com/projects/trac/changeset/2123), which would cause problems on UltraSPARC.
+- Garbage encountered during reload-acls could cause crashes. Fixed in [commit 2323](http://wiki.powerdns.com/projects/trac/changeset/2323), closing [ticket 330](https://github.com/PowerDNS/pdns/issues/330).
+- The recursor would lose its root hints in a very rare situation. Corrected in [commit 2380](http://wiki.powerdns.com/projects/trac/changeset/2380).
+- We did not always drop supplemental groups while dropping privileges. Reported by David Black of Atlassian, fixed in [commit 2524](http://wiki.powerdns.com/projects/trac/changeset/2524).
+- Cache aging would sometimes get confused when we had a mix of expired and non-expired records in cache. Spotted and fixed by Winfried Angele in [commit 3068](http://wiki.powerdns.com/projects/trac/changeset/3068), closing [ticket 438](https://github.com/PowerDNS/pdns/issues/438).
+- rec\_control reload-acl no longer ignores arguments. Fix in [commit 3037](http://wiki.powerdns.com/projects/trac/changeset/3037), closing [ticket 490](https://github.com/PowerDNS/pdns/issues/490).
+- Since we re-parse our commandline in rec\_control we've been doubling the commands on the commandline, causing weird output. Reported by Winfried Angele. Fixed in [commit 2992](http://wiki.powerdns.com/projects/trac/changeset/2992), closing [ticket 618](https://github.com/PowerDNS/pdns/issues/618). This issue was not present in any officially released versions.
+- [commit 2879](http://wiki.powerdns.com/projects/trac/changeset/2879) drops some spurious stderr logging from Lua scripts, and makes sure 'place' is always valid.
+- We would sometimes refuse to resolve domains with just one nameserver living at the apex. Fixed in [commit 2817](http://wiki.powerdns.com/projects/trac/changeset/2817).
+- We would sometimes stick RRs in the wrong parts of response packets. Fixed in [commit 2625](http://wiki.powerdns.com/projects/trac/changeset/2625).
+- The ACL parser was too liberal, sometimes causing recursors to be very open. Fixed in [commit 2629](http://wiki.powerdns.com/projects/trac/changeset/2629), closing [ticket 331](https://github.com/PowerDNS/pdns/issues/331).
+- rec\_control now honours socket-dir from recursor.conf. Fixed in [commit 2630](http://wiki.powerdns.com/projects/trac/changeset/2630).
+- When traversing CNAME chains, sometimes we would end up with multiple SOAs in the result. Fixed in [commit 2633](http://wiki.powerdns.com/projects/trac/changeset/2633).
+
+# PowerDNS Authoritative Server 3.2
+Released January 17th, 2013
+
+This is a stability and conformity update to 3.1. It mostly makes our DNSSEC implementation more robust, and improves interoperability with various validators. 3.2 has received very extensive testing on a lot of edge cases, verifying output both against common validators and compared against other authoritative servers.
+
+**Warning**: Version 3.2 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. There are also some important changes if you are coming from 3.0 or 3.1. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+## Downloads
+- [Official download page](http://www.powerdns.com/content/downloads.html)
+- [native RHEL5/6 packages from Kees Monshouwer](http://www.monshouwer.eu/download/3rd_party/pdns-server/)
+- [additional third-party builds](http://wiki.powerdns.com/trac#GettingPowerDNSpackages)
+
+In addition to all the changes below, we now auto-build semi-static packages. Relevant changes to make that possible are in [commit 2849](http://wiki.powerdns.com/projects/trac/changeset/2849), [commit 2853](http://wiki.powerdns.com/projects/trac/changeset/2853), 2858, [commit 2859](http://wiki.powerdns.com/projects/trac/changeset/2859), [commit 2860](http://wiki.powerdns.com/projects/trac/changeset/2860).
+
+## Changes between 3.2-RC4 and the final 3.2 release
+- Aki Tuomi contributed a bunch of fixes to our crypto drivers. Code in [commit 3036](http://wiki.powerdns.com/projects/trac/changeset/3036) and [commit 3055](http://wiki.powerdns.com/projects/trac/changeset/3055)/[commit 3057](http://wiki.powerdns.com/projects/trac/changeset/3057).
+- The ksk|zsk argument for pdnssec import-zone-key was required while it should be optional. Fixed in [commit 3051](http://wiki.powerdns.com/projects/trac/changeset/3051).
+
+## Changes between 3.2-RC3 and 3.2-RC4
+- The experimental undocumented bindbackend superslave mode would break the first added domain until a restart. Fixed by Kees Monshouwer in [commit 3013](http://wiki.powerdns.com/projects/trac/changeset/3013).
+- Sander Hoentjen reported an issue with our choice of ports for outgoing TCP connections. Investigating it turned up that we were randomizing TCP connections on purpose while leaving UDP port choice to the kernel, which should be the other way around. Fixed in [commit 3014](http://wiki.powerdns.com/projects/trac/changeset/3014), closing [ticket 643](https://github.com/PowerDNS/pdns/issues/643) and [ticket 644](https://github.com/PowerDNS/pdns/issues/644).
+- Aki Tuomi contributed some autoconf code to use mysql\_config if it is available. Code in [commit 3015](http://wiki.powerdns.com/projects/trac/changeset/3015) and [commit 3019](http://wiki.powerdns.com/projects/trac/changeset/3019), closing [ticket 458](https://github.com/PowerDNS/pdns/issues/458).
+- The MongoDB backend was removed at the author's request, as it does not work with any current libmongo versions. Change in [commit 3017](http://wiki.powerdns.com/projects/trac/changeset/3017).
+- Mark Zealey discovered we were retrieving the ascii powerdns version string for each packet, not just for version string queries. Fixed in [commit 3018](http://wiki.powerdns.com/projects/trac/changeset/3018), closing [ticket 651](https://github.com/PowerDNS/pdns/issues/651).
+- Our new json code would not compile on solaris 9 and 10 due to lack of strcasestr. Juraj Lutter contributed a portable version in [commit 3020](http://wiki.powerdns.com/projects/trac/changeset/3020).
+- Mark Zealey noted that RRs with low TTLs could lower our query-cache-ttl persistently. Fixed in [commit 3023](http://wiki.powerdns.com/projects/trac/changeset/3023), closing [ticket 662](https://github.com/PowerDNS/pdns/issues/662).
+- pdnssec now honours module-dir, patch by Fredrik Danerklint in [commit 3026](http://wiki.powerdns.com/projects/trac/changeset/3026).
+
+## Changes between 3.2-RC2 and 3.2-RC3
+- Michael Scheffler noticed that the lazy-recursion setting had no effect at all. Setting removed in [commit 3003](http://wiki.powerdns.com/projects/trac/changeset/3003).
+- Mark Zealey found that an earlier performance improvement could cause crashes under high load, with lots of IPs configured in local-address and receiver-threads higher than 1. Fixed in [commit 3005](http://wiki.powerdns.com/projects/trac/changeset/3005).
+
+## Changes between 3.2-RC1 and 3.2-RC2
+- The udp-queries metric would only count on the first thread launched, instead of on all threads. Additionally, it was initialised at MAXINT at startup, instead of at 0. Both issues fixed by Kees Monshouwer in [commit 2999](http://wiki.powerdns.com/projects/trac/changeset/2999), closing [ticket 491](https://github.com/PowerDNS/pdns/issues/491) and [ticket 582](https://github.com/PowerDNS/pdns/issues/582).
+- Aki Tuomi contributed zone2json, a great way for programmers to benefit from our zone file parser. Code in [commit 2997](http://wiki.powerdns.com/projects/trac/changeset/2997), closes [ticket 509](https://github.com/PowerDNS/pdns/issues/509).
+- Our DNS TXT parser is not 8-bit safe, but our DNS TXT writer assumes the reader is! Reported by Jan-Piet Mens in [ticket 541](https://github.com/PowerDNS/pdns/issues/541), [commit 2993](http://wiki.powerdns.com/projects/trac/changeset/2993) fixes our writer but not yet our parser.
+- Ruben d'Arco did some improvements to the MyDNS backend, and provided a full test suite for it, that we now run after every commit. Code in [commit 2988](http://wiki.powerdns.com/projects/trac/changeset/2988).
+- Some exceptions from backends would lose their meaning while bubbling up. Fixed by Aki Tuomi in [commit 2985](http://wiki.powerdns.com/projects/trac/changeset/2985), closing [ticket 639](https://github.com/PowerDNS/pdns/issues/639).
+- The packet-cache honours max reply length while matching cached packets against queries, but not EDNS status. This would mean that EDNS-enabled replies with a 512 reply len could be returned on non-EDNS queries. Spotted while investigating a report from Winfried Angele, patched by Ruben d'Arco in [commit 2982](http://wiki.powerdns.com/projects/trac/changeset/2982), closing [ticket 630](https://github.com/PowerDNS/pdns/issues/630).
+- Errors involving creating, deletion or changing permissions on the control socket were unclear. Ruben d'Arco improved this in [commit 2981](http://wiki.powerdns.com/projects/trac/changeset/2981).
+- pipe-timeout was always documented to be in milliseconds, but it turns out it was in seconds! [commit 2971](http://wiki.powerdns.com/projects/trac/changeset/2971) changes them to actually be in ms, and 'increases' the default from 1000 seconds to 2000 milliseconds.
+- Some exceptions would get dropped during inbound AXFR, yielding a log file that says 'transaction started' and nothing after that, making AXFR fail silently. [commit 2976](http://wiki.powerdns.com/projects/trac/changeset/2976) and [commit 2977](http://wiki.powerdns.com/projects/trac/changeset/2977) improve this somewhat.
+- We now error out on empty labels inside of names (www..example.com) instead of generating bogus reply packets. Code in [commit 2972](http://wiki.powerdns.com/projects/trac/changeset/2972), reported by several users.
+- Doing chmod before chown, instead of the other way around, apparently avoids requiring a whole SELinux capability. Reported by Sander Hoentjen, fixed in [commit 2965](http://wiki.powerdns.com/projects/trac/changeset/2965).
+- Christian Hofstaedtler fixed a bug in our Debian init.d script. Code in [commit 2963](http://wiki.powerdns.com/projects/trac/changeset/2963).
+- Superslave errors ('Unable to find backend willing to host ..') now include the NSset found at the master, to aid debugging. Code in [commit 2887](http://wiki.powerdns.com/projects/trac/changeset/2887).
+- [commit 2874](http://wiki.powerdns.com/projects/trac/changeset/2874) in RC1 broke compilation without SQLite3 and made query logging unreliable. Fixed in [commit 2888](http://wiki.powerdns.com/projects/trac/changeset/2888), [commit 2889](http://wiki.powerdns.com/projects/trac/changeset/2889).
+- The dnsreplay tool now processes single packet pcaps. Fix in [commit 2895](http://wiki.powerdns.com/projects/trac/changeset/2895).
+- PowerDNS always derives NSEC/NSEC3 from the actual zone content. To accommodate this, zone2sql now drops NSEC/NSEC3 records, as those should never be in a PowerDNS backend directly ([commit 2915](http://wiki.powerdns.com/projects/trac/changeset/2915)), bindbackend ignores NSEC/NSEC3 while reading zonefiles ([commit 2917](http://wiki.powerdns.com/projects/trac/changeset/2917)) and pdnssec reports NSEC/NSEC3 in the database as an error condition ([commit 2918](http://wiki.powerdns.com/projects/trac/changeset/2918)).
+- The bindbackend now ignores NSEC/NSEC3 records while reading zonefiles. Change in [commit 2917](http://wiki.powerdns.com/projects/trac/changeset/2917).
+- An EXPERIMENTAL feature ('direct-dnskey') for reading ZSKs from the records table/your BIND zonefile was added in [commit 2920](http://wiki.powerdns.com/projects/trac/changeset/2920), [commit 2921](http://wiki.powerdns.com/projects/trac/changeset/2921), [commit 2922](http://wiki.powerdns.com/projects/trac/changeset/2922).
+- While fully optional, PowerDNS supports direct RRSIG queries. Kees Monshouwer improved on our behaviour for those queries in [commit 2927](http://wiki.powerdns.com/projects/trac/changeset/2927).
+- IPv6 glue situations require AAAA records for the receiving end of a delegation in the ADDITIONAL section of a referral. This was supported ('do-ipv6-additional-processing') but not enabled by default. [commit 2929](http://wiki.powerdns.com/projects/trac/changeset/2929) enables it by default.
+- pdnssec check-zone now warns for CNAME-and-other data at names in your zones. Code by Ruben d'Arco in [commit 2930](http://wiki.powerdns.com/projects/trac/changeset/2930).
+- Positive ANY-responses would include a spurious NSEC3. Corrected in [commit 2932](http://wiki.powerdns.com/projects/trac/changeset/2932) and [commit 2933](http://wiki.powerdns.com/projects/trac/changeset/2933), cleaned up by Kees Monshouwer in [commit 2935](http://wiki.powerdns.com/projects/trac/changeset/2935).
+- The ldapbackend now allows overriding the base dn for AXFR subtree search. Fixed in [commit 2934](http://wiki.powerdns.com/projects/trac/changeset/2934), closing [ticket 536](https://github.com/PowerDNS/pdns/issues/536).
+
+Changes below are in 3.2-RC1 and up.
+
+## DNSSEC changes in 3.2
+- Kees Monshouwer did a tremendous amount of work to improve and perfect our DNSSEC implementation, mostly in the NSEC3 area. Code in [commit 2687](http://wiki.powerdns.com/projects/trac/changeset/2687), [commit 2689](http://wiki.powerdns.com/projects/trac/changeset/2689), [commit 2691](http://wiki.powerdns.com/projects/trac/changeset/2691), fixing [ticket 486](https://github.com/PowerDNS/pdns/issues/486), [ticket 537](https://github.com/PowerDNS/pdns/issues/537), [ticket 540](https://github.com/PowerDNS/pdns/issues/540). He also implemented support for Empty Non-Terminals, code in [commit 2721](http://wiki.powerdns.com/projects/trac/changeset/2721), [commit 2732](http://wiki.powerdns.com/projects/trac/changeset/2732), [commit 2745](http://wiki.powerdns.com/projects/trac/changeset/2745), fixing [ticket 127](https://github.com/PowerDNS/pdns/issues/127) and [ticket 558](https://github.com/PowerDNS/pdns/issues/558).
+- Presigned wildcard operation was improved with the help of many parties (see commit message for [commit 2676](http://wiki.powerdns.com/projects/trac/changeset/2676)). Presigned operation was also changed to be more consistent with master/live-signing operation. Code and a full test suite in [commit 2709](http://wiki.powerdns.com/projects/trac/changeset/2709), which also improves TTL behaviour for various situations. Fixes [ticket 460](https://github.com/PowerDNS/pdns/issues/460), [ticket 533](https://github.com/PowerDNS/pdns/issues/533), [ticket 559](https://github.com/PowerDNS/pdns/issues/559).
+- Depending on database & locale settings, names starting with underscore would sometimes cause broken records. [commit 2710](http://wiki.powerdns.com/projects/trac/changeset/2710) contains schema and code changes for the gpgsql and gmysql backends to sort this (no pun intended) definitively, closing [ticket 550](https://github.com/PowerDNS/pdns/issues/550). In addition, a pdnssec test-schema command was added (experimental and incomplete). It can be used to verify underscore sorting and a few other parameters of the database. Code in [commit 2714](http://wiki.powerdns.com/projects/trac/changeset/2714).
+- We now always include an EDNS section in responses to queries that also had an EDNS section. This was thought to improve BIND interoperability, but this turned out to be false. In any case, this change improves standards compliance. Spotted by Mats Dufberg, code in [commit 2649](http://wiki.powerdns.com/projects/trac/changeset/2649).
+- It turns out we were storing Botan keys the wrong way. Botan did not care but Polar did, causing interoperability problems. Fixed in [commit 2720](http://wiki.powerdns.com/projects/trac/changeset/2720), with the kind help of Paul Bakker of PolarSSL. Fixes [ticket 492](https://github.com/PowerDNS/pdns/issues/492) as reported by Florian Obser via Debian.
+- pdnssec add-zone-key now defaults to RSASHA256, like secure-zone already did. Code in [commit 2692](http://wiki.powerdns.com/projects/trac/changeset/2692).
+- pdns\_control purge now also purges DNSSEC-related caches (keys and metadata). Code in [commit 2694](http://wiki.powerdns.com/projects/trac/changeset/2694), by Ruben d'Arco. Fixes [ticket 530](https://github.com/PowerDNS/pdns/issues/530).
+- The signer thread would die in specific situations, leaving you with a non-working but very busy system. Fixed in [commit 2668](http://wiki.powerdns.com/projects/trac/changeset/2668), [commit 2670](http://wiki.powerdns.com/projects/trac/changeset/2670), closing [ticket 517](https://github.com/PowerDNS/pdns/issues/517).
+- pdnssec secure-zone now warns when you just signed a slave zone. Suggested by Mark Scholten, code in [commit 2795](http://wiki.powerdns.com/projects/trac/changeset/2795), closes [ticket 592](https://github.com/PowerDNS/pdns/issues/592).
+- pdnssec check-zone now warns about out-of-zone data. Patch by Kees Monshouwer in [commit 2826](http://wiki.powerdns.com/projects/trac/changeset/2826), closing [ticket 604](https://github.com/PowerDNS/pdns/issues/604).
+- pdnssec now honours --no-config. Patch by Kees Monshouwer in [commit 2810](http://wiki.powerdns.com/projects/trac/changeset/2810).
+- Various fixes for bindbackend presigned operation, mostly by Kees Monshouwer. Code in [commit 2815](http://wiki.powerdns.com/projects/trac/changeset/2815), closing [ticket 600](https://github.com/PowerDNS/pdns/issues/600).
+- Bindbackend could get confused about domain metadata, sometimes even causing hangs. Fixes by Kees Monshouwer in [commit 2819](http://wiki.powerdns.com/projects/trac/changeset/2819) and [commit 2834](http://wiki.powerdns.com/projects/trac/changeset/2834), closing [ticket 600](https://github.com/PowerDNS/pdns/issues/600) and [ticket 603](https://github.com/PowerDNS/pdns/issues/603).
+- SQL queries in gsql backends that reference the domain\_id column have been made explicit about from what table they want this column. This makes it easier to operate custom schemas without changing the queries. Fix by Nicky Gerritsen in [commit 2821](http://wiki.powerdns.com/projects/trac/changeset/2821).
+- In various situations involving CNAMEs and wildcards, and for ANY queries involving CNAMEs, we would sometimes return bogus results. Fixed in [commit 2825](http://wiki.powerdns.com/projects/trac/changeset/2825) by Kees Monshouwer.
+- rectify-zone accidentally set auth=1 on NS records of secure delegations. Reported by George Notaras, fixed by Kees Monshouwer in [commit 2831](http://wiki.powerdns.com/projects/trac/changeset/2831), closing [ticket 605](https://github.com/PowerDNS/pdns/issues/605).
+- The DNSSEC signature cache now actually gets cleaned up, avoiding lasting spikes in memory usage every thursday. Code in [commit 2836](http://wiki.powerdns.com/projects/trac/changeset/2836) and [commit 2843](http://wiki.powerdns.com/projects/trac/changeset/2843), closing [ticket 594](https://github.com/PowerDNS/pdns/issues/594).
+- Signatures used to roll at midnight on thursday. We now roll them one hour after midnight, with inception still set to midnight, to allow for some variations in clock quality on resolvers. Code in [commit 2857](http://wiki.powerdns.com/projects/trac/changeset/2857).
+- Duplicate records (same name/type/content/priority) would sometimes get broken RRSIGs during outgoing AXFR. Fixed in [commit 2856](http://wiki.powerdns.com/projects/trac/changeset/2856).
+- A root zone (name="") with DNSSEC would cause crashes in some situations. Reported by Luuk Hendriks. Fixed in [commit 2867](http://wiki.powerdns.com/projects/trac/changeset/2867), [commit 2868](http://wiki.powerdns.com/projects/trac/changeset/2868), closing [ticket 614](https://github.com/PowerDNS/pdns/issues/614).
+- Direct RRSIG queries for zones with auto-completed SOA records would cause trouble. Reported by Kees Monshouwer and fixed by him in [commit 2869](http://wiki.powerdns.com/projects/trac/changeset/2869).
+- When a name is matched only by a wildcard, but the type in the query is not present, we would be lacking one NSEC(3) record to prove the existence of the wildcard. Fixed by Kees Monshouwer in [commit 2872](http://wiki.powerdns.com/projects/trac/changeset/2872) and [commit 2873](http://wiki.powerdns.com/projects/trac/changeset/2873).
+- Luuk Hendriks spotted that our PolarSSL RSA key generation code was using inferior entropy. This can be important on virtual machines with badly implemented clocks. Fixed in [commit 2876](http://wiki.powerdns.com/projects/trac/changeset/2876), closing [ticket 615](https://github.com/PowerDNS/pdns/issues/615).
+
+## Non-DNSSEC improvements/changes
+- Bindbackend would sometimes crash on startup, due to a sync\_with\_stdio call. This call has been moved to pdns\_server proper to occur before any threads are spawned, avoiding race conditions in this call. Note that this crash has only been observed twice in thousands of regression test runs and has never been reported in the real world. Change in [commit 2882](http://wiki.powerdns.com/projects/trac/changeset/2882).
+- Leen Besselink submitted query logging support for the SQLite3 parts in the bindbackend. Code in [commit 2874](http://wiki.powerdns.com/projects/trac/changeset/2874).
+- Multi-backend operation would sometimes cause garbage domain IDs to be passed to backends. Reported by Kees Monshouwer and fixed by him in [commit 2871](http://wiki.powerdns.com/projects/trac/changeset/2871).
+- Bindbackend would sometimes crash during reloads/rediscovers. The changes in [commit 2837](http://wiki.powerdns.com/projects/trac/changeset/2837) get rid of the crash, at the cost of returning SERVFAIL during reloads. Closes [ticket 564](https://github.com/PowerDNS/pdns/issues/564).
+- Our label decompression code was naive, causing troubles for slaving of very specifically formatted zones. Fix in [ticket 2822](https://github.com/PowerDNS/pdns/issues/2822), closes [ticket 599](https://github.com/PowerDNS/pdns/issues/599).
+- Bindbackend slaves would choke on unknown RR types and do silly things with RP and SRV records. Fixed in [commit 2811](http://wiki.powerdns.com/projects/trac/changeset/2811) and [commit 2812](http://wiki.powerdns.com/projects/trac/changeset/2812).
+- The luabackend can now compile against Lua 5.2. Patch by Fredrik Danerklint in [commit 2794](http://wiki.powerdns.com/projects/trac/changeset/2794), additional luabackend compile fixes in [commit 2854](http://wiki.powerdns.com/projects/trac/changeset/2854).
+- A new backend, the 'Remote backend' [Remote Backend](authoritative/backend-remote.md "Remote Backend") was submitted by Aki Tuomi. It aims to replace the pipebackend with a better protocol and support for more connection methods, including HTTP. Code in [commit 2755](http://wiki.powerdns.com/projects/trac/changeset/2755), [commit 2756](http://wiki.powerdns.com/projects/trac/changeset/2756), [commit 2757](http://wiki.powerdns.com/projects/trac/changeset/2757), [commit 2758](http://wiki.powerdns.com/projects/trac/changeset/2758), [commit 2759](http://wiki.powerdns.com/projects/trac/changeset/2759), [commit 2824](http://wiki.powerdns.com/projects/trac/changeset/2824), closing [ticket 529](https://github.com/PowerDNS/pdns/issues/529), [ticket 597](https://github.com/PowerDNS/pdns/issues/597).
+- The gsqlite (SQLite 2) backend was removed. We were not aware of any users and it was not actually working anyway. Changes in commits [2773](http://wiki.powerdns.com/projects/trac/changeset/2773)-[2777](http://wiki.powerdns.com/projects/trac/changeset/2777), closing [ticket 565](https://github.com/PowerDNS/pdns/issues/565).
+- Various tinydnsbackend improvements: ignore-bogus-records option; TAI offset updated; strip dots on names where suitable; various internal improvements. Code in [commit 2762](http://wiki.powerdns.com/projects/trac/changeset/2762).
+- gpgsql no longer logs the database password in connection errors. Code in [commit 2609](http://wiki.powerdns.com/projects/trac/changeset/2609), [commit 2612](http://wiki.powerdns.com/projects/trac/changeset/2612), closing [ticket 459](https://github.com/PowerDNS/pdns/issues/459).
+- You can now finally specify 0.0.0.0 or :: as local-address/local-ipv6 without getting replies from the wrong address. This much-requested feature is implemented in [commit 2763](http://wiki.powerdns.com/projects/trac/changeset/2763), [commit 2766](http://wiki.powerdns.com/projects/trac/changeset/2766), [commit 2779](http://wiki.powerdns.com/projects/trac/changeset/2779) and [commit 2781](http://wiki.powerdns.com/projects/trac/changeset/2781). Tested on Linux, FreeBSD and Mac OS X.
+- 3.2 can be reliably built with or without Lua. This and many other configure/compile-related fixes in [commit 2610](http://wiki.powerdns.com/projects/trac/changeset/2610), [commit 2611](http://wiki.powerdns.com/projects/trac/changeset/2611) / [ticket 461](https://github.com/PowerDNS/pdns/issues/461), [commit 2666](http://wiki.powerdns.com/projects/trac/changeset/2666), [commit 2671](http://wiki.powerdns.com/projects/trac/changeset/2671), [commit 2672](http://wiki.powerdns.com/projects/trac/changeset/2672) / [ticket 522](https://github.com/PowerDNS/pdns/issues/522), [commit 2673](http://wiki.powerdns.com/projects/trac/changeset/2673) / [ticket 522](https://github.com/PowerDNS/pdns/issues/522), [commit 2696](http://wiki.powerdns.com/projects/trac/changeset/2696) / [ticket 555](https://github.com/PowerDNS/pdns/issues/555), [commit 2697](http://wiki.powerdns.com/projects/trac/changeset/2697) / [ticket 457](https://github.com/PowerDNS/pdns/issues/457), [commit 2698](http://wiki.powerdns.com/projects/trac/changeset/2698), [commit 2708](http://wiki.powerdns.com/projects/trac/changeset/2708), [commit 2742](http://wiki.powerdns.com/projects/trac/changeset/2742) / [ticket 462](https://github.com/PowerDNS/pdns/issues/462)), [commit 2752](http://wiki.powerdns.com/projects/trac/changeset/2752) / [ticket 437](https://github.com/PowerDNS/pdns/issues/437), [commit 2764](http://wiki.powerdns.com/projects/trac/changeset/2764), [commit 2809](http://wiki.powerdns.com/projects/trac/changeset/2809), [commit 2844](http://wiki.powerdns.com/projects/trac/changeset/2844), [commit 2845](http://wiki.powerdns.com/projects/trac/changeset/2845), [commit 2846](http://wiki.powerdns.com/projects/trac/changeset/2846), [commit 2881](http://wiki.powerdns.com/projects/trac/changeset/2881).
+- Juraj Lutter contributed AXFR-SOURCE per zone metadata settings. Code in [commit 2616](http://wiki.powerdns.com/projects/trac/changeset/2616).
+- Initscripts now have exit codes, submitted by Sander Hoentjen. Code in [commit 2728](http://wiki.powerdns.com/projects/trac/changeset/2728). Guardian now returns 0 instead of 1 when receiving SIGTERM, requested by Morten Stevens of Fedora. Code in [commit 2717](http://wiki.powerdns.com/projects/trac/changeset/2717).
+- Mark Zealey submitted various performance improvement patches and suggestions. Accepted as [commit 2729](http://wiki.powerdns.com/projects/trac/changeset/2729) / [ticket 579](https://github.com/PowerDNS/pdns/issues/579), [commit 2730](http://wiki.powerdns.com/projects/trac/changeset/2730) / [ticket 584](https://github.com/PowerDNS/pdns/issues/584)), [commit 2731](http://wiki.powerdns.com/projects/trac/changeset/2731) / [ticket 583](https://github.com/PowerDNS/pdns/issues/583)), [commit 2768](http://wiki.powerdns.com/projects/trac/changeset/2768) / [ticket 578](https://github.com/PowerDNS/pdns/issues/578)). Please see commit messages for more details.
+- pdnssec check-all-zones now reuses database connections, avoiding a socket exhaustion issue in some situations. Code in [commit 2749](http://wiki.powerdns.com/projects/trac/changeset/2749), closes [ticket 519](https://github.com/PowerDNS/pdns/issues/519).
+- Ruben d'Arco submitted various improvements regarding trailing dots. Additional lookups now try harder, pdnssec errors about trailing dots in names, pdnssec warns about trailing dots in names inside content fields, AXFR now strips the dot from SRV hostnames. Code in [commit 2748](http://wiki.powerdns.com/projects/trac/changeset/2748), fixes [ticket 289](https://github.com/PowerDNS/pdns/issues/289).
+- Pre-3.0, backends would get cycled if they threw the right error. 3.2 reinstates this behaviour, as it is more robust. Change in [commit 2734](http://wiki.powerdns.com/projects/trac/changeset/2734) (reverting [commit 2100](http://wiki.powerdns.com/projects/trac/changeset/2100)), fixes [ticket 386](https://github.com/PowerDNS/pdns/issues/386).
+- PowerDNS auth does not use the select() kernel/library call anymore. This means fd-numbers over 1023 (and, in general, more than 1024 sockets, including more than 1024 listening sockets) should now work reliably. Code in [commit 2739](http://wiki.powerdns.com/projects/trac/changeset/2739), [commit 2740](http://wiki.powerdns.com/projects/trac/changeset/2740), fixes [ticket 408](https://github.com/PowerDNS/pdns/issues/408).
+- gmysql users can now specify the 'group' we connect as, using the gmysql-group setting. Submitted by Kees Monshouwer, code in [commit 2770](http://wiki.powerdns.com/projects/trac/changeset/2770), [commit 2771](http://wiki.powerdns.com/projects/trac/changeset/2771), [commit 2778](http://wiki.powerdns.com/projects/trac/changeset/2778), [commit 2780](http://wiki.powerdns.com/projects/trac/changeset/2780), closing [ticket 463](https://github.com/PowerDNS/pdns/issues/463).
+- The Linux-only traceback handler is now optional (use traceback-handler=off to disable it). Suggested by Marc Haber. Change in [commit 2798](http://wiki.powerdns.com/projects/trac/changeset/2798), closes [ticket 497](https://github.com/PowerDNS/pdns/issues/497).
+- We now use IPV6\_V6ONLY to bind IPv6 sockets. This ensures consistent behaviour between different operating systems. Change in [commit 2799](http://wiki.powerdns.com/projects/trac/changeset/2799).
+- MySQL connections are now logged at a higher loglevel, reducing log clutter. Change in [commit 2800](http://wiki.powerdns.com/projects/trac/changeset/2800).
+- We now ship a systemd unit file in contrib/. Added in [commit 2847](http://wiki.powerdns.com/projects/trac/changeset/2847) and [commit 2848](http://wiki.powerdns.com/projects/trac/changeset/2848), submitted by Morten Stevens.
+
+## Assorted bugfixes
+- If a slave domain is removed while a transfer for it is queued, we no longer try the transfer. This also avoids a rare crash in similar circumstances. Code in [commit 2802](http://wiki.powerdns.com/projects/trac/changeset/2802), closes [ticket 596](https://github.com/PowerDNS/pdns/issues/596).
+- When using pdnssec with gsql backends, sometimes an SSqlException would pop up without any useful information. This no longer happens and errors are now in general more meaningful. Fix in [commit 2803](http://wiki.powerdns.com/projects/trac/changeset/2803).
+- zone2sql now uses correct string syntax for PostgreSQL. This is needed for importing with the changed default settings in PostgreSQL 9.2 and up. Code in [commit 2797](http://wiki.powerdns.com/projects/trac/changeset/2797), closes [ticket 471](https://github.com/PowerDNS/pdns/issues/471).
+- We no longer send v6 notifications if v6 is not available. Same for IPv4. Code in [commit 2772](http://wiki.powerdns.com/projects/trac/changeset/2772), fixes [ticket 515](https://github.com/PowerDNS/pdns/issues/515).
+- We would sometimes serve stale data after an incoming AXFR. Reported by Martin Draschl, fixed by Ruben d'Arco in [commit 2699](http://wiki.powerdns.com/projects/trac/changeset/2699), closing [ticket 525](https://github.com/PowerDNS/pdns/issues/525).
+- Duplicate incoming NOTIFYs could cause PowerDNS to try to insert the same domain name into a database twice. Fixed in [commit 2703](http://wiki.powerdns.com/projects/trac/changeset/2703), closing [ticket 453](https://github.com/PowerDNS/pdns/issues/453).
+- pdnssec show-zone now works on a zone that has any number of keys, instead of requiring active keys. Reported by Jeroen Tushuizen of myH2Oservers, code in [commit 2769](http://wiki.powerdns.com/projects/trac/changeset/2769), closes [ticket 586](https://github.com/PowerDNS/pdns/issues/586).
+- pdns-control notify-host now accepts v6 literals. Reported by Christof Meerwald, fixed in [commit 2704](http://wiki.powerdns.com/projects/trac/changeset/2704).
+- The tinydnsbackend no longer chokes on questions longer than 64 bytes. Code in [commit 2622](http://wiki.powerdns.com/projects/trac/changeset/2622).
+- *-all-domains commands in pdnssec now work with Postgres (gpgsql) too. Code in [commit 2645](http://wiki.powerdns.com/projects/trac/changeset/2645), closing [ticket 472](https://github.com/PowerDNS/pdns/issues/472).
+- We would sometimes leave the opcode of an outgoing packet uninitialized. Fixed in [commit 2680](http://wiki.powerdns.com/projects/trac/changeset/2680), closing [ticket 532](https://github.com/PowerDNS/pdns/issues/532).
+- nproxy can now listen on a configurable port. Code in [commit 2684](http://wiki.powerdns.com/projects/trac/changeset/2684), fixes [ticket 534](https://github.com/PowerDNS/pdns/issues/534).
+- Improve mydnsbackend for SOA queries. Code in [commit 2751](http://wiki.powerdns.com/projects/trac/changeset/2751), fixes [ticket 439](https://github.com/PowerDNS/pdns/issues/439), by Ruben d'Arco.
+- Various non-functional fixes that make Valgrind happy (note that Valgrind was right to complain in all of these situations), in [commit 2715](http://wiki.powerdns.com/projects/trac/changeset/2715), [commit 2716](http://wiki.powerdns.com/projects/trac/changeset/2716), [commit 2718](http://wiki.powerdns.com/projects/trac/changeset/2718).
+
+# PowerDNS Authoritative Server 3.1
+Released on the 4th of May 2012
+RC3 released on the 30th of April 2012
+RC2 released on the 14th of April 2012
+RC1 released on the 23th of March 2012
+
+**Warning**: Version 3.1 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. There are also some important changes if you are coming from 3.0. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+Version 3.1 of the PowerDNS Authoritative Server represents the 'coming of age' of our DNSSEC implementation. In addition, 3.1 solves a lot of '.0' issues typically associated with a major new release.
+
+As usual, we are very grateful for the involvement of the PowerDNS community. The uptake of 3.0 was rapid, and many users were very helpful in shaking out the bugs, and willing to test the fixes we provided or, in many cases, provided the fixes themselves.
+
+Of specific note is the giant PowerDNS DNSSEC deployment in Sweden by Atomia and Binero. PowerDNS 3.0 now powers over 150000 DNSSEC domains in Sweden, around 95% of all DNSSEC domains, in a country were most internet service providers actually validate all .SE domains.
+
+Finally, this release has benefited a lot from Peter van Dijk joining us, as he has merged a tremendous amount of patches, cleaned up years of accumulated dust in the code, and massively improved our regression testing into a full blown continuous integration setup with full DNSSEC tests!
+
+Additionally, we would like to thank Ruben d'Arco, Jose Arthur Benetasso Villanova, Marc Haber, Jimmy Bergman, Aki Tuomi and everyone else who helped us out!
+
+## Downloads
+- [Official download page](http://www.powerdns.com/content/downloads.html)
+- [CentOS/RHEL 5/6 RPMs](http://www.monshouwer.eu/download/3rd_party/pdns-server/) kindly provided by Kees Monshouwer.
+- [Additional packages](http://wiki.powerdns.com/trac#GettingPowerDNSpackages) kindly provided by various other people.
+
+## Changes between RC3 and final
+- pdnssec now honours the default-soa-name setting. Reported by Kees Monshouwer, fixed in [commit 2600](http://wiki.powerdns.com/projects/trac/changeset/2600).
+
+## Changes between RC2 and RC3
+- The hidden test-algorithms command for pdnssec now has a little brother 'test-algorithm X'. Code in [commit 2596](http://wiki.powerdns.com/projects/trac/changeset/2596), by Aki Tuomi.
+- PolarSSL upgraded to 1.1.2 due to weak RSA key generation ([commit 2586](http://wiki.powerdns.com/projects/trac/changeset/2586)). If you created RSA keys with RC1 or RC2 using PolarSSL, please replace them! This upgrade introduced a slowdown; speedup patch in [commit 2593](http://wiki.powerdns.com/projects/trac/changeset/2593).
+- It turns out we were using libmysqlclient in a thread-unsafe manner. This issue was reported and painstakingly debugged by Marc Haber. Presumably fixed in [commit 2591](http://wiki.powerdns.com/projects/trac/changeset/2591).
+- Updated a bunch of internal counters to be threadsafe. Code in [commit 2579](http://wiki.powerdns.com/projects/trac/changeset/2579).
+- NSEC(3) bitmaps can now cover RRtypes above 255. Reported by Michael Braunoeder, patch by Aki Tuomi in [commit 2590](http://wiki.powerdns.com/projects/trac/changeset/2590).
+- pdnssec check-zone now reports MBOXFW and URL records (as those are unsupported since 3.0). Reported by Gerwin Krist of Digitalus, patch by Ruben d'Arco. Closes [ticket 446](https://github.com/PowerDNS/pdns/issues/446).
+- The odbcbackend was removed. It only runs on Windows and Windows is unsupported since 3.0. Removal in [commit 2576](http://wiki.powerdns.com/projects/trac/changeset/2576).
+- We used to send the chunk length and the actual chunk in two separate writes (often resulting in two separate TCP packets) during outbound AXFR. This confused MSDNS. We now combine those writes. Code in [commit 2575](http://wiki.powerdns.com/projects/trac/changeset/2575).
+- The bindbackend can now run without SQLite3, as previously intended. Fix in [commit 2574](http://wiki.powerdns.com/projects/trac/changeset/2574).
+- Some high-concurrency master setups would crash under load. Fixed in [commit 2571](http://wiki.powerdns.com/projects/trac/changeset/2571).
+
+# Changes between RC1 and RC2
+- We imported the TinyDNS backend by Ruben d'Arco. Code mostly in [commit 2559](http://wiki.powerdns.com/projects/trac/changeset/2559). See [TinyDNS Backend](authoritative/backend-tinydns.md "TinyDNS Backend").
+- Overriding C(XX)FLAGS is easier now. Problem pointed out by Jose Arthur Benetasso Villanova and others, fix suggested by Sten Spans. Patch in [commit 2533](http://wiki.powerdns.com/projects/trac/changeset/2533).
+- TSIG fixes: skip embedded spaces in keys ([commit 2536](http://wiki.powerdns.com/projects/trac/changeset/2536)), compute signatures correctly (by Ruben d'Arco in [commit 2547](http://wiki.powerdns.com/projects/trac/changeset/2547)),
+- nproxy, dnsscan and dnsdemog did not compile at all. Fixes in [commit 2538](http://wiki.powerdns.com/projects/trac/changeset/2538), [commit 2554](http://wiki.powerdns.com/projects/trac/changeset/2554).
+- We now allow unescaped tabs in TXT records. Fix in [commit 2539](http://wiki.powerdns.com/projects/trac/changeset/2539).
+- SOA records no longer disappear during incoming transfers. Fix by Ruben d'Arco in [commit 2540](http://wiki.powerdns.com/projects/trac/changeset/2540).
+- PowerDNS compiles on OS X (and other platforms that support our auth server but not the recursor) again, fix in [commit 2566](http://wiki.powerdns.com/projects/trac/changeset/2566).
+- Cleanups related to warnings from gcc and valgrind in [commit 2561](http://wiki.powerdns.com/projects/trac/changeset/2561), [commit 2562](http://wiki.powerdns.com/projects/trac/changeset/2562), [commit 2565](http://wiki.powerdns.com/projects/trac/changeset/2565).
+- Solaris compatibility fixes by Ruben d'Arco, Juraj Lutter and others in [commit 2548](http://wiki.powerdns.com/projects/trac/changeset/2548), [commit 2552](http://wiki.powerdns.com/projects/trac/changeset/2552), [commit 2553](http://wiki.powerdns.com/projects/trac/changeset/2553), [commit 2560](http://wiki.powerdns.com/projects/trac/changeset/2560). Fixes for *BSD in [commit 2546](http://wiki.powerdns.com/projects/trac/changeset/2546).
+- pdns\_control help would report 'version' twice, reported by Gerwin, fix in [commit 2549](http://wiki.powerdns.com/projects/trac/changeset/2549).
+
+## DNSSEC related fixes
+- When slaving zones, PowerDNS now automatically detects that a zone is presigned. Code in [commit 2502](http://wiki.powerdns.com/projects/trac/changeset/2502), closing [ticket 369](https://github.com/PowerDNS/pdns/issues/369), [ticket 392](https://github.com/PowerDNS/pdns/issues/392).
+- The bindbackend can now manage its own SQLite3 database to store key data, removing the need to run it with a gsql backend. Code in [commit 2448](http://wiki.powerdns.com/projects/trac/changeset/2448), [commit 2449](http://wiki.powerdns.com/projects/trac/changeset/2449), [commit 2450](http://wiki.powerdns.com/projects/trac/changeset/2450), [commit 2451](http://wiki.powerdns.com/projects/trac/changeset/2451), [commit 2452](http://wiki.powerdns.com/projects/trac/changeset/2452), [commit 2453](http://wiki.powerdns.com/projects/trac/changeset/2453), [commit 2455](http://wiki.powerdns.com/projects/trac/changeset/2455), [commit 2482](http://wiki.powerdns.com/projects/trac/changeset/2482), [commit 2496](http://wiki.powerdns.com/projects/trac/changeset/2496), [commit 2499](http://wiki.powerdns.com/projects/trac/changeset/2499).
+- NSEC/NSEC3 logic for picking 'boundary' names was tricky, and got it wrong in some cases. Fixes in [commit 2289](http://wiki.powerdns.com/projects/trac/changeset/2289), [commit 2429](http://wiki.powerdns.com/projects/trac/changeset/2429), [commit 2435](http://wiki.powerdns.com/projects/trac/changeset/2435) and [commit 2473](http://wiki.powerdns.com/projects/trac/changeset/2473).
+- The subtle differences between 'what records get NSEC', 'what records get NSEC3' and 'what records should get signed' did not translate well to the SQL auth column. We now use 'ordername IS NULL' to map the whole spectrum. Code in [commit 2477](http://wiki.powerdns.com/projects/trac/changeset/2477), [commit 2480](http://wiki.powerdns.com/projects/trac/changeset/2480), [commit 2492](http://wiki.powerdns.com/projects/trac/changeset/2492).
+- Pre-signed AXFR output, although correct, was different from our query responses. Rectified in [commit 2477](http://wiki.powerdns.com/projects/trac/changeset/2477).
+- Spotted & fixed by Jimmy Bergman of Atomia, CNAMEs and RRSIGs could have bad interactions. Fix in [commit 2314](http://wiki.powerdns.com/projects/trac/changeset/2314), further refined in [commit 2318](http://wiki.powerdns.com/projects/trac/changeset/2318). Closes [ticket 411](https://github.com/PowerDNS/pdns/issues/411).
+- Spotted & fixed by Jimmy Bergman of Atomia, we now allow direct RRSIG queries even when do=0.
+- Spotted by Mark Scholten and Marco Davids, we would sometimes generate duplicate (and wrong) RRSIGs when signing an ANY answer because of record jumbling. Fix in [commit 2381](http://wiki.powerdns.com/projects/trac/changeset/2381).
+- Several fixes to handling of DS queries, in [commit 2420](http://wiki.powerdns.com/projects/trac/changeset/2420), [commit 2510](http://wiki.powerdns.com/projects/trac/changeset/2510), [commit 2512](http://wiki.powerdns.com/projects/trac/changeset/2512).
+- We now lowercase the signer name in an RRSIG. This is not mandated by DNSSEC specification but it improves compatibility with some validators. Fix in [commit 2426](http://wiki.powerdns.com/projects/trac/changeset/2426).
+
+## Bug fixes
+- Winfried Angele discovered we would open an additional backend connection per zone in the BIND backend. This only impacted users with multiple simultaneous backends. Fix in [commit 2253](http://wiki.powerdns.com/projects/trac/changeset/2253), closing [ticket 383](https://github.com/PowerDNS/pdns/issues/383).
+- All versions of max-cache-entries setting had confusing behaviour when set to 0. Now clarified to mean that 0 truly means 0, and not 'infinite'. Change in [commit 2328](http://wiki.powerdns.com/projects/trac/changeset/2328).
+- Wildcards in the presence of delegations were broken. Reported by a cast of thousands. Fix & regression test in [commit 2368](http://wiki.powerdns.com/projects/trac/changeset/2368). Closes [ticket 389](https://github.com/PowerDNS/pdns/issues/389).
+- Internal caches used an order of magnitude more memory than expected and some were not purged properly, which hindered real life deployments. Spotted by Winfried Angele and others. Fixed in [commit 2287](http://wiki.powerdns.com/projects/trac/changeset/2287) and [commit 2328](http://wiki.powerdns.com/projects/trac/changeset/2328).
+- Christof Meerwald discovered our .tar file missed a file of the Lua backend. Change in [commit 2257](http://wiki.powerdns.com/projects/trac/changeset/2257).
+- Paul Xek found out that the edns-subnet support did not work for subnets tinier than a /25 or /121. Fix in [commit 2258](http://wiki.powerdns.com/projects/trac/changeset/2258).
+- edns-subnet aware PIPE scripts received bogus remote information on AXFR requests. Fixed in [commit 2284](http://wiki.powerdns.com/projects/trac/changeset/2284).
+- Fix compilation against older versions of MySQL that do not have MYSQL\_OPT\_RECONNECT. [commit 2264](http://wiki.powerdns.com/projects/trac/changeset/2264), closing [ticket 378](https://github.com/PowerDNS/pdns/issues/378).
+- D. Stussy of Snarked.net discovered that PowerDNS could not parse a DNS packet with a trailing blob of unknown length. Fixed in [commit 2267](http://wiki.powerdns.com/projects/trac/changeset/2267).
+- 'pdnssec' did not work for records with NULL ttls. Fixed in [commit 2266](http://wiki.powerdns.com/projects/trac/changeset/2266), closing [ticket 432](https://github.com/PowerDNS/pdns/issues/432).
+- Pipe backend had issues parsing IPv6 records in ABI version 3. Fixed in [commit 2260](http://wiki.powerdns.com/projects/trac/changeset/2260).
+- We truncated the altitude in LOC records! I hope no one got lost. Fix in [commit 2268](http://wiki.powerdns.com/projects/trac/changeset/2268).
+- Xander Soldaat discovered that even if the web server was not configured, we'd still listen on the port. Fix in [commit 2269](http://wiki.powerdns.com/projects/trac/changeset/2269), closes [ticket 402](https://github.com/PowerDNS/pdns/issues/402).
+- The PIPE backend issues frequent fork()s, leading to potential fd leaks if these are not marked as 'close on exec'. Solved in [commit 2273](http://wiki.powerdns.com/projects/trac/changeset/2273), closing [ticket 194](https://github.com/PowerDNS/pdns/issues/194).
+- Robert van der Meulen found that we messed up the interaction between wildcards and CNAMEs. Fixed in [commit 2276](http://wiki.powerdns.com/projects/trac/changeset/2276), which also adds a regression test to prevent this issue from recurring.
+- Fred Wittekind discovered that our notification proxy 'nproxy' no longer built from source. Fixed in [commit 2278](http://wiki.powerdns.com/projects/trac/changeset/2278).
+- Grant Keller found that we were inconsistent with spaces in labels, thus breaking DNS-SD. Fix in [commit 2305](http://wiki.powerdns.com/projects/trac/changeset/2305).
+- Winfried Angele fixed our autoconf script for Lua detection in [commit 2308](http://wiki.powerdns.com/projects/trac/changeset/2308).
+- BIND backend would leak an fd when including a configuration file from named.conf. Spotted by Hannu Ylitalo of Nebula Oy in [commit 2359](http://wiki.powerdns.com/projects/trac/changeset/2359).
+- GSQLite3 backend could crash on a network error at the wrong moment, leading to a restart by the guardian. Fix in [commit 2336](http://wiki.powerdns.com/projects/trac/changeset/2336).
+- './configure --enable-verbose-logging' was broken, fixed in [commit 2312](http://wiki.powerdns.com/projects/trac/changeset/2312).
+- PowerDNS would serve up old SOA data immediately after sending out a notification. Complicated bug documented perfectly in [ticket 427](https://github.com/PowerDNS/pdns/issues/427), which also came with not one but with two different patches to fix the problem. Thanks to Keith Buck. Code in [commit 2408](http://wiki.powerdns.com/projects/trac/changeset/2408).
+- Flag '--start-id' in zone2sql was not functional. Removed for now in [commit 2387](http://wiki.powerdns.com/projects/trac/changeset/2387), closing [ticket 332](https://github.com/PowerDNS/pdns/issues/332).
+- Our distribution tarball did not have the SQL schemas. Fixed in [commit 2459](http://wiki.powerdns.com/projects/trac/changeset/2459) and [commit 2460](http://wiki.powerdns.com/projects/trac/changeset/2460).
+- "Empty" MX records would confuse one of our parsers. Fixed in [commit 2468](http://wiki.powerdns.com/projects/trac/changeset/2468), closing Debian bug 533023.
+- The pdns.conf 'wildcards'-setting did not do anything in 3.0, so it was removed. Change in [commit 2508](http://wiki.powerdns.com/projects/trac/changeset/2508), [commit 2509](http://wiki.powerdns.com/projects/trac/changeset/2509).
+- Additional processing based on records loaded by the BIND backend might fail because of a trailing dot mismatch. Fix in [commit 2398](http://wiki.powerdns.com/projects/trac/changeset/2398).
+
+## New features
+- Per-zone AXFR ACLs, based on the allow-axfr-ips zone metadata item. Code in [commit 2274](http://wiki.powerdns.com/projects/trac/changeset/2274). Also, remove some remains of our previous approach to supporting this in [commit 2326](http://wiki.powerdns.com/projects/trac/changeset/2326).
+- New SOA Serial Tweak mode INCEPTION-EPOCH for when operating as a 'signing slave', contributed by Jimmy Bergman. Code and documentation in [commit 2320](http://wiki.powerdns.com/projects/trac/changeset/2320).
+- Newlines in the 'content' field of backends are now allowed, restoring some DKIM setups to working condition. Update in [commit 2394](http://wiki.powerdns.com/projects/trac/changeset/2394), closing [ticket 395](https://github.com/PowerDNS/pdns/issues/395).
+
+## Improvements
+- Depending on the encoding used, MySQL could take issue with our 'tsigkeys' table which contained very large rows. Trimmed in [commit 2400](http://wiki.powerdns.com/projects/trac/changeset/2400), closing [ticket 410](https://github.com/PowerDNS/pdns/issues/410).
+- Various build/configure-related fixes in [commit 2319](http://wiki.powerdns.com/projects/trac/changeset/2319), [commit 2373](http://wiki.powerdns.com/projects/trac/changeset/2373), [commit 2386](http://wiki.powerdns.com/projects/trac/changeset/2386), closing [ticket 380](https://github.com/PowerDNS/pdns/issues/380), [ticket 405](https://github.com/PowerDNS/pdns/issues/405), [ticket 420](https://github.com/PowerDNS/pdns/issues/420).
+- We now show the SOA serial after zone transfers. Code in [commit 2385](http://wiki.powerdns.com/projects/trac/changeset/2385), closing [ticket 416](https://github.com/PowerDNS/pdns/issues/416).
+- Ruben d'Arco submitted a full rework of our slave-side AXFR TSIG handling, closing [ticket 393](https://github.com/PowerDNS/pdns/issues/393) and [ticket 400](https://github.com/PowerDNS/pdns/issues/400) in the process. Code in [commit 2506](http://wiki.powerdns.com/projects/trac/changeset/2506). Additional improvement in [commit 2513](http://wiki.powerdns.com/projects/trac/changeset/2513).
+- The records.name-column in the gpgsql schema is now constrained to lowercase, as PowerDNS would be unable to find other entries anyway. Fix in [commit 2503](http://wiki.powerdns.com/projects/trac/changeset/2503), closing [ticket 426](https://github.com/PowerDNS/pdns/issues/426).
+- The gsql-backends can now handle huge records, thanks to a patch by Ruben d'Arco. Code in [commit 2476](http://wiki.powerdns.com/projects/trac/changeset/2476), closing [ticket 407](https://github.com/PowerDNS/pdns/issues/407). Additional changes in [commit 2292](http://wiki.powerdns.com/projects/trac/changeset/2292), [commit 2487](http://wiki.powerdns.com/projects/trac/changeset/2487), [commit 2489](http://wiki.powerdns.com/projects/trac/changeset/2489). Closes [ticket 218](https://github.com/PowerDNS/pdns/issues/218), [ticket 316](https://github.com/PowerDNS/pdns/issues/316).
+- Some of PowerDNS' internal classes would work with uninitialized data when repurposed outside of the PowerDNS core logic. Fix in [commit 2469](http://wiki.powerdns.com/projects/trac/changeset/2469),
+- pdnssec now has 'check-all-zones' and 'rectify-all-zones' commands. Submitted by Ruben d'Arco, code in [commit 2467](http://wiki.powerdns.com/projects/trac/changeset/2467).
+- 'restart' in our init.d-script would not start pdns if it was down before. Fixed in [commit 2462](http://wiki.powerdns.com/projects/trac/changeset/2462).
+- 'pdnssec rectify-zone' now honours --verbose and is rather quiet without it. Code in [commit 2443](http://wiki.powerdns.com/projects/trac/changeset/2443).
+- Improved error messages for systems without IPv6. Changes in [commit 2425](http://wiki.powerdns.com/projects/trac/changeset/2425).
+- The packet- and querycache now honour TTLs from backend data. Code in [commit 2414](http://wiki.powerdns.com/projects/trac/changeset/2414).
+- 'pdns\_control help' now shows useful usage information. Code in [commit 2410](http://wiki.powerdns.com/projects/trac/changeset/2410) and [commit 2465](http://wiki.powerdns.com/projects/trac/changeset/2465).
+- Jasper Spaans improved our init.d script for compliance with Debian Squeeze. Patch in [commit 2251](http://wiki.powerdns.com/projects/trac/changeset/2251). Further improvement with 'set -e' to initscript contributed by Marc Haber in [commit 2301](http://wiki.powerdns.com/projects/trac/changeset/2301).
+- Klaus Darilion discovered our configuration file template and --help output explained the various cache TTLs wrongly, and he also added documentation for some missing parameters. [commit 2271](http://wiki.powerdns.com/projects/trac/changeset/2271) and [commit 2272](http://wiki.powerdns.com/projects/trac/changeset/2272).
+- Add support for building against Botan 1.10 (stable) and drop support for 1.9 (development). Changes in [commit 2334](http://wiki.powerdns.com/projects/trac/changeset/2334). This fixes several bugs when building against 1.9.
+- Upgrade internal PolarSSL library to their version 1.1.1. Change in [commit 2389](http://wiki.powerdns.com/projects/trac/changeset/2389) and beyond.
+- Compilation of several backends failed for Boost in non-standard locations. Fixes in [commit 2316](http://wiki.powerdns.com/projects/trac/changeset/2316)..
+- We now do additional processing for SRV records too. Code in [commit 2388](http://wiki.powerdns.com/projects/trac/changeset/2388), closing [ticket 423](https://github.com/PowerDNS/pdns/issues/423) (which also contained the patch). Regression test updates that flow from this in [commit 2390](http://wiki.powerdns.com/projects/trac/changeset/2390).
+- Fix compilation on OSX. [commit 2316](http://wiki.powerdns.com/projects/trac/changeset/2316).
+- Fix pdnssec crash when asked to do DNSSEC without a DNSSEC capable backend. Code in [commit 2369](http://wiki.powerdns.com/projects/trac/changeset/2369).
+- If PowerDNS was not configured to operate as a DNS master, it would still accept 'pdns\_control notify' commands, but then not do it. Spotted by David Gavarret, patch by Jose Arthur Benetasso Villanova in [commit 2379](http://wiki.powerdns.com/projects/trac/changeset/2379).
+- In various places we would only accept UPPERCASE DNS typenames. Fixed in [commit 2370](http://wiki.powerdns.com/projects/trac/changeset/2370), closing [ticket 390](https://github.com/PowerDNS/pdns/issues/390).
+- We would not always drop supplemental groups correctly. Reported by David Black of Atlassian.
+- Our regression tests have been strengthened a lot, and now cover way more features. Commits in [2280](http://wiki.powerdns.com/projects/trac/changeset/2280), [2281](http://wiki.powerdns.com/projects/trac/changeset/2281), [2282](http://wiki.powerdns.com/projects/trac/changeset/2282), [2317](http://wiki.powerdns.com/projects/trac/changeset/2317), [2348](http://wiki.powerdns.com/projects/trac/changeset/2348), [2349](http://wiki.powerdns.com/projects/trac/changeset/2349), [2350](http://wiki.powerdns.com/projects/trac/changeset/2350), [2351](http://wiki.powerdns.com/projects/trac/changeset/2351) and beyond.
+- Update to support the latest draft of DANE/TLSA. Spotted by James Cloos ([commit 2338](http://wiki.powerdns.com/projects/trac/changeset/2338)). Further improvements by Pieter Lexis in [commit 2347](http://wiki.powerdns.com/projects/trac/changeset/2347), [commit 2358](http://wiki.powerdns.com/projects/trac/changeset/2358).
+- Compilation on OpenBSD was eased by patches from Brad Smith, which can be found in [commit 2288](http://wiki.powerdns.com/projects/trac/changeset/2288) and [commit 2291](http://wiki.powerdns.com/projects/trac/changeset/2291), closing [ticket 95](https://github.com/PowerDNS/pdns/issues/95).
+- 'make check' failed on the internal PolarSSL. Spotted by Daniel Briley, fix in [commit 2283](http://wiki.powerdns.com/projects/trac/changeset/2283).
+- The default SQL schemas were expanded to contain far longer content fields. [commit 2292](http://wiki.powerdns.com/projects/trac/changeset/2292), [commit 2293](http://wiki.powerdns.com/projects/trac/changeset/2293).
+- Documentation typos, Jake Spencer ([commit 2304](http://wiki.powerdns.com/projects/trac/changeset/2304)), Jose Arthur Benetasso Villanova ([commit 2337](http://wiki.powerdns.com/projects/trac/changeset/2337)). Code typos in [commit 2324](http://wiki.powerdns.com/projects/trac/changeset/2324) (closes [ticket 296](https://github.com/PowerDNS/pdns/issues/296)).
+- Manpage updates from Debian, provided by Matthijs Möhlmann. Content in [commit 2306](http://wiki.powerdns.com/projects/trac/changeset/2306).
+- pdnssec rectify-zone can now accept multiple zones at the same time. Code in [commit 2383](http://wiki.powerdns.com/projects/trac/changeset/2383).
+- As suggested in [ticket 416](https://github.com/PowerDNS/pdns/issues/416), we now log the SOA serial number after committing an AXFRed zone to the backend. Code in [commit 2385](http://wiki.powerdns.com/projects/trac/changeset/2385).
+- Pick up location of sqlite3 libraries using pkg-config. Implemented using a variation of the patch found in the, now closed, [ticket 380](https://github.com/PowerDNS/pdns/issues/380). Code in [commit 2386](http://wiki.powerdns.com/projects/trac/changeset/2386).
+- Documented 'pdnssec --verbose' flag is now accepted. Code in [commit 2384](http://wiki.powerdns.com/projects/trac/changeset/2384), closing [ticket 404](https://github.com/PowerDNS/pdns/issues/404).
+- 'pdnssec --help' now lists all supported signing algorithms. Suggested by Jose Arthur Benetasso Villanova.
+- PIPE backend example script with edns-subnet support was improved to actually use edns-subnet field. Plus update PIPE backend documentation. Code in [commit 2285](http://wiki.powerdns.com/projects/trac/changeset/2285), more documentation regarding MX and SRV in [commit 2313](http://wiki.powerdns.com/projects/trac/changeset/2313).
+- edns-subnet fields now also output in logfile when available ([commit 2321](http://wiki.powerdns.com/projects/trac/changeset/2321)).
+- When running with virtualized configuration files, we now allow dashes in the configuration name. Suggested by Marc Haber, code in [commit 2295](http://wiki.powerdns.com/projects/trac/changeset/2295). Further fixes by Brielle Bruns in [commit 2327](http://wiki.powerdns.com/projects/trac/changeset/2327).
+- Compilation fixes for GNU/Hurd in [commit 2307](http://wiki.powerdns.com/projects/trac/changeset/2307) via Matthijs Möhlmann.
+- Marc Haber improved our Debian packaging scripts for smoother upgrades. Code in [commit 2315](http://wiki.powerdns.com/projects/trac/changeset/2315).
+- When failing to bind to an IP address, report to which one it failed. [commit 2325](http://wiki.powerdns.com/projects/trac/changeset/2325).
+- Supermaster checks were performed synchronously, leading to the possibilities of slowdowns. Fixed in [commit 2402](http://wiki.powerdns.com/projects/trac/changeset/2402).
+
+## Other changes
+- Removed the deprecated non-generic mysqlbackend, in [commit 2488](http://wiki.powerdns.com/projects/trac/changeset/2488), [commit 2514](http://wiki.powerdns.com/projects/trac/changeset/2514), [commit 2515](http://wiki.powerdns.com/projects/trac/changeset/2515).
+- Removed the deprecated 'pdnsbackend', in [commit 2490](http://wiki.powerdns.com/projects/trac/changeset/2490), [commit 2516](http://wiki.powerdns.com/projects/trac/changeset/2516).
+- Removed GRANT statements from the gpgsql schema, as we can't assume they will work for everyone. Change in [commit 2493](http://wiki.powerdns.com/projects/trac/changeset/2493).
+Tickets closed but not associated with a commit
+- [ticket 125](https://github.com/PowerDNS/pdns/issues/125): "PowerDNS offers wild card info. when it is not queried for."
+- [ticket 219](https://github.com/PowerDNS/pdns/issues/219): "Accept NOTIFY from masters on non-standard port"
+- [ticket 247](https://github.com/PowerDNS/pdns/issues/247): "pdns caching weirdness with recursion-desired flag"
+- [ticket 253](https://github.com/PowerDNS/pdns/issues/253): "bind backend crashes on long comment line in included file"
+- [ticket 271](https://github.com/PowerDNS/pdns/issues/271): "PowerDNS Server responding with out-of-zone authority section in case there is a cname"
+- [ticket 304](https://github.com/PowerDNS/pdns/issues/304): "also-notify option for pdns, also gives also-notify for bindbackend."
+- [ticket 311](https://github.com/PowerDNS/pdns/issues/311): "PowerDNSSEC responding with SERVFAIL upon IN A query for a CNAME"
+- [ticket 325](https://github.com/PowerDNS/pdns/issues/325): "CNAME working strange!"
+- [ticket 376](https://github.com/PowerDNS/pdns/issues/376): "Unable to create long TXT records"
+- [ticket 412](https://github.com/PowerDNS/pdns/issues/412): "--without-lua doesn't disable lua"
+- [ticket 415](https://github.com/PowerDNS/pdns/issues/415): "Signing thread died during AXFR of signed domain"
+- [ticket 422](https://github.com/PowerDNS/pdns/issues/422): "ecdsa256 keys bug"
+
+# Authoritative Server version 2.9.22.6
+**Warning**: The 2.9.22.x series of releases is end-of-life and unsupported. It contains many issues and potential security problems. We urge you to upgrade to a recent version of PowerDNS!
+
+The improvements to the master/slave engine in 2.9.22.5 contained one serious bug that can cause crashes on busy setups. 2.9.22.6 fixes this crash.
+
+# Authoritative Server version 2.9.22.5
+**Warning**: The 2.9.22.x series of releases is end-of-life and unsupported. It contains many issues and potential security problems. We urge you to upgrade to a recent version of PowerDNS!
+
+2.9.22.5 is an interim release for those not yet ready to make the jump to 3.0, but do need a more recent version of the Authoritative Server. It also contains the patch from [PowerDNS Security Advisory 2012-01](security/powerdns-advisory-2012-01.md "PowerDNS Security Advisory 2012-01: PowerDNS Authoritative Server can be caused to generate a traffic loop").
+
+- Improved performance of master/slave engine, especially when hosting tens or hundreds of thousands of slave zones. Code in commits [1657](http://wiki.powerdns.com/projects/trac/changeset/1657), [1658](http://wiki.powerdns.com/projects/trac/changeset/1658), [1661](http://wiki.powerdns.com/projects/trac/changeset/1661) (which also brings multi-master support), [1662](http://wiki.powerdns.com/projects/trac/changeset/1662) (non-standard ports for masters), [1664](http://wiki.powerdns.com/projects/trac/changeset/1664), [1665](http://wiki.powerdns.com/projects/trac/changeset/1665), [1666](http://wiki.powerdns.com/projects/trac/changeset/1666), [1667](http://wiki.powerdns.com/projects/trac/changeset/1667), [1672](http://wiki.powerdns.com/projects/trac/changeset/1672), [1673](http://wiki.powerdns.com/projects/trac/changeset/1673), [2063](http://wiki.powerdns.com/projects/trac/changeset/2063)).
+- Compilation fixes for more modern compilers ([commit 1660](http://wiki.powerdns.com/projects/trac/changeset/1660), [commit 1694](http://wiki.powerdns.com/projects/trac/changeset/1694))
+- Don't crash on communication error with pdns\_control ([commit 2015](http://wiki.powerdns.com/projects/trac/changeset/2015)).
+- Packet cache fixes for UltraSPARC ([commit 1663](http://wiki.powerdns.com/projects/trac/changeset/1663))
+- Fix crashes in the BIND backend ([commit 1693](http://wiki.powerdns.com/projects/trac/changeset/1693), [commit 1692](http://wiki.powerdns.com/projects/trac/changeset/1692))
+
+# PowerDNS Authoritative Server 3.0.1
+**Warning**: The DNSSEC implementation of PowerDNS Authoritative Server 3.0 and 3.0.1 contains many issues regarding CNAMES, wildcards and (in)secure delegations. If you use any of these, and you use DNSSEC you MUST upgrade to 3.1 or beyond!
+
+3.0.1 consists of 3.0, plus the patch from [PowerDNS Security Advisory 2012-01](security/powerdns-advisory-2012-01.md "PowerDNS Security Advisory 2012-01: PowerDNS Authoritative Server can be caused to generate a traffic loop")
+
+# PowerDNS Authoritative Server 3.0
+Released on the 22nd of July 2011
+RC1 released on the 4th of April 2011
+RC2 released on the 19th of April 2011
+RC3 released on the 19th of July 2011
+
+**Warning**: Version 3.0 of the PowerDNS Authoritative Server is a major upgrade if you are coming from 2.9.x. Please refer to the [Upgrade documentation](authoritative/upgrading.md) for important information on correct and stable operation, as well as notes on performance and memory use.
+
+**Warning**: The DNSSEC implementation of PowerDNS Authoritative Server 3.0 and 3.0.1 contains many issues regarding CNAMES, wildcards and (in)secure delegations. If you use any of these, and you use DNSSEC you MUST upgrade to 3.1 or beyond!
+
+Version 3.0 of the PowerDNS Authoritative Server brings a number of important features, as well as over two years of accumulated bug fixing.
+
+The largest news in 3.0 is of course the advent of DNSSEC. Not only does PowerDNS now (finally) support DNSSEC, we think that our support of this important protocol is among the easiest to use available. In addition, all important algorithms are supported.
+
+Complete detail can be found in [Serving authoritative DNSSEC data](authoritative/dnssec.md "Serving authoritative DNSSEC data"). The goal of 'PowerDNSSEC' is to allow existing PowerDNS installations to start serving DNSSEC with as little hassle as possible, while maintaining performance and achieving high levels of security.
+
+Tutorials and examples of how to use DNSSEC in PowerDNS can be found linked from [http://powerdnssec.org](http://powerdnssec.org).
+
+PowerDNS Authoritative Server 3.0 development has been made possible by the financial and moral support of
+
+- [AFNIC, the French registry](http://www.afnic.fr/)
+- [IPCom's RcodeZero Anycast DNS](http://www.ipcom.at/en/dns/rcodezero_anycast/), a subsidiary of NIC.AT, the Austrian registry
+- [SIDN, the Dutch registry](http://www.sidn.nl/)
+- .. (awaiting details) ..
+
+This release has received exceptional levels of community support, and we'd like to thank the following people in addition to those mentioned explicitly below: Peter Koch (DENIC), Olaf Kolkman (NLNetLabs), Wouter Wijngaards (NLNetLabs), Marco Davids (SIDN), Markus Travaille (SIDN), Leen Besselink, Antoin Verschuren (SIDN), Olafur Guðmundsson (IETF), Dan Kaminsky (Recursion Ventures), Roy Arends (Nominet), Miek Gieben (SIDN), Stephane Bortzmeyer (AFNIC), Michael Braunoeder (nic.at), Peter van Dijk, Maik Zumstrull, Jose Arthur Benetasso Villanova (Locaweb), Stefan Schmidt, Roland van Rijswijk (Surfnet), Paul Bakker (Brainspark/Fox-IT), Mathew Hennessy, Johannes Kuehrer (Austrian World4You GmbH), Marc van de Geijn (bHosted.nl), Stefan Arentz and Martin van Hensbergen (Fox-IT), Christof Meerwald, Detlef Peeters, Jack Lloyd, Frank Altpeter, Fredrik Danerklint, Vasiliy G Tolstov, Brielle Bruns, Evan Hunt, Ralf van der Enden, Marc Laros, Serge Belyshev, Christian Hofstaedtler, Charlie Smurthwaite, Nikolaos Milas, ..
+
+## Known issues as of RC3
+- Not all new features are fully documented yet
+
+## Changes between RC3 and final
+- Slight tweak to the pipebackend to ease DNSSEC operations ([commit 2239](http://wiki.powerdns.com/projects/trac/changeset/2239), [commit 2247](http://wiki.powerdns.com/projects/trac/changeset/2247)). Also fix pipebackend support in pdnssec tool ([commit 2244](http://wiki.powerdns.com/projects/trac/changeset/2244)).
+- Upgrade the experimental native Lua backend to the latest version from Fredrik Danerklint ([commit 2240](http://wiki.powerdns.com/projects/trac/changeset/2240)) and include this backend in the .deb packages ([commit 2242](http://wiki.powerdns.com/projects/trac/changeset/2242))
+- Remove IPv6 dependency, it was only possible to run master/slave operations on a server with at least one IPv6 address. Some very old virtualized setups turned out to have no IPv6 at all. Fix in [commit 2246](http://wiki.powerdns.com/projects/trac/changeset/2246).
+
+## Changes between RC2 and RC3
+- PowerDNS Authoritative Server could not be configured to use an IPv6 based resolving backend. Solved in [commit 2191](http://wiki.powerdns.com/projects/trac/changeset/2191).
+- LDAP backend reconfigured the timezone (TZ) setting of the daemon, leading to confusing logfile entries. Fixed by Christian Hofstaedtler in [commit 2913](http://wiki.powerdns.com/projects/trac/changeset/2913), closing [ticket 313](https://github.com/PowerDNS/pdns/issues/313).
+- Non-DNSSEC capable backends could crash on DNSSEC queries. Fixed in [commit 2194](http://wiki.powerdns.com/projects/trac/changeset/2194) and [commit 2196](http://wiki.powerdns.com/projects/trac/changeset/2196) (thanks to Charlie Smurthwaite) closing [ticket 360](https://github.com/PowerDNS/pdns/issues/360).
+- Errors looking up a UID or GID were reported confusingly ('Success'), fixed in [commit 2195](http://wiki.powerdns.com/projects/trac/changeset/2195), closing [ticket 359](https://github.com/PowerDNS/pdns/issues/359).
+- Fix compilation against older MySQL, client libraries ([commit 2198](http://wiki.powerdns.com/projects/trac/changeset/2198), [commit 2199](http://wiki.powerdns.com/projects/trac/changeset/2199), [commit 2204](http://wiki.powerdns.com/projects/trac/changeset/2204)), especially for older RHEL/CentOS. Also addresses the failure to look in lib64 directory for PostgreSQL.
+- Sqlite3 needs write access not just to its database file, but also to the directory it is in. If this wasn't the case, no useful error message was provided. Improvement in [commit 2202](http://wiki.powerdns.com/projects/trac/changeset/2202).
+- Update of MongoDB backend ([commit 2203](http://wiki.powerdns.com/projects/trac/changeset/2203), [commit 2212](http://wiki.powerdns.com/projects/trac/changeset/2212)).
+- 'pdnssec hash-zone-record' emitted an inverted warning about narrow NSEC3 hashes. Spotted by Jan-Piet Mens, fix in [commit 2205](http://wiki.powerdns.com/projects/trac/changeset/2205).
+- PowerDNS can fill out default fields for SOA records, but neglected to do so if the SOA record was matched by an incoming ANY question. Spotted by Marc Laros & others. Fixes [ticket 357](https://github.com/PowerDNS/pdns/issues/357), code in [commit 2206](http://wiki.powerdns.com/projects/trac/changeset/2206).
+- PowerDNS would mistreat binary data in TXT records. Fix in [commit 2207](http://wiki.powerdns.com/projects/trac/changeset/2207). Again spotted by Jan-Piet Mens. Closes [ticket 356](https://github.com/PowerDNS/pdns/issues/356).
+- Add experimental Lua backend by our star contributor Fredrik Danerklint. [commit 2208](http://wiki.powerdns.com/projects/trac/changeset/2208).
+- Christoph Meerwald discovered our RRSIG freshness checking checked more than the intended RRSIG (on the SOA record). Fix in [commit 2209](http://wiki.powerdns.com/projects/trac/changeset/2209).
+- Christoph Meerwald discovered we got confused by TSIG signed EDNS-adorned queries, since we expected the EDNS OPT pseudorecord to be the very last record. Fix in [commit 2214](http://wiki.powerdns.com/projects/trac/changeset/2214).
+- Christoph Meerwald discovered that when using SOA outgoing editing we would sign and THEN edit. This was not productive. Fixed in [commit 2215](http://wiki.powerdns.com/projects/trac/changeset/2215).
+- Add missing-but-documented pdnssec command 'disable-dnssec'. Spotted by Craig Whitmore. Plus fixed misleading --help output. Code in [commit 2216](http://wiki.powerdns.com/projects/trac/changeset/2216).
+- By popular demand, a tweak which makes an overloaded database no longer restart PowerDNS but to drop queries until the database is available again. Code in [commit 2217](http://wiki.powerdns.com/projects/trac/changeset/2217), lightly tested. Enable by setting 'overload-queue-length=100' (for example).
+- By suggestion of Miek Gieben of SIDN, add SOA-EDIT mode 'EPOCH' which sets the SOA serial number to the 'UNIX time'. Implemented in [commit 2218](http://wiki.powerdns.com/projects/trac/changeset/2218).
+- Added some US export control & ECCN to documentation, needed because of DNSSEC content. Update in [commit 2219](http://wiki.powerdns.com/projects/trac/changeset/2219).
+- Fix up various spelling mistakes and badly formatted messages ([commit 2220](http://wiki.powerdns.com/projects/trac/changeset/2220) and [commit 2221](http://wiki.powerdns.com/projects/trac/changeset/2221)) by Maik Zumstrull and 'anonymous'.
+- After a lot of thought, we now handle CNAMEs to names outside our knowledge ('bailiwick') exactly as in BIND 9.8.0, even though our way was standards compliant too. It confused things. Update in [commit 2222](http://wiki.powerdns.com/projects/trac/changeset/2222) and [commit 2224](http://wiki.powerdns.com/projects/trac/changeset/2224).
+- Tweak sqlite3 library location detection for newer Ubuntu versions. Change in [commit 2223](http://wiki.powerdns.com/projects/trac/changeset/2223).
+- DNSSEC SQL schema improvements allowing for the use of constraints and foreign keys in [commit 2225](http://wiki.powerdns.com/projects/trac/changeset/2225), by Gerald Gruenberg, closing [ticket 371](https://github.com/PowerDNS/pdns/issues/371).
+- Add support for EDNS option 'edns-subnet', based on draft-vandergaast-edns-client-subnet ([commit 2226](http://wiki.powerdns.com/projects/trac/changeset/2226), [commit 2228](http://wiki.powerdns.com/projects/trac/changeset/2228), [commit 2229](http://wiki.powerdns.com/projects/trac/changeset/2229), [commit 2230](http://wiki.powerdns.com/projects/trac/changeset/2230), [commit 2231](http://wiki.powerdns.com/projects/trac/changeset/2231), [commit 2233](http://wiki.powerdns.com/projects/trac/changeset/2233)).
+- Zone2sql sent out the wrong 'COMMIT' statement in sqlite mode. In addition, in this mode, zone2sql would not emit statements to update the domains table unless the 'slave' setting was chosen. Code in [commit 2167](http://wiki.powerdns.com/projects/trac/changeset/2167).
+- We dropped the Authoritative Answer flag on an out-of-bailiwick CNAME referral, which was unnecessary. Code in [commit 2170](http://wiki.powerdns.com/projects/trac/changeset/2170).
+- Kees Monshouwer discovered that we failed to detect the location of PostgreSQL on RHEL/CentOS. Fix in [commit 2144](http://wiki.powerdns.com/projects/trac/changeset/2144). In addition, [commit 2162](http://wiki.powerdns.com/projects/trac/changeset/2162) eases detection of MySQL on RHEL/CentOS 64 bits systems.
+- Marc Laros re-reported an old bug in the internally used 'pdns' backend where details of the SOA record were not filled out correctly. Resolved in [commit 2145](http://wiki.powerdns.com/projects/trac/changeset/2145).
+- Jan-Piet Mens found that our TSIG signed SOA zone freshness check was signed incorrectly. Fixed in [commit 2147](http://wiki.powerdns.com/projects/trac/changeset/2147). Improved error messages that helped debug this issue in [commit 2148](http://wiki.powerdns.com/projects/trac/changeset/2148), [commit 2149](http://wiki.powerdns.com/projects/trac/changeset/2149).
+- Jan-Piet Mens helped debug an issue where some servers were "almost always" unable to transfer a TSIG signed zone correctly. Turns out that the TSIG signing code used an internal timestamp and not the remote timestamp. Because of good NTP synchronization this quite often was not a problem. Fix in [commit 2159](http://wiki.powerdns.com/projects/trac/changeset/2159).
+- Thor Spruyt of Telenet discovered that the PowerDNS code would try to emit DNS answers over TCP of over 65535 bytes long, which failed. We now truncate such answers properly. Code in [commit 2150](http://wiki.powerdns.com/projects/trac/changeset/2150).
+- The Slave engine now reuses an existing database connection, removing the need to create a new database connection every minute (and worse, log about it). Code in [commit 2153](http://wiki.powerdns.com/projects/trac/changeset/2153).
+- Fix a potential Year 2106 bug in the TSIG signing code. Because we care ([commit 2156](http://wiki.powerdns.com/projects/trac/changeset/2156)).
+- Added experimental support for the 'DANE' TLSA record which is used to authenticate SSL certificates via DNSSEC. [commit 2161](http://wiki.powerdns.com/projects/trac/changeset/2161).
+- Added experimental support for the MongoDB 'NoSQL' backend, contributed by Fredrik Danerklint in [commit 2162](http://wiki.powerdns.com/projects/trac/changeset/2162).
+
+## Other major new features
+- TSIG for authorizing and authenticating AXFR requests & incoming zone transfers (Code in [2024](http://wiki.powerdns.com/projects/trac/changeset/2024), [2025](http://wiki.powerdns.com/projects/trac/changeset/2025), [2033](http://wiki.powerdns.com/projects/trac/changeset/2033), [2034](http://wiki.powerdns.com/projects/trac/changeset/2034)). This allows for retrieving TSIG protected content, as well as serving it.
+- Per zone also-notify.
+- MyDNS compatible backend, allowing for 'instantaneous' migration from this authoritative nameserver. Code in [commit 1418](http://wiki.powerdns.com/projects/trac/changeset/1418), contributed by Jonathan Oddy.
+- PowerDNS can now slave zones over IPv6 and notify IPv6 remotes of updates. Already. Code in [commit 2009](http://wiki.powerdns.com/projects/trac/changeset/2009) and beyond.
+- Lua based incoming zone editing, allowing masters or signing slaves to add information to the zone they will (re-)serve. Implemented in [commit 2065](http://wiki.powerdns.com/projects/trac/changeset/2065). To enable, use LUA-AXFR-SCRIPT zone metadata setting.
+- Native Oracle backend with full DNSSEC support. Contributed by Maik Zumstrull, then at the Steinbuch Centre for Computing at the Karlsruhe Institute of Technology.
+- "Also-notify" support, implemented by Aki Tuomi in [commit 1400](http://wiki.powerdns.com/projects/trac/changeset/1400). Support for Generic SQL backends and for the BIND backend. Further code in [commit 1360](http://wiki.powerdns.com/projects/trac/changeset/1360).
+- Support for binding to thousands of IP addresses, code in [commit 1443](http://wiki.powerdns.com/projects/trac/changeset/1443).
+- Generic MySQL backend now supports stored procedures. Implemented in [commit 2084](http://wiki.powerdns.com/projects/trac/changeset/2084), closing [ticket 231](https://github.com/PowerDNS/pdns/issues/231).
+- Generic ODBC backend compiles again, and is reported to work for some users that need it. Code contributed in [ticket 309](https://github.com/PowerDNS/pdns/issues/309), author unknown.
+- Massively parallel slaving infrastructure, able to check the freshness of thousands of remote zones per second, plus perform many incoming zone transfers simultaneously. Sponsored by Tyler Hall, code in [1449](http://wiki.powerdns.com/projects/trac/changeset/1449), [1500](http://wiki.powerdns.com/projects/trac/changeset/1500), [1859](http://wiki.powerdns.com/projects/trac/changeset/1859)
+- Core DNS logic replaced completely to deal with the brave new world of DNSSEC.
+
+## Bugs fixed
+- sqlite2 and sqlite3 backends used MySQL-style escaping, leading to SQL errors in some cases. Discovered by Sten Spans. Fixed in [commit 1342](http://wiki.powerdns.com/projects/trac/changeset/1342).
+- Internal webserver no longer prints '1e2%'. Bug rediscovered by Jeff Sipek. Fixed in [commit 1342](http://wiki.powerdns.com/projects/trac/changeset/1342).
+- PowerDNS would refuse to serve domain names with spaces in them, or otherwise non-printable characters. Addressed in [commit 2081](http://wiki.powerdns.com/projects/trac/changeset/2081).
+- PowerDNS can now serve escaped labels, as described by RFC 4343. Data should be present in backends in that escaped form. Code in [commit 2089](http://wiki.powerdns.com/projects/trac/changeset/2089).
+- In some cases, we would include duplicate CNAMEs. In addition, we would hand out a full root-referral when not configured to in some cases (ticket [223](https://github.com/PowerDNS/pdns/issues/223)). Discovered by Andreas Jakum, fixed in [commit 1344](http://wiki.powerdns.com/projects/trac/changeset/1344).
+- Shane Kerr discovered we would corrupt DNS transaction IDs from the packet cache on big endian systems. Fix in [commit 1346](http://wiki.powerdns.com/projects/trac/changeset/1346), closing [ticket 222](https://github.com/PowerDNS/pdns/issues/222).
+- PowerDNS did not use RFC 1982 serial arithmetic, leading to a SOA serial number of 1 to be regarded as older than 4400000000, when in fact it is 'newer'. Issue (re-)discovered by Jan-Piet Mens.
+- BIND backend got confused of a zone's file name changed after a configuration reload. Fix in [commit 1347](http://wiki.powerdns.com/projects/trac/changeset/1347), closing [ticket 228](https://github.com/PowerDNS/pdns/issues/228).
+- When restarted by the Guardian, PowerDNS will perform a full multi-threaded cache cleanup, which took a long time and could crash. Fix in [commit 1364](http://wiki.powerdns.com/projects/trac/changeset/1364).
+- Under artificial circumstances, PowerDNS would never clean its packet cache. Found by Marcus Goller, fix in [commit 1399](http://wiki.powerdns.com/projects/trac/changeset/1399) and [commit 1408](http://wiki.powerdns.com/projects/trac/changeset/1408). This update also retunes the cleanup frequency.
+- Packetcache would cache things it should not have been caching. Fixes in commits [1407](http://wiki.powerdns.com/projects/trac/changeset/1407), [1488](http://wiki.powerdns.com/projects/trac/changeset/1488), [1869](http://wiki.powerdns.com/projects/trac/changeset/1869), [1880](http://wiki.powerdns.com/projects/trac/changeset/1880)
+- When processing incoming notifications, the BIND backend was case-sensitive, and would disregard notifications in the wrong case. Discovered by 'Dolphin', fix in [commit 1420](http://wiki.powerdns.com/projects/trac/changeset/1420).
+- The init.d script did not mention the 'reload' command. Code in [commit 1463](http://wiki.powerdns.com/projects/trac/changeset/1463), closes [ticket 233](https://github.com/PowerDNS/pdns/issues/233).
+- Generic SQL Backends would sometimes emit obscure error messages. Fix in [commit 2049](http://wiki.powerdns.com/projects/trac/changeset/2049).
+- PowerDNS would be confused by embedded NULs in domain names, and would also mess up the escaping of some characters. Fix in [commit 1468](http://wiki.powerdns.com/projects/trac/changeset/1468), [commit 1469](http://wiki.powerdns.com/projects/trac/changeset/1469), [commit 1478](http://wiki.powerdns.com/projects/trac/changeset/1478), [commit 1480](http://wiki.powerdns.com/projects/trac/changeset/1480),
+- SOA queries for the name of a delegation point were not referred. Fix in [commit 1466](http://wiki.powerdns.com/projects/trac/changeset/1466), closing [ticket 224](https://github.com/PowerDNS/pdns/issues/224). In addition, queries for AAAA for a CNAMEd record pointing to a name with no AAAA would deliver a direct SOA, without the CNAME in between. Fix in [commit 1542](http://wiki.powerdns.com/projects/trac/changeset/1542), [commit 1607](http://wiki.powerdns.com/projects/trac/changeset/1607). Also, wildcard CNAMEs pointing to a record without the type requested suffered from the same issue, fix in [commit 1543](http://wiki.powerdns.com/projects/trac/changeset/1543).
+- On processing an incoming AXFR, once an MX or SRV record had been seen, all future fields got a 'priority' entry as well. This had no operational impact, but looked messy. Fixed in [commit 1437](http://wiki.powerdns.com/projects/trac/changeset/1437).
+- Aki Tuomi discovered that the BIND zone file parser would misrepresent 'something IN MX 15 @'. Fix in [commit 1621](http://wiki.powerdns.com/projects/trac/changeset/1621).
+- Marco Davids discovered the BIND zone file parser would trip over really long lines. Fix in [commit 1624](http://wiki.powerdns.com/projects/trac/changeset/1624), [commit 1625](http://wiki.powerdns.com/projects/trac/changeset/1625).
+- Thomas Mieslinger discovered that our webserver would only be started after dropping privileges, which could cause problems. Fix in [commit 1629](http://wiki.powerdns.com/projects/trac/changeset/1629).
+- Zone2sql did quite often not do exactly what was required, which users fixed by editing the SQL output. Revamped in [commit 2032](http://wiki.powerdns.com/projects/trac/changeset/2032).
+- An Ubuntu user discovered in Launchpad bug 600479 that restarting database threads cost a lot of memory. Normally this is rare, except in case of problems. Addressed in [commit 1676](http://wiki.powerdns.com/projects/trac/changeset/1676).
+- BIND backend could crash under (very) high load with very large numbers of zones (hundreds of thousands). Fixed in [commit 1690](http://wiki.powerdns.com/projects/trac/changeset/1690).
+- Miek Gieben and Marco Davids spotted that PowerDNS would answer the version.bind query in the IN class too. Bug reported via twitter! Fix in [commit 1709](http://wiki.powerdns.com/projects/trac/changeset/1709).
+- Marcus Lauer and the OpenDNSSEC project discovered that outgoing notifications did not carry the 'aa' flag. Fixed in [commit 1746](http://wiki.powerdns.com/projects/trac/changeset/1746).
+- Debugging PowerDNS, or backgrounding it, could cause crashes. Fixed by Anders Kaseorg in [commit 1747](http://wiki.powerdns.com/projects/trac/changeset/1747).
+- Fixed a bug that could cause crashes on launching thousands of backend connections. Never observed to occur, but who knows. Fix in [commit 1792](http://wiki.powerdns.com/projects/trac/changeset/1792).
+- Under some circumstances, large answers could be truncated in mid-record. While technically legal, this upset a number of resolver implementations (including the PowerDNS Recursor!). Fixed in [commit 1830](http://wiki.powerdns.com/projects/trac/changeset/1830), re-closes [ticket 200](https://github.com/PowerDNS/pdns/issues/200).
+- Jan Piet Mens and Florian Weimer discovered we had problems dealing with escaped labels and escaped TXT fields. Fixed in [commit 2000](http://wiki.powerdns.com/projects/trac/changeset/2000).
+- After 2.2 billion queries, statistics would wrap oddly. Fix in [commit 2019](http://wiki.powerdns.com/projects/trac/changeset/2019), closing [ticket 327](https://github.com/PowerDNS/pdns/issues/327).
+
+## Improvements
+- Long TXT records are now split into 255-byte components automatically. Implemented in [commit 1340](http://wiki.powerdns.com/projects/trac/changeset/1340), reported by Darren Gamble in [ticket 188](https://github.com/PowerDNS/pdns/issues/188).
+- When receiving large numbers of notifications, PowerDNS would check these synchronously, leading to a slowdown for other services. Fixed in [commit 2058](http://wiki.powerdns.com/projects/trac/changeset/2058), problem diagnosed by Richard Poole of Heart Internet.
+- Fixed compilation on newer compilers and newer versions of Boost. Changes in [1345](http://wiki.powerdns.com/projects/trac/changeset/1345) (closes [ticket 227](https://github.com/PowerDNS/pdns/issues/227)), [1391](http://wiki.powerdns.com/projects/trac/changeset/1391), [1394](http://wiki.powerdns.com/projects/trac/changeset/1394), [1425](http://wiki.powerdns.com/projects/trac/changeset/1425), [1427](http://wiki.powerdns.com/projects/trac/changeset/1427), [1428](http://wiki.powerdns.com/projects/trac/changeset/1428), [1429](http://wiki.powerdns.com/projects/trac/changeset/1429), [1440](http://wiki.powerdns.com/projects/trac/changeset/1440), [1653](http://wiki.powerdns.com/projects/trac/changeset/1653), thanks to Ruben Kerkhof and others.
+- Moved Generic PostgreSQL backend over to the newer E'' style escapes. [commit 2094](http://wiki.powerdns.com/projects/trac/changeset/2094).
+- Compilation fixes for Mac OS X 10.5.7 in [commit 1389](http://wiki.powerdns.com/projects/trac/changeset/1389), thanks to Tobias Markmann.
+- We can now bind to scoped IPv6 addresses, lack spotted by Darren Gamble. Part of the fix is in [commit 2018](http://wiki.powerdns.com/projects/trac/changeset/2018).
+- Built-in query cache can now also cache queries which lead to multiple answers. Code in [commit 2069](http://wiki.powerdns.com/projects/trac/changeset/2069).
+- Prodded on by Jan Piet Mens, we now support 'unknown types' (which look like TYPE65534).
+- Add 'slave-renotify' to retransmit notifies for slaved zones, which is helpful when acting as a 'signing slave' for a hidden master. Code in [commit 1950](http://wiki.powerdns.com/projects/trac/changeset/1950).
+- No longer let zone2sql and zone2ldap import BIND 'hint' zones. [commit 1998](http://wiki.powerdns.com/projects/trac/changeset/1998).
+- Allow for timestamps to explicitly be specified in (s)econds. Code in [commit 1398](http://wiki.powerdns.com/projects/trac/changeset/1398), closing [ticket 250](https://github.com/PowerDNS/pdns/issues/250).
+- Zones with URL and MBOXFW records can be transferred over AXFR, code in [commit 1464](http://wiki.powerdns.com/projects/trac/changeset/1464).
+- Maik Zumstrull cleaned up the BIND Backend makefile, plus taught our init.d script to read /etc/default/pdns. Code in [commit 1601](http://wiki.powerdns.com/projects/trac/changeset/1601), [commit 1602](http://wiki.powerdns.com/projects/trac/changeset/1602).
+- Generic SQL backends now support multiple masters in the domains table. Code in [commit 1857](http://wiki.powerdns.com/projects/trac/changeset/1857). Additionally, masters can also have :port numbers. Code in [commit 1858](http://wiki.powerdns.com/projects/trac/changeset/1858).
+
+# Recursor version 3.3.1
+**Warning**:Unreleased
+
+Version 3.3.1 contains a small number of important fixes, adds some memory usage statistics, but no new features.
+
+- Discovered by John J and Robin J, the PowerDNS Recursor did not process packets that were truncated in mid-record, and also did not act on the 'truncated' (TC) flag in that case. This broke a very small number of domains, most of them served by very old versions of the PowerDNS Authoritative Server. Fix in [commit 1740](http://wiki.powerdns.com/projects/trac/changeset/1740).
+- PowerDNS emitted a harmless, but irritating, error message on receiving certain very short packets. Discovered by Winfried A and John J, fix in [commit 1729](http://wiki.powerdns.com/projects/trac/changeset/1729).
+- PowerDNS could crash on startup if configured to provide service on malformed IPv6 addresses on FreeBSD, or in case when the FreeBSD kernel was compiled without any form of IPv6 support. Debugged by Bryan Seitz, fix in [commit 1727](http://wiki.powerdns.com/projects/trac/changeset/1727).
+- Add max-mthread-stack metric to debug rare crashes. Could be used to save memory on constrained systems. Implemented in [commit 1745](http://wiki.powerdns.com/projects/trac/changeset/1745).
+- Add cache-bytes and packetcache-bytes metrics to measure our 'pre-malloc' memory utilization. Implemented in [commit 1750](http://wiki.powerdns.com/projects/trac/changeset/1750).
+
+# Recursor version 3.3
+Released on the 22nd of September 2010.
+
+**Warning**: Version 3.3 fixes a number of small but persistent issues, rounds off our IPv6 %link-level support and adds an important feature for many users of the Lua scripts.
+
+In addition, scalability on Solaris 10 is improved.
+
+## Bug fixes
+- 'dist-recursor' script was not compatible with pure POSIX /bin/sh, discovered by Simon Kirby. Fix in [commit 1545](http://wiki.powerdns.com/projects/trac/changeset/1545).
+- Simon Bedford, Brad Dameron and Laurient Papier discovered relatively high TCP/IP loads could cause TCP/IP service to shut down over time. Addressed in commits [1546](http://wiki.powerdns.com/projects/trac/changeset/1546), [1640](http://wiki.powerdns.com/projects/trac/changeset/1640), [1652](http://wiki.powerdns.com/projects/trac/changeset/1652), [1685](http://wiki.powerdns.com/projects/trac/changeset/1685), [1698](http://wiki.powerdns.com/projects/trac/changeset/1698). Additional information provided by Zwane Mwaikambo, Nicholas Miell and Jeff Roberson. Testing by Christian Hofstaedtler and Michael Renner.
+- The PowerDNS Recursor could not read the 'root zone' (this is something else than the root hints) because of an unquoted TXT record. This has now been addressed, allowing operators to hardcode the root zone. This can improve security if the root zone used is kept up to date. Change in [commit 1547](http://wiki.powerdns.com/projects/trac/changeset/1547).
+- A return of an old bug, when a domain gets new nameservers, but the old nameservers continue to contain a copy of the domain, PowerDNS could get 'stuck' with the old servers. Fixed in [commit 1548](http://wiki.powerdns.com/projects/trac/changeset/1548).
+- Discovered & reported by Alexander Gall of SWITCH, the Recursor used to try to resolve 'AXFR' records over UDP. Fix in [commit 1619](http://wiki.powerdns.com/projects/trac/changeset/1619).
+- The Recursor embedded authoritative server messed up parsing a record like '@ IN MX 15 @'. Spotted by Aki Tuomi, fix in [commit 1621](http://wiki.powerdns.com/projects/trac/changeset/1621).
+- The Recursor embedded authoritative server messed up parsing really really long lines. Spotted by Marco Davids, fix in [commit 1624](http://wiki.powerdns.com/projects/trac/changeset/1624), [commit 1625](http://wiki.powerdns.com/projects/trac/changeset/1625).
+- Packet cache was not DNS class correct. Spotted by "Robin", fix in [commit 1688](http://wiki.powerdns.com/projects/trac/changeset/1688).
+- The packet cache would cache some NXDOMAINs for too long. Solving this bug exposed an underlying oddity where the initial NXDOMAIN response had an overly long (untruncated) TTL, whereas all the next ones would be ok. Solved in [commit 1679](http://wiki.powerdns.com/projects/trac/changeset/1679), closing [ticket 281](https://github.com/PowerDNS/pdns/issues/281). Especially important for RBL operators. Fixed after some nagging by Alex Broens (thanks).
+
+## Improvements
+- The priming of the root now uses more IPv6 addresses. Change in [commit 1550](http://wiki.powerdns.com/projects/trac/changeset/1550), closes [ticket 287](https://github.com/PowerDNS/pdns/issues/287). Also, the IPv6 address of I.ROOT-SERVERS.NET was added in [commit 1650](http://wiki.powerdns.com/projects/trac/changeset/1650).
+- The `rec_control dump-cache` command now also dumps the 'negative query' cache. Code in [commit 1713](http://wiki.powerdns.com/projects/trac/changeset/1713).
+- PowerDNS Recursor can now bind to fe80 IPv6 space with '%eth0' link selection. Suggested by Darren Gamble, implemented with help from Niels Bakker. Change in [commit 1620](http://wiki.powerdns.com/projects/trac/changeset/1620).
+- Solaris on x86 has a long standing bug in port\_getn(), which we now work around. Spotted by 'Dirk' and 'AS'. Solution suggested by the Apache runtime library, update in [commit 1622](http://wiki.powerdns.com/projects/trac/changeset/1622).
+- New runtime statistic: 'tcp-clients' which lists the number of currently active TCP/IP clients. Code in [commit 1623](http://wiki.powerdns.com/projects/trac/changeset/1623).
+- Deal better with UltraDNS style CNAME redirects containing SOA records. Spotted by Andy Fletcher from UKDedicated in [ticket 303](https://github.com/PowerDNS/pdns/issues/303), fix in [commit 1628](http://wiki.powerdns.com/projects/trac/changeset/1628).
+- The packet cache, which has 'ready to use' packets containing answers, now artificially ages the ready to use packets. Code in [commit 1630](http://wiki.powerdns.com/projects/trac/changeset/1630).
+- Lua scripts can now indicate that certain queries will have 'variable' answers, which means that the packet cache will not touch these answers. This is great for overriding some domains for some users, but not all of them. Use setvariable() in Lua to indicate such domains. Code in [commit 1636](http://wiki.powerdns.com/projects/trac/changeset/1636).
+- Add query statistic called 'dont-outqueries', plus add IPv6 address :: and IPv4 address 0.0.0.0 to the default "dont-query" set, preventing the Recursor from talking to itself. Code in [commit 1637](http://wiki.powerdns.com/projects/trac/changeset/1637).
+- Work around a gcc 4.1 bug, still in wide use on common platforms. Code in [commit 1653](http://wiki.powerdns.com/projects/trac/changeset/1653).
+- Add 'ARCHFLAGS' to PowerDNS Recursor Makefile, easing 64 bit compilation on mainly 32 bit platforms (and vice versa).
+- Under rare circumstances, querying the Recursor for statistics under very high load could lead to a crash (although this has never been observed). Bad code removed & good code unified in [commit 1675](http://wiki.powerdns.com/projects/trac/changeset/1675).
+- Spotted by Jeff Sipek, the rec\_control manpage did not list the new get-all command. [commit 1677](http://wiki.powerdns.com/projects/trac/changeset/1677).
+- On some platforms, it may be better to have PowerDNS itself distribute queries over threads (instead of leaving it up to the kernel). This experimental feature can be enabled with the 'pdns-distributes-queries' setting. Code in [commit 1678](http://wiki.powerdns.com/projects/trac/changeset/1678) and beyond. Speeds up Solaris measurably.
+- Cache cleaning code was cleaned up, unified and expanded to cover the 'negative cache', which used to be cleaned rather bluntly. Code in [commit 1702](http://wiki.powerdns.com/projects/trac/changeset/1702), further tweaks in [commit 1712](http://wiki.powerdns.com/projects/trac/changeset/1712), spotted by Darren Gamble, Imre Gergely and Christian Kovacic.
+
+## Changes between RC1, RC2 and RC3.
+- RC2: Fixed linking on RHEL5/CentOS5, which both ship with a gcc compiler that claims to support atomic operations, but doesn't. Code in [commit 1714](http://wiki.powerdns.com/projects/trac/changeset/1714). Spotted by 'Bas' and Imre Gergely.
+- RC2: Negative query cache was configured to grow too large, and was not cleaned efficiently. Code in [commit 1712](http://wiki.powerdns.com/projects/trac/changeset/1712), spotted by Imre Gergely.
+- RC3: Root failed to be renewed automatically, relied on fallback to make this happen. Code in [commit 1716](http://wiki.powerdns.com/projects/trac/changeset/1716), spotted by Detlef Peeters.
+
+# Recursor version 3.2
+Released on the 7th of March 2010.
+
+**Warning**: Lua scripts from version 3.1.7.* are fully compatible with version 3.2. However, scripts written for development snapshot releases, are NOT. Please see [Scripting](recursor/scripting.md "Scripting") for details!
+
+The 3.2 release is the first major release of the PowerDNS Recursor in a long time. Partly this is because 3.1.7.* functioned very well, and delivered satisfying performance, partly this is because in order to really move forward, some heavy lifting had to be done.
+
+As always, we are grateful for the large PowerDNS community that is actively involved in improving the quality of our software, be it by submitting patches, by testing development versions of our software or helping debug interesting issues. We specifically want to thank Stefan Schmidt and Florian Weimer, who both over the years have helped tremendously in keeping PowerDNS fast, stable and secure.
+
+This version of the PowerDNS Recursor contains a rather novel form of lock-free multithreading, a situation that comes close to the old '--fork' trick, but allows the Recursor to fully utilize multiple CPUs, while delivering unified statistics and operational control.
+
+In effect, this delivers the best of both worlds: near linear scaling, with almost no administrative overhead.
+
+Compared to 'regular multithreading', whereby threads cooperate more closely, more memory is used, since each thread maintains its own DNS cache. However, given the economics, and the relatively limited total amount of memory needed for high performance, this price is well worth it.
+
+In practical numbers, over 40,000 queries/second sustained performance has now been measured by a third party, with a 100.0% packet response rate. This means that the needs of around 400,000 residential connections can now be met by a single commodity server.
+
+In addition to the above, the PowerDNS Recursor is now providing resolver service for many more Internet users than ever before. This has brought with it 24/7 Service Level Agreements, and 24/7 operational monitoring by networking personnel at some of the largest telecommunications companies in the world.
+
+In order to facilitate such operation, more statistics are now provided that allow the visual verification of proper PowerDNS Recursor operation. As an example of this there are now graphs that plot how many queries were dropped by the operating system because of a CPU overload, plus statistics that can be monitored to determine if the PowerDNS deployment is under a spoofing attack.
+All in all, this is a large and important PowerDNS Release, paving the way for further innovation.
+
+**Note**: This release removes support for the 'fork' multi-processor option. In addition, the default is now to spawn two threads. This has been done in such a way that total memory usage will remain identical, so each thread will use half of the allocated maximum number of cache entries.
+
+## Changes between RC2 and -release
+- 'Make install' when an existing configuration file contained a 'fork' statement has been fixed. Spotted by Darren Gamble, code in [commit 1534](http://wiki.powerdns.com/projects/trac/changeset/1534).
+- Reloading a non-existent allow-from-file caused the control thread to stop working. Spotted by Imre Gergely, code in [commit 1532](http://wiki.powerdns.com/projects/trac/changeset/1532).
+- Parser got confused by reading en empty line in auth-forward-zones. Spotted by Imre Gergely, code in [commit 1533](http://wiki.powerdns.com/projects/trac/changeset/1533).
+- David Gavarret discovered undocumented and not-working settings to set the owner, group and access modes of the control socket. Code by Aki Tuomi and documentation in [commit 1535](http://wiki.powerdns.com/projects/trac/changeset/1535). Fixup in [commit 1536](http://wiki.powerdns.com/projects/trac/changeset/1536) for FreeBSD as found by Ralf van der Enden.
+- Tiny improvement possibly solving an issue on Solaris 10's completion port event multiplexer ([commit 1537](http://wiki.powerdns.com/projects/trac/changeset/1537)).
+
+## Changes between RC1 and RC2
+- Compilation on Solaris 10 has been fixed (various patchlevels had different issues), code in [commit 1522](http://wiki.powerdns.com/projects/trac/changeset/1522).
+- Compatibility with CentOS4/RHEL4 has been restored, the gcc and glibc versions shipped with this distribution contain a Thread Local Storage bug which we now work around. Thanks to Darren Gamble and Imre Gergely for debugging this issue, code in [commit 1527](http://wiki.powerdns.com/projects/trac/changeset/1527).
+- A failed setuid operation, because of misconfiguration, would result in a crash instead of an error message. Fixed in [commit 1523](http://wiki.powerdns.com/projects/trac/changeset/1523).
+- Imre Gergely discovered that PowerDNS was doing spurious root repriming when invalidating nssets. Fixed in [commit 1531](http://wiki.powerdns.com/projects/trac/changeset/1531).
+- Imre Gergely discovered our rrd graphs had not been changed for the new multithreaded world, and did not allow scaling beyond 200% cpu use. In addition, CPU usage graphs did not add up correctly. Implemented in [commit 1524](http://wiki.powerdns.com/projects/trac/changeset/1524).
+- Andreas Jakum discovered the description of 'max-packetcache-entries' and 'forward-zones-recurse' was wrong in the output of '--help' and '--config'. In addition, some stray backup files made it into the RC1 release. Addressed in [commit 1529](http://wiki.powerdns.com/projects/trac/changeset/1529).
+Full release notes follow, including some overlap with the incremental release notes above. Improvements
+- Multithreading, allowing near linear scaling to multiple CPUs or cores. Configured using 'threads=' (many commits). This also deprecates the '--fork' option.
+- Added ability to read a configuration item of a running PowerDNS Recursor using 'rec\_control get-parameter' ([commit 1243](http://wiki.powerdns.com/projects/trac/changeset/1243)), suggested by Wouter de Jong.
+- Added ability to read all statistics in one go of a running PowerDNS Recursor using 'rec\_control get-all' ([commit 1496](http://wiki.powerdns.com/projects/trac/changeset/1496)), suggested by Michael Renner.
+- Speedups in packet generation (Commits [1258](http://wiki.powerdns.com/projects/trac/changeset/1258), [1259](http://wiki.powerdns.com/projects/trac/changeset/1259), [1262](http://wiki.powerdns.com/projects/trac/changeset/1262))
+- TCP deferred accept() filter is turned on again for slight DoS protection. Code in [commit 1414](http://wiki.powerdns.com/projects/trac/changeset/1414).
+- PowerDNS Recursor can now do TCP/IP queries to remote IPv6 addresses ([commit 1412](http://wiki.powerdns.com/projects/trac/changeset/1412)).
+- Solaris 9 '/dev/poll' support added, Solaris 8 now deprecated. Changes in [commit 1421](http://wiki.powerdns.com/projects/trac/changeset/1421), [commit 1422](http://wiki.powerdns.com/projects/trac/changeset/1422), [commit 1424](http://wiki.powerdns.com/projects/trac/changeset/1424), [commit 1413](http://wiki.powerdns.com/projects/trac/changeset/1413).
+- Lua functions can now also see the address \_to\_ which a question was sent, using getlocaladdress(). Implemented in [commit 1309](http://wiki.powerdns.com/projects/trac/changeset/1309) and [commit 1315](http://wiki.powerdns.com/projects/trac/changeset/1315).
+- Maximum cache sizes now default to a sensible value. Suggested by Roel van der Made, implemented in [commit 1354](http://wiki.powerdns.com/projects/trac/changeset/1354).
+- Domains can now be forwarded to IPv6 addresses too, using either ::1 syntax or [::1]:25. Thanks to Wijnand Modderman for discovering this issue, fixed in [commit 1349](http://wiki.powerdns.com/projects/trac/changeset/1349).
+- Lua scripts can now load libraries at runtime, for example to calculate md5 hashes. Code by Winfried Angele in [commit 1405](http://wiki.powerdns.com/projects/trac/changeset/1405).
+- Periodic statistics output now includes average queries per second, as well as packet cache numbers ([commit 1493](http://wiki.powerdns.com/projects/trac/changeset/1493)).
+- New metrics are available for graphing, plus added to the default graphs ([commit 1495](http://wiki.powerdns.com/projects/trac/changeset/1495), [commit 1498](http://wiki.powerdns.com/projects/trac/changeset/1498), [commit 1503](http://wiki.powerdns.com/projects/trac/changeset/1503))
+- Fix errors/crashes on more recent versions of Solaris 10, where the ports functions could return ENOENT under some circumstances. Reported and debugged by Jan Gyselinck, fixed in [commit 1372](http://wiki.powerdns.com/projects/trac/changeset/1372).
+
+## New features
+- Add pdnslog() function for Lua scripts, so errors or other messages can be logged properly.
+- New settings to set the owner, group and access modes of the control socket (socket-owner, socket-group, socket-mode). Code by Aki Tuomi and documentation in [commit 1535](http://wiki.powerdns.com/projects/trac/changeset/1535). Fixup in [commit 1536](http://wiki.powerdns.com/projects/trac/changeset/1536) for FreeBSD as found by Ralf van der Enden.
+- rec\_control now accepts a --timeout parameter, which can be useful when reloading huge Lua scripts. Implemented in [commit 1366](http://wiki.powerdns.com/projects/trac/changeset/1366).
+- Domains can now be forwarded with the 'recursion-desired' bit on or off, using either **forward-zones-recurse** or by prefixing the name of a zone with a '+' in **forward-zones-file**. Feature suggested by Darren Gamble, implemented in [commit 1451](http://wiki.powerdns.com/projects/trac/changeset/1451).
+- Access control lists can now be reloaded at runtime (implemented in [commit 1457](http://wiki.powerdns.com/projects/trac/changeset/1457)).
+- PowerDNS Recursor can now use a pool of query-local-addresses to further increase resilience against spoofing. Suggested by Ad Spelt, implemented in [commit 1426](http://wiki.powerdns.com/projects/trac/changeset/1426).
+- PowerDNS Recursor now also has a packet cache, greatly speeding up operations. Implemented in [commit 1426](http://wiki.powerdns.com/projects/trac/changeset/1426), [commit 1433](http://wiki.powerdns.com/projects/trac/changeset/1433) and further.
+- Cache can be limited in how long it maximally stores records, for BIND compatibility (TTL limiting), by setting **max-cache-ttl**.Idea by Winfried Angele, implemented in [commit 1438](http://wiki.powerdns.com/projects/trac/changeset/1438).
+- Cache cleaning turned out to be scanning more of the cache than necessary for cache maintenance. In addition, far more frequent but smaller cache cleanups improve responsiveness. Thanks to Winfried Angele for discovering this issue. (commits [1501](http://wiki.powerdns.com/projects/trac/changeset/1501), [1507](http://wiki.powerdns.com/projects/trac/changeset/1507))
+- Performance graphs enhanced with separate CPU load and cache effectiveness plots, plus display of various overload situations (commits [1503](http://wiki.powerdns.com/projects/trac/changeset/1503))
+
+## Compiler/Operating system/Library updates
+- PowerDNS Recursor can now compile against newer versions of Boost (verified up to and including 1.42.0). Reported & fixed by Darix in [commit 1274](http://wiki.powerdns.com/projects/trac/changeset/1274). Further fixes in [commit 1275](http://wiki.powerdns.com/projects/trac/changeset/1275), [commit 1276](http://wiki.powerdns.com/projects/trac/changeset/1276), [commit 1277](http://wiki.powerdns.com/projects/trac/changeset/1277), [commit 1283](http://wiki.powerdns.com/projects/trac/changeset/1283).
+- Fix compatibility with newer versions of GCC (closes ticket [ticket 227](https://github.com/PowerDNS/pdns/issues/227), spotted by Ruben Kerkhof, code in [commit 1345](http://wiki.powerdns.com/projects/trac/changeset/1345), more fixes in commit [1394](http://wiki.powerdns.com/projects/trac/changeset/1394), [1416](http://wiki.powerdns.com/projects/trac/changeset/1416), [1440](http://wiki.powerdns.com/projects/trac/changeset/1440)).
+- Rrdtool update graph is now compatible with FreeBSD out of the box. Thanks to Bryan Seitz ([commit 1517](http://wiki.powerdns.com/projects/trac/changeset/1517)).
+- Fix up Makefile for older versions of Make ([commit 1229](http://wiki.powerdns.com/projects/trac/changeset/1229)).
+- Solaris compilation improvements (out of the box, no handwork needed).
+- Solaris 9 MTasker compilation fixes, as suggested by John Levon. Changes in [commit 1431](http://wiki.powerdns.com/projects/trac/changeset/1431).
+
+## Bug fixes
+- Under rare circumstances, the recursor could crash on 64 bit Linux systems running glibc 2.7, as found in Debian Lenny. These circumstances became a lot less rare for the 3.2 release. Discovered by Andreas Jakum and debugged by \#powerdns, fix in [commit 1519](http://wiki.powerdns.com/projects/trac/changeset/1519).
+- Imre Gergely discovered that PowerDNS was doing spurious root repriming when invalidating nssets. Fixed in [commit 1531](http://wiki.powerdns.com/projects/trac/changeset/1531).
+- Configuration parser is now resistant against trailing tabs and other whitespace ([commit 1242](http://wiki.powerdns.com/projects/trac/changeset/1242))
+- Fix typo in a Lua error message. Close [ticket 210](https://github.com/PowerDNS/pdns/issues/210), as reported by Stefan Schmidt ([commit 1319](http://wiki.powerdns.com/projects/trac/changeset/1319)).
+- Profiled-build instructions were broken, discovered & fixes suggested by Stefan Schmidt. [ticket 239](https://github.com/PowerDNS/pdns/issues/239), fix in [commit 1462](http://wiki.powerdns.com/projects/trac/changeset/1462).
+- Fix up duplicate SOA from a remote authoritative server from showing up in our output ([commit 1475](http://wiki.powerdns.com/projects/trac/changeset/1475)).
+- All security fixes from 3.1.7.2 are included.
+- Under highly exceptional circumstances on FreeBSD the PowerDNS Recursor could crash because of a TCP/IP error. Reported and fixed by Andrei Poelov in [ticket 192](https://github.com/PowerDNS/pdns/issues/192), fixed in [commit 1280](http://wiki.powerdns.com/projects/trac/changeset/1280).
+- PowerDNS Recursor can be a root-server again. Error spotted by the ever vigilant Darren Gamble (ticket [229](https://github.com/PowerDNS/pdns/issues/229)), fix in [commit 1458](http://wiki.powerdns.com/projects/trac/changeset/1458).
+- Rare TCP/IP errors no longer lead to PowerDNS Recursor logging errors or becoming confused. Debugged by Josh Berry of Plusnet PLC. Code in [commit 1457](http://wiki.powerdns.com/projects/trac/changeset/1457).
+- Do not hammer parent servers in case child zones are misconfigured, requery at most once every 10 seconds. Reported & investigated by Stefan Schmidt and Andreas Jakum, fixed in [commit 1265](http://wiki.powerdns.com/projects/trac/changeset/1265).
+- Properly process answers from remote authoritative servers that send error answers without including the original question ([commit 1329](http://wiki.powerdns.com/projects/trac/changeset/1329), [commit 1327](http://wiki.powerdns.com/projects/trac/changeset/1327)).
+- No longer spontaneously turn on 'export-etc-hosts' after reloading zones. Discovered by Paul Cairney, reported in [ticket 225](https://github.com/PowerDNS/pdns/issues/225), addressed in [commit 1348](http://wiki.powerdns.com/projects/trac/changeset/1348).
+- Very abrupt server failure of large numbers of high-volume authoritative servers could trigger an out of memory situation. Addressed in [commit 1505](http://wiki.powerdns.com/projects/trac/changeset/1505).
+- Make timeouts for queries to remote authoritative servers configurable with millisecond granularity. In addition, the old code turned out to consider the timeout expired when the integral number of seconds since 1970 increased by 1 - which *on average* is after 500ms. This might have caused spurious timeouts! New default timeout is 1500ms. See **network-timeout** setting for more details. Code in [commit 1402](http://wiki.powerdns.com/projects/trac/changeset/1402).
+
+# Recursor version 3.1.7.2
+Released on the 6th of January 2010.
+
+This release consist of a number of vital security updates. These updates address issues that can in all likelihood lead to a full system compromise. In addition, it is possible for third parties to pollute your cache with dangerous data, exposing your users to possible harm.
+
+This version has been well tested, and at the time of this release is already powering millions of internet connections, and should therefore be a risk-free upgrade from 3.1.7.1 or any earlier version of the PowerDNS Recursor.
+
+All known versions of the PowerDNS Recursor are impacted to a greater or lesser extent, so an immediate update is advised.
+
+These vulnerabilities were discovered by a third party that can't yet be named, but who we thank for their contribution to a more secure PowerDNS Recursor.
+
+For more information, see [PowerDNS Security Advisory 2010-01](security/powerdns-advisory-2010-01.md "PowerDNS Security Advisory 2010-01: PowerDNS Recursor up to and including 3.1.7.1 can be brought down and probably exploited") and [PowerDNS Security Advisory 2010-02](security/powerdns-advisory-2010-02.md "PowerDNS Security Advisory 2010-02: PowerDNS Recursor up to and including 3.1.7.1 can be spoofed into accepting bogus data").
+
+# Recursor version 3.1.7.1
+Released on the 2nd of August 2009.
+
+This release consists entirely of fixes for tiny bugs that have been reported over the past year. In addition, compatibility has been restored with the latest versions of the gcc compiler and the 'boost' libraries.
+
+No features have been added, but some debugging code that very slightly impacted performance (and polluted the console when operating in the foreground) has been removed.
+
+FreeBSD users may want to upgrade because of a very remote chance of 3.1.7 and previous crashing once every few years. For other operators not currently experiencing problems, there is no reason to upgrade.
+
+- Improved error messages when parsing zones for authoritative serving ([commit 1235](http://wiki.powerdns.com/projects/trac/changeset/1235)).
+- Better resilience against whitespace in configuration (changesets [1237](http://wiki.powerdns.com/projects/trac/changeset/1237), [1240](http://wiki.powerdns.com/projects/trac/changeset/1240), [1242](http://wiki.powerdns.com/projects/trac/changeset/1242))
+- Slight performance increase ([commit 1378](http://wiki.powerdns.com/projects/trac/changeset/1378))
+- Fix rare case where timeouts were not being reported to the right query-thread ([commit 1260](http://wiki.powerdns.com/projects/trac/changeset/1260))
+- Fix compilation against newer versions of the Boost C++ libraries ([commit 1381](http://wiki.powerdns.com/projects/trac/changeset/1381))
+- Close very rare issue with TCP/IP close reporting ECONNRESET on FreeBSD. Reported by Andrei Poelov in [ticket 192](https://github.com/PowerDNS/pdns/issues/192).
+- Silence debugging output ([commit 1286](http://wiki.powerdns.com/projects/trac/changeset/1286)).
+- Fix compilation against newer versions of gcc ([commit 1384](http://wiki.powerdns.com/projects/trac/changeset/1384))
+- No longer set export-etc-hosts to 'on' on reload-zones. Discovered by Paul Cairney, closes [ticket 225](https://github.com/PowerDNS/pdns/issues/225).
+- Sane default for the maximum cache size in the Recursor, suggested by Roel van der Made ([commit 1354](http://wiki.powerdns.com/projects/trac/changeset/1354)).
+- No longer exit because of the changed behaviour of the Solaris 'completion ports' in more recent versions of Solaris. Fix in [commit 1372](http://wiki.powerdns.com/projects/trac/changeset/1372), reported by Jan Gyselinck.
+
+# Authoritative Server version 2.9.22
+**Warning**: The 2.9.22.x series of releases is end-of-life and unsupported. It contains many issues and potential security problems. We urge you to upgrade to a recent version of PowerDNS!
+
+Released on the 27th of January 2009.
+
+This is a huge release, spanning almost 20 months of development. Besides fixing a lot of bugs, of note is the addition of the so called 'Notification Proxy', which allows PowerDNS to function as a master server behind a firewall, plus the huge performance improvement of the internal caches.
+
+This work has been made possible by UPC Broadband and Directi, respectively.
+
+Finally, the release candidates of this version have been tested & improved by Jorn Ekkelenkamp, Ton van Rosmalen, Jeff Sipek, Tyler Hall, Christof Meerwald and Stefan Schmidt.
+
+## Fixed between rc1 and rc2, but not an issue in 2.9.21.
+- **pdns\_control ccounts** again outputs proper cache statistics. Implemented in [commit 1304](http://wiki.powerdns.com/projects/trac/changeset/1304).
+- Negative query caching was reinstated, leading to 6 times fewer backend queries than rc1 on the Express.powerdns.com servers.
+- Packetcache no longer needlessly parses outgoing packets before sending them.
+- Fancy records work again. This work has been sponsored by ISP Services. Implemented in [commit 1302](http://wiki.powerdns.com/projects/trac/changeset/1302) and [commit 1299](http://wiki.powerdns.com/projects/trac/changeset/1299).
+
+## New features
+- **pdns\_control** can now also work over TCP/IP. Sponsored by Directi. Commits [1246](http://wiki.powerdns.com/projects/trac/changeset/1246), [1251](http://wiki.powerdns.com/projects/trac/changeset/1251), [1254](http://wiki.powerdns.com/projects/trac/changeset/1254), [1255](http://wiki.powerdns.com/projects/trac/changeset/1255).
+- Implemented a notification proxy, see ["Notification proxy (nproxy)"](tools/analysis.md#nproxy"). This work was sponsored by UPC Broadband. Implemented in commits [1075](http://wiki.powerdns.com/projects/trac/changeset/1075), [1077](http://wiki.powerdns.com/projects/trac/changeset/1077), [1082](http://wiki.powerdns.com/projects/trac/changeset/1082), [1083](http://wiki.powerdns.com/projects/trac/changeset/1083), [1085](http://wiki.powerdns.com/projects/trac/changeset/1085) and [1086](http://wiki.powerdns.com/projects/trac/changeset/1086).
+- IXFR queries are now supported in the sense that we treat them as AXFR queries, silencing warnings in other nameservers. Suggested in [ticket 131](https://github.com/PowerDNS/pdns/issues/131).
+- The PIPE backend has been extended by David Apgar to allow the reporting of errors using the 'FAIL' command, plus support for responses with whitespace. Implemented in [commit 1114](http://wiki.powerdns.com/projects/trac/changeset/1114).
+- PowerDNS Authoritative server now parses incoming EDNS options, like maximum allowed packet size. Implemented in [commit 1123](http://wiki.powerdns.com/projects/trac/changeset/1123) and [commit 1281](http://wiki.powerdns.com/projects/trac/changeset/1281).
+- Added support for DHCID, IPSECKEY and KX records, thanks Norbert Sendetzky for the hint. Implemented in [commit 1144](http://wiki.powerdns.com/projects/trac/changeset/1144).
+- Norbert Sendetzky has has added support for all record types supported by PowerDNS to the LDAPBackend. Furthermore, the detection of OpenLDAP in autoconf has been improved. Finally, debian has supplied some fixes to PowerLDAP. Implemented in [commit 1152](http://wiki.powerdns.com/projects/trac/changeset/1152) and [commit 1153](http://wiki.powerdns.com/projects/trac/changeset/1153).
+- Implemented EDNS NSID option for retrieving the nameserver ID out of band. Defaults to hostname, can be specified using the **server-id** setting. Code in [commit 1232](http://wiki.powerdns.com/projects/trac/changeset/1232).
+- Implemented experimental EDNS PING for enhanced forgery resilience. Code in [commit 1232](http://wiki.powerdns.com/projects/trac/changeset/1232).
+
+## Performance
+- Improve packet generation performance, in some cases by 25%. Code in [1258](http://wiki.powerdns.com/projects/trac/changeset/1258), [1259](http://wiki.powerdns.com/projects/trac/changeset/1259).
+- Improved access list checking performance. [commit 1261](http://wiki.powerdns.com/projects/trac/changeset/1261).
+- PowerDNS Authoritative caches were completely redone, and are now based on the same cache that is in the resolver. This work has been sponsored by Directi. In large benchmarks, PowerDNS performance has improved by an order of magnitude or more. This new version allows for near-instantaneous cache purging, plus very rapid purging based on suffix. Purge commands can also be batched. This work is partially based on an innovative reverse-string comparison function authored by Aki Tuomi.
+- Installations which run with very high cache hitrates can now benefit from multiple CPUs by setting **receiver-threads** to the number of desired CPUs to utilize in cache operations. Implemented in [commit 1316](http://wiki.powerdns.com/projects/trac/changeset/1316).
+- BIND backend speedups in [commit 1108](http://wiki.powerdns.com/projects/trac/changeset/1108), measured at around a 20% improvement, possibly more on very large setups.
+
+## Bugs fixed
+- Tyler Hall discovered the PowerDNS configuration file parser had problems with trailing tabs. This turned out to be a wider problem in PowerDNS. Buggy code replaced by a library call in [commit 1237](http://wiki.powerdns.com/projects/trac/changeset/1237) and [commit 1240](http://wiki.powerdns.com/projects/trac/changeset/1240).
+- David Apgar of Yahoo discovered that our 'guardian' method of restarting PowerDNS in case of problems was not fool proof, and submitted a fix. A variation of this fix can be found in [commit 1323](http://wiki.powerdns.com/projects/trac/changeset/1323). Also reported by Directi.
+- Connection reset by peer events in the TCP nameserver no longer lead to the cycling of database connections. Code in [commit 1241](http://wiki.powerdns.com/projects/trac/changeset/1241).
+- FreeBSD compilation with Generic PostgreSQL backend was fixed. Reported by Wouter de Jong of WideXS, fixed in [commit 1305](http://wiki.powerdns.com/projects/trac/changeset/1305), closes [ticket 95](https://github.com/PowerDNS/pdns/issues/95).
+- Webserver no longer prints '1e2%'. Finally closes [ticket 26](https://github.com/PowerDNS/pdns/issues/26). Much friendly nagging for over 3 years by Jeff Sipek, code in [commit 1303](http://wiki.powerdns.com/projects/trac/changeset/1303).
+- PowerDNS used to ignore certain queries it could not answer. These queries are no longer ignored, but get a SERVFAIL response. Implemented in [commit 1239](http://wiki.powerdns.com/projects/trac/changeset/1239).
+- Fix subtle CNAME and wildcard interactions reported by 'zzyzz', implemented in [commit 1147](http://wiki.powerdns.com/projects/trac/changeset/1147).
+- The generic backends did not honour the **default-ttl** setting. Spotted and implemented by Matti Hiljanen.
+- Matti Hiljanen discovered that the OpenDBX backend did not fill out the SOA ttl value properly. Matti also improved the SQL statements for better compatibility. Implemented in [commit 1181](http://wiki.powerdns.com/projects/trac/changeset/1181).
+- Treat invalid WWW requests better. Spotted by Maikel Verheijen, implemented in [commit 1092](http://wiki.powerdns.com/projects/trac/changeset/1092).
+- Documentation errors and typos, spotted by Marco Davids ([commit 1097](http://wiki.powerdns.com/projects/trac/changeset/1097)) and Rejo Zengers ([commit 1119](http://wiki.powerdns.com/projects/trac/changeset/1119))
+- Properly fill out the 'recursion available'-flag. Spotted by Augie Schwer in [ticket 167](https://github.com/PowerDNS/pdns/issues/167).
+- Several memory leaks on bad data in the database or other errors have been fixed. Addressed in [1078](http://wiki.powerdns.com/projects/trac/changeset/1078) and [1079](http://wiki.powerdns.com/projects/trac/changeset/1079).
+- In contravention to the documentation, the domain type as specified in the database ('MASTER', 'SLAVE' or 'NATIVE') was interpreted case sensitively. [1084](http://wiki.powerdns.com/projects/trac/changeset/1084).
+- BIND backend could crash on processing information about slave zones to be checked. Spotted by Stefan Schmidt, fixed in [1089](http://wiki.powerdns.com/projects/trac/changeset/1089).
+- Jelte Jansen of Stichting NLNetLabs discovered PowerDNS in BIND mode couldn't operate as a root-server! Fixed in [1057](http://wiki.powerdns.com/projects/trac/changeset/1057).
+- 'DPS' discovered there was a rare opportunity for PowerDNS to lock up waiting for new data. Addressed in [1076](http://wiki.powerdns.com/projects/trac/changeset/1076).
+- Make singlethreaded mode more resilient against errors. [commit 1272](http://wiki.powerdns.com/projects/trac/changeset/1272).
+- DNSSEC records were part of 2.9.21, but were not actually hooked up. Please note that while PowerDNS can serve most DNSSEC records, it does not do DNSSEC processing. Implemented in [1046](http://wiki.powerdns.com/projects/trac/changeset/1046).
+- Shawn Starr migrated all his domains to PowerDNS in one evening, from an installation that had been used since BIND4. In doing so, he found 3 bugs in as many hours. An **IN** statement in the BIND `named.conf` with a zone with a trailing dot was misparsed, fixed in [commit 1233](http://wiki.powerdns.com/projects/trac/changeset/1233). Secondly, the zone file parser tripped over a line consisting of nothing but comments in the wrong place. Finally '$ORIGIN .' was misparsed. Last two issues fixed in [commit 1234](http://wiki.powerdns.com/projects/trac/changeset/1234).
+- Our statistics counters did not wrap correctly after the 2.15 billion mark. Spotted by Stefan Schmidt, reported in [ticket 179](https://github.com/PowerDNS/pdns/issues/179), fixed in [commit 1284](http://wiki.powerdns.com/projects/trac/changeset/1284).
+- Bindbackend could sometimes generate very strange error messages while processing a malformed zone file. Sometimes such error messages could cause a crash (reported on HP-UX). Addressed by [commit 1279](http://wiki.powerdns.com/projects/trac/changeset/1279). This could not be triggered remotely. Closes ticket [ticket 203](https://github.com/PowerDNS/pdns/issues/203).
+- Pipe backend did not clean up killed coprocesses. Found and fixed by Daniel Drown
+- Installations with tens of thousands of slave domains would never complete the cycle to check the freshness of all zones as each incoming notification disrupted this cycle. Addressed in cooperation with Tyler Hall of EditDNS.
+
+## Improvements
+- Zone parser improvements mean $TTL and $INCLUDES now work a lot better. Implemented in [1056](http://wiki.powerdns.com/projects/trac/changeset/1056), [1062](http://wiki.powerdns.com/projects/trac/changeset/1062).
+- No longer report temporary recvfrom errors, which used to spam the log on many systems. Addressed in [commit 1320](http://wiki.powerdns.com/projects/trac/changeset/1320).
+- Direct queries for 'fancy records' would lead to errors, such queries now fail early. Spotted by Jorn Ekkelenkamp, implemented in [1051](http://wiki.powerdns.com/projects/trac/changeset/1051).
+- Fix typo in geobackend, closing [ticket 157](https://github.com/PowerDNS/pdns/issues/157), implemented in [1090](http://wiki.powerdns.com/projects/trac/changeset/1090).
+- Initial work on TSIG support - not done yet. Spurred on by Marco Davids.
+- Embarrassingly, the 'master' configuration setting was not documented in the list of all settings!
+- Norbert has updated OpenDBX so that SQLite reads and writes no longer deadlock, plus compilation fixes on Solaris, plus the addition of autoserials to backends that support triggers. Implemented in [commit 1154](http://wiki.powerdns.com/projects/trac/changeset/1154).
+- Random generator is now based on AES, improving the security of certain proxy operations. This is the same random generator that is in the recursor. Implemented in [commit 1256](http://wiki.powerdns.com/projects/trac/changeset/1256).
+- Documentation for 'supermaster' mode was improved due to popular demand.
+- When binding to a UDP port failed, supply a more precise error message ([commit 1245](http://wiki.powerdns.com/projects/trac/changeset/1245))
+- The zone parser error messages were vastly improved, partially inspired by Shawn's cowboy migration. Code in [commit 1235](http://wiki.powerdns.com/projects/trac/changeset/1235).
+- Labels are compressed more efficiently (case-insensitively), leading to smaller packets. Implemented in [commit 1156](http://wiki.powerdns.com/projects/trac/changeset/1156).
+- Fix handling of TCP timeouts to not cause a reload of the backends. Implemented in [commit 1092](http://wiki.powerdns.com/projects/trac/changeset/1092).
+- TCP Receiver no longer spams the log with common network errors. Implemented in [commit 1306](http://wiki.powerdns.com/projects/trac/changeset/1306).
+- Move from select() to poll()-based multiplexing, allowing PowerDNS to listen on more than 1024 sockets simultaneously. One big PowerDNS user needs this. Implemented in [1072](http://wiki.powerdns.com/projects/trac/changeset/1072).
+- Zone2sql now reads source files in performance enhancing inode order. Additionally, zone2sql no longer dies on a missing zone file if **--on-error-resume-next** was specified. Finally, statistics of zone2sql conversion have been improved. Implemented in [1055](http://wiki.powerdns.com/projects/trac/changeset/1055).
+- Address issues found by more recent g++ versions. Spotted and/or fixed by Jorn Ekkelenkamp ([commit 1051](http://wiki.powerdns.com/projects/trac/changeset/1051)), Marcus Rueckert ([commit 1094](http://wiki.powerdns.com/projects/trac/changeset/1094)), Norbert Sendetzky ([commit 1107](http://wiki.powerdns.com/projects/trac/changeset/1107)), Serge Belyshev ([commit 1171](http://wiki.powerdns.com/projects/trac/changeset/1171)).
+- The Intel C Compiler implements certain things differently, causing the master/slave communicator to malfunction. Spotted by Marcus Rueckert, implemented in [1052](http://wiki.powerdns.com/projects/trac/changeset/1052), plus fallout in [1105](http://wiki.powerdns.com/projects/trac/changeset/1105).
+- PowerDNS can now be compiled with Boost 1.37.0.
+- Andre Lorbach of Adiscon discovered the Microsoft Windows 2003 nameserver adds out of zone data to zone transfers, which we need to ignore, instead of rejecting the entire zone. Implemented in [1048](http://wiki.powerdns.com/projects/trac/changeset/1048).
+- PowerDNS now skips remote master servers which consistently generate timeout messages, improving the master checking cycle time tremendously. Developed in cooperation with Tyler Hall. Implemented in [commit 1278](http://wiki.powerdns.com/projects/trac/changeset/1278).
+- When binding to a UDP port failed, supply a more precise error message ([commit 1245](http://wiki.powerdns.com/projects/trac/changeset/1245))
+- **dnsreplay** now waits for the final answers to arrive, making it possible to process even small pcap files and get meaningful statistics. [commit 1268](http://wiki.powerdns.com/projects/trac/changeset/1268).
+- **dnsreplay** has a more sane default timeout now, which can be configured too. Suggested by Augie Schwer in [ticket 163](https://github.com/PowerDNS/pdns/issues/163), implemented in [commit 1287](http://wiki.powerdns.com/projects/trac/changeset/1287).
+
+# Authoritative Server version 2.9.21.2
+Released on the 18th of November 2008.
+
+This release consists of a single patch to PowerDNS Authoritative Server version 2.9.21.1. In some configurations, notably with configuration option 'distributor-threads=1', the PowerDNS Authoritative Server crashes easily in some error conditions.
+
+All users are urged to upgrade. Even though PowerDNS restarts itself on encountering such error conditions, and even though most PowerDNS configurations do not run in single threaded mode, an upgrade is recommended.
+
+More detail can be found in [PowerDNS Security Advisory 2008-02](security/powerdns-advisory-2008-03.md "PowerDNS Security Advisory 2008-02: Some PowerDNS Configurations can be forced to restart remotely").
+
+# Authoritative Server version 2.9.21.1
+Released on the 6th of August 2008.
+
+This release consists of a single patch to PowerDNS Authoritative Server version 2.9.21. Brian J. Dowling of Simplicity Communications has discovered a security implication of the previous PowerDNS behaviour to drop queries it considers malformed. We are grateful that Brian notified us quickly about this problem.
+
+This issue has been assigned CVE-2008-3337. The single patch is in [commit 1239](http://wiki.powerdns.com/projects/trac/changeset/1239). More detail can be found in [PowerDNS Security Advisory 2008-02](security/powerdns-advisory-2008-02.md "PowerDNS Security Advisory 2008-02: By not responding to certain queries, domains become easier to spoof").
+
+The implication is that while the PowerDNS Authoritative server itself does not face a security risk because of dropping these malformed queries, other resolving nameservers run a higher risk of accepting spoofed answers for domains being hosted by PowerDNS Authoritative Servers before 2.9.21.1.
+
+While the dropping of queries does not aid sophisticated spoofing attempts, it does facilitate simpler attacks.
+
+It may be good to know that several large sites already run with this patch applied, as it has been in the public code base for some weeks already.
+
+# Recursor version 3.1.7
+Released the 25th of June 2008.
+
+This version contains powerful scripting abilities, allowing operators to modify DNS responses in many interesting ways. Among other things, these abilities can be used to filter out malware domains, to perform load balancing, to comply with legal and other requirements and finally, to implement 'NXDOMAIN' redirection.
+
+It is hoped that the addition of Lua scripting will enable responsible DNS modification for those that need it.
+
+For more details about the Lua scripting, which can be modified, loaded and unloaded at runtime, see [Scripting](recursor/scripting.md "Scripting"). Many thanks are due to the \#lua irc channel, for excellent near-realtime Lua support. In addition, a number of PowerDNS users have been enthousiastically testing prereleases of the scripting support, and have found and solved many issues.
+
+In addition, 3.1.7 fixes a number of bugs
+
+- In 3.1.5 and 3.1.6, an authoritative server could continue to renew its authority, even though a domain had been delegated to other servers in the meantime.
+
+ In the rare cases where this happened, and the old servers were not shut down, the observed effect is that users were fed outdated data. Bug spotted and analysed by Darren Gamble, fix in [commit 1182](http://wiki.powerdns.com/projects/trac/changeset/1182) and [commit 1183](http://wiki.powerdns.com/projects/trac/changeset/1183).
+
+- Thanks to long time PowerDNS contributor Stefan Arentz, for the first time, Mac OS X 10.5 users can compile and run the PowerDNS Recursor! Patch in [commit 1185](http://wiki.powerdns.com/projects/trac/changeset/1185).
+- Sten Spans spotted that for outgoing TCP/IP queries, the **query-local-address** setting was not honored. Fixed in [commit 1190](http://wiki.powerdns.com/projects/trac/changeset/1190).
+- **rec\_control wipe-cache** now also wipes domains from the negative cache, hurrying up the expiry of negatively cached records. Suggested by Simon Kirby, implemented in [commit 1204](http://wiki.powerdns.com/projects/trac/changeset/1204).
+- When a forwarder server is configured for a domain, using the **forward-zones** setting, this server IP address was filtered using the **dont-query** setting, which is generally not what is desired: the server to which queries are forwarded will often live in private IP space, and the operator should be trusted to know what he is doing. Reported and argued by Simon Kirby, fix in [commit 1211](http://wiki.powerdns.com/projects/trac/changeset/1211).
+- Marcus Rueckert of OpenSUSE reported that very recent gcc versions emitted a (correct) warning on an overly complicated line in syncres.cc, fixed in [commit 1189](http://wiki.powerdns.com/projects/trac/changeset/1189).
+- Stefan Schmidt discovered that the netmask matching code, used by the new Lua scripts, but also by all other parts of PowerDNS, had problems with explicit '/32' matches. Fixed in [commit 1205](http://wiki.powerdns.com/projects/trac/changeset/1205).
+
+# Recursor version 3.1.6
+Released on the 1st of May 2008.
+
+This version fixes two important problems, each on its own important enough to justify a quick upgrade.
+
+- Version 3.1.5 had problems resolving several slightly misconfigured domains, including for a time 'juniper.net'. Nameserver timeouts were not being processed correctly, leading PowerDNS to not update the internal clock, which in turn meant that any queries immediately following an error would time out as well. Because of retries, this would usually not be a problem except on very busy servers, for domains with different nameservers at different levels of the DNS-hierarchy, like 'juniper.net'.
+
+ This issue was fixed rapidly because of the help of [XS4ALL](http://www.xs4all.nl) (Eric Veldhuyzen, Kai Storbeck), Brad Dameron and Kees Monshouwer. Fix in [commit 1178](http://wiki.powerdns.com/projects/trac/changeset/1178).
+
+- The new high-quality random generator was not used for all random numbers, especially in source port selection. This means that 3.1.5 is still a lot more secure than 3.1.4 was, and its algorithms more secure than most other nameservers, but it also means 3.1.5 is not as secure as it could be. A quick upgrade is recommended. Discovered by Thomas Biege of Novell (SUSE), fixed in [commit 1179](http://wiki.powerdns.com/projects/trac/changeset/1179).
+
+# Recursor version 3.1.5
+Released on the 31st of March 2008.
+
+Much like 3.1.4, this release does not add a lot of major features. Instead, performance has been improved significantly (estimated at around 20%), and many rare and not so rare issues were addressed. Multi-part TXT records now work as expected - the only significant functional bug found in 15 months. One of the oldest feature requests was fulfilled: version 3.1.5 can finally forward queries for designated domains to multiple servers, on differing port numbers if needed. Previously only one forwarder address was supported. This lack held back a number of migrations to PowerDNS.
+
+We would like to thank Amit Klein of Trusteer for bringing a serious vulnerability to our attention which would enable a smart attacker to 'spoof' previous versions of the PowerDNS Recursor into accepting possibly malicious data.
+
+Details can be found on [this Trusteer page](http://www.trusteer.com/docs/powerdnsrecursor.html).
+
+It is recommended that all users of the PowerDNS Recursor upgrade to 3.1.5 as soon as practicable, while we simultaneously note that busy servers are less susceptible to the attack, but not immune.
+
+The PowerDNS Security Advisory can be found in [PowerDNS Security Advisory 2008-01](security/powerdns-advisory-2008-01.md "PowerDNS Security Advisory 2008-01: System random generator can be predicted, leading to the potential to 'spoof' PowerDNS Recursor").
+
+This version can properly benefit from all IPv4 and IPv6 addresses in use at the root-servers as of early February 2008. In order to implement this, changes were made to how the Recursor deals internally with A and AAAA queries for nameservers, see below for more details.
+
+Additionally, newer releases of the G++ compiler required some fixes (see [ticket 173](https://github.com/PowerDNS/pdns/issues/173)).
+
+This release was made possible by the help of Wichert Akkerman, Winfried Angele, Arnoud Bakker (Fox-IT), Niels Bakker (no relation!), Leo Baltus (Nederlandse Publieke Omroep), Marco Davids (SIDN), David Gavarret (Neuf Cegetel), Peter Gervai, Marcus Goller (UPC), Matti Hiljanen (Saunalahti/Elisa), Ruben Kerkhof, Alex Kiernan, Amit Klein (Trusteer), Kenneth Marshall (Rice University), Thomas Rietz, Marcus Rueckert (OpenSUSE), Augie Schwer (Sonix), Sten Spans (Bit), Stefan Schmidt (Freenet), Kai Storbeck (xs4all), Alex Trull, Andrew Turnbull (No Wires) and Aaron Thompson, and many more who filed bugs anonymously, or who we forgot to mention.
+
+## Security related issues
+- Amit Klein has informed us that System random generator output can be predicted based on its past behaviour, allowing a smart attacker to 'spoof' our nameserver. Full details in [PowerDNS Security Advisory 2008-01](security/powerdns-advisory-2008-01.md "PowerDNS Security Advisory 2008-01: System random generator can be predicted, leading to the potential to 'spoof' PowerDNS Recursor").
+- The Recursor will by default no longer query private-space nameservers. This closes a slight security risk and simultaneously improves performance and stability. For more information, see **dont-query** in [pdns\_recursor settings](recursor/settings.md#dont-query "pdns_recursor settings"). Implemented in [commit 923](http://wiki.powerdns.com/projects/trac/changeset/923).
+- Applied fix for [ticket 110](https://github.com/PowerDNS/pdns/issues/110) ('PowerDNS should change directory to '/' in chroot), implemented in [commit 944](http://wiki.powerdns.com/projects/trac/changeset/944).
+
+## Performance
+- The DNS packet writing and parsing infrastructure performance was improved in several ways, see commits [925](http://wiki.powerdns.com/projects/trac/changeset/925), [926](http://wiki.powerdns.com/projects/trac/changeset/926), [928](http://wiki.powerdns.com/projects/trac/changeset/928), [931](http://wiki.powerdns.com/projects/trac/changeset/931), [1021](http://wiki.powerdns.com/projects/trac/changeset/1021), [1050](http://wiki.powerdns.com/projects/trac/changeset/1050).
+- Remove multithreading overhead from the Recursor ([commit 999](http://wiki.powerdns.com/projects/trac/changeset/999)).
+
+## Bug fixes
+- Built-in authoritative server now properly derives the TTL from the SOA record if not specified. Implemented in [commit 1165](http://wiki.powerdns.com/projects/trac/changeset/1165). Additionally, even when TTL was specified for the built-in authoritative server, it was ignored. Reported by Stefan Schmidt, closing [ticket 147](https://github.com/PowerDNS/pdns/issues/147).
+- Empty TXT record components can now be served. Implemented in [commit 1166](http://wiki.powerdns.com/projects/trac/changeset/1166), closing [ticket 178](https://github.com/PowerDNS/pdns/issues/178). Spotted by Matti Hiljanen.
+- The Recursor would not properly override old data with new, sometimes serving old and new data concurrently. Fixed in [commit 1137](http://wiki.powerdns.com/projects/trac/changeset/1137).
+- SOA records with embedded carriage-return characters are now parsed correctly. Implemented in [commit 1167](http://wiki.powerdns.com/projects/trac/changeset/1167), closing [ticket 162](https://github.com/PowerDNS/pdns/issues/162).
+- Some routing conditions could cause UDP connected sockets to generate an error which PowerDNS did not deal with properly, leading to a leaked file descriptor. As these run out over time, the recursor could crash. This would also happen for IPv6 queries on a host with no IPv6 connectivity. Thanks to Kai of xs4all and Wichert Akkerman for reporting this issue. Fix in [commit 1133](http://wiki.powerdns.com/projects/trac/changeset/1133).
+- Empty unknown record types can now be stored without generating a scary error ([commit 1129](http://wiki.powerdns.com/projects/trac/changeset/1129))
+- Applied fix for [ticket 111](https://github.com/PowerDNS/pdns/issues/111), [ticket 112](https://github.com/PowerDNS/pdns/issues/112) and [ticket 153](https://github.com/PowerDNS/pdns/issues/153) - large (multipart) TXT records are now retrieved and served properly. Fix in [commit 996](http://wiki.powerdns.com/projects/trac/changeset/996).
+- Solaris compilation instructions in Recursor documentation were wrong, leading to an instant crash on startup. Luckily nobody reads the documentation, except for Marcus Goller who found the error. Fixed in [commit 1124](http://wiki.powerdns.com/projects/trac/changeset/1124).
+- On Solaris, finally fix the issue where queries get distributed strangely over CPUs, or not get distributed at all. Much debugging and analysing performed by Alex Kiernan, who also supplied fixes. Implemented in [commit 1091](http://wiki.powerdns.com/projects/trac/changeset/1091), [commit 1093](http://wiki.powerdns.com/projects/trac/changeset/1093).
+- Various fixes for modern G++ versions, most spotted by Marcus Rueckert (commits [964](http://wiki.powerdns.com/projects/trac/changeset/964), [965](http://wiki.powerdns.com/projects/trac/changeset/965), [1028](http://wiki.powerdns.com/projects/trac/changeset/1028), [1052](http://wiki.powerdns.com/projects/trac/changeset/1052)), and Ruben Kerkhof ([commit 1136](http://wiki.powerdns.com/projects/trac/changeset/1136), closing [ticket 175](https://github.com/PowerDNS/pdns/issues/175)).
+- Recursor would not properly clean up pidfile and control socket, closing [ticket 120](https://github.com/PowerDNS/pdns/issues/120), code in [commit 988](http://wiki.powerdns.com/projects/trac/changeset/988), [commit 1098](http://wiki.powerdns.com/projects/trac/changeset/1098) (part of fix by Matti Hiljanen, spotted by Leo Baltus)
+- Recursor can now serve multi-line records from its limited authoritative server ([commit 1014](http://wiki.powerdns.com/projects/trac/changeset/1014)).
+- When parsing zones, the 'm' time specification stands for minutes, not months! Closing Debian bug 406462 ([commit 1026](http://wiki.powerdns.com/projects/trac/changeset/1026))
+- Authoritative zone parser did not support '@' in the content of records. Spotted by Marco Davids, fixed in [commit 1030](http://wiki.powerdns.com/projects/trac/changeset/1030).
+- Authoritative zone parser could be confused by trailing TABs on record lines ([commit 1062](http://wiki.powerdns.com/projects/trac/changeset/1062)).
+- EINTR error code could block entire server if received at the wrong time. Spotted by Arnoud Bakker, fix in [commit 1059](http://wiki.powerdns.com/projects/trac/changeset/1059).
+- Fix crash on NetBSD on Alpha CPUs, might improve startup behaviour on empty caches on other architectures as well ([commit 1061](http://wiki.powerdns.com/projects/trac/changeset/1061)).
+- Outbound TCP queries were being performed sub-optimally because of an interaction with the 'MPlexer'. Fixes in [commit 1115](http://wiki.powerdns.com/projects/trac/changeset/1115), [commit 1116](http://wiki.powerdns.com/projects/trac/changeset/1116).
+
+## New features
+- Implemented **rec\_control** command **get uptime**, as suggested by Niels Bakker ([commit 935](http://wiki.powerdns.com/projects/trac/changeset/935)). Added to default rrdtool scripts in [commit 940](http://wiki.powerdns.com/projects/trac/changeset/940).
+- The Recursor Authoritative component, meant for having the Recursor serve some zones authoritatively, now supports $INCLUDE and $GENERATE. Implemented in [commit 951](http://wiki.powerdns.com/projects/trac/changeset/951) and [commit 952](http://wiki.powerdns.com/projects/trac/changeset/952), [commit 967](http://wiki.powerdns.com/projects/trac/changeset/967) (discovered by Thomas Rietz),
+- Implemented **forward-zones-file** option in order to support larger amounts of zones which should be forwarded to another nameserver ([commit 963](http://wiki.powerdns.com/projects/trac/changeset/963)).
+- Both **forward-zones** and **forward-zones-file** can now specify multiple forwarders per domain, implemented in [commit 1168](http://wiki.powerdns.com/projects/trac/changeset/1168), closing [ticket 81](https://github.com/PowerDNS/pdns/issues/81). Additionally, both these settings can also specify non-standard port numbers, as suggested in ticket [ticket 122](https://github.com/PowerDNS/pdns/issues/122). Patch authored by Aaron Thompson, with additional work by Augie Schwer.
+- Sten Spans contributed **allow-from-file**, implemented in [commit 1150](http://wiki.powerdns.com/projects/trac/changeset/1150). This feature allows the Recursor to read access rules from a (large) file.
+
+## General improvements
+- Ruben Kerkhof fixed up weird permission bits as well as our SGML documentation code in [commit 936](http://wiki.powerdns.com/projects/trac/changeset/936) and [commit 937](http://wiki.powerdns.com/projects/trac/changeset/937).
+- Full IPv6 parity. If configured to use IPv6 for outgoing queries (using **query-local-address6=::0** for example), IPv6 and IPv4 addresses are finally treated 100% identically, instead of 'mostly'. This feature is implemented using 'ANY' queries to find A and AAAA addresses in one query, which is a new approach. Treat with caution.
+- Now perform EDNS0 root refreshing queries, so as to benefit from all returned addresses. Relevant since early February 2008 when the root-servers started to respond with IPv6 addresses, which made the default non-EDNS0 maximum packet length reply no longer contain all records. Implemented in [commit 1130](http://wiki.powerdns.com/projects/trac/changeset/1130). Thanks to dns-operations AT mail.oarc.isc.org for quick suggestions on how to deal with this change.
+- **rec\_control** now has a timeout in case the Recursor does not respond. Implemented in [commit 945](http://wiki.powerdns.com/projects/trac/changeset/945).
+- (Error) messages are now logged with saner priorities ([commit 955](http://wiki.powerdns.com/projects/trac/changeset/955)).
+- Outbound query IP interface stemmed from 1997 (!) and was in dire need of a cleanup ([commit 1117](http://wiki.powerdns.com/projects/trac/changeset/1117)).
+- L.ROOT-SERVERS.NET moved ([commit 1118](http://wiki.powerdns.com/projects/trac/changeset/1118)).
+
+# PowerDNS Authoritative Server version 2.9.21
+Released the 21st of April 2007.
+
+This is the first release the PowerDNS Authoritative Server since the Recursor was split off to a separate product, and also marks the transfer of the new technology developed specifically for the recursor, back to the authoritative server.
+
+This move has reduced the amount of code of the Authoritative server by over 2000 lines, while improving the quality of the program enormously.
+
+However, since so much has been changed, care should be taken when deploying 2.9.21.
+
+To signify the magnitude of the underlying improvements, the next release of the PowerDNS Authoritative Server will be called 3.0.
+
+This release would not have been possible without large amounts of help and support from the PowerDNS Community. We specifically want to thank Massimo Bandinelli of Italy's [Register.it](http://register.it), [Dave Aaldering of Aaldering ICT](http://aaldering-ict.nl), [True BV](http://true.nl), [XS4ALL](http://www.xs4all.nl), Daniel Bilik of [Neosystem](http://www.neosystem.cz), [EasyDNS](http://www.easydns.com), [Heinrich Ruthensteiner](http://www.siemens.com) of Siemens, [Augie Schwer](http://schwer.us), [Mark Bergsma](http://www.wikipedia.org), [Marco Davids](http://www.forfun.net), [Marcus Rueckert of OpenSUSE](http://www.opensuse.org), Andre Muraro of [Locaweb](http://www.locaweb.com.br), Antony Lesuisse, [Norbert Sendetzky](http://www.linuxnetworks.de), [Marco Chiavacci](http://www.aruba.it), Christoph Haas, Ralf van der Enden and Ruben Kerkhof.
+
+## Security issues
+- The previous packet parsing and generating code contained no known bugs, but was however very lengthy and overly complex, and might have had security problems. The new code is 'inherently safe' because it relies on bounds-checking C++ constructs. Therefore, a move to 2.9.21 is highly recommended.
+- Pre-2.9.21, communication between master and server nameservers was not checked as rigidly as possible, possibly allowing third parties to disrupt but not modify such communications.
+
+**Warning**: The 'bind1' legacy version of our BIND backend has been dropped! There should be no need to rely on this old version anymore, as the main BIND backend has been very well tested recently.
+
+## Bugs
+- Multi-part TXT records weren't supported. This has been fixed, and regression tests have been added. Code in commits [1016](http://wiki.powerdns.com/projects/trac/changeset/1016), [996](http://wiki.powerdns.com/projects/trac/changeset/996), [994](http://wiki.powerdns.com/projects/trac/changeset/994).
+- Email addresses with embedded dots in SOA records were not parsed correctly, nor were other embedded dots. Noted by 'Bastiaan', fixed in [commit 1026](http://wiki.powerdns.com/projects/trac/changeset/1026).
+- BIND backend treated the 'm' TTL modifier as 'months' and not 'minutes'. Closes Debian bug 406462. Addressed in [commit 1026](http://wiki.powerdns.com/projects/trac/changeset/1026).
+- Our snapshots were built against a static version of PostgreSQL that was incompatible with many Linux distributions, leading to instant crashes on startup. Fixed in [1022](http://wiki.powerdns.com/projects/trac/changeset/1022) and [1023](http://wiki.powerdns.com/projects/trac/changeset/1023).
+- CNAME referrals to child zones gave improper responses. Noted by Augie Schwer in [ticket 123](https://github.com/PowerDNS/pdns/issues/123), fixed in [commit 992](http://wiki.powerdns.com/projects/trac/changeset/992).
+- When passing a port number with the **recursor** setting, this would sometimes generate errors during additional processing. Switched off overly helpful additional processing for recursive queries to remove this problem. Implemented in [commit 1031](http://wiki.powerdns.com/projects/trac/changeset/1031), spotted by Ralf van der Enden.
+- NS to a nameserver with the name of the zone itself generated problems. Spotted by Augie Schwer, fixed in [commit 947](http://wiki.powerdns.com/projects/trac/changeset/947).
+- Multi-line records in the BIND backend were not always parsed correctly. Fixed in [commit 1014](http://wiki.powerdns.com/projects/trac/changeset/1014).
+- The LOC-record had problems operating outside of the eastern hemisphere of the northern part of the world! Fixed in [commit 1011](http://wiki.powerdns.com/projects/trac/changeset/1011).
+- Backends were compiled without multithreading preprocessor flags. As far as we can determine, this would only cause problems for the BIND backend, but we cannot rule out this caused instability in other backends. Fixed in [commit 1001](http://wiki.powerdns.com/projects/trac/changeset/1001).
+- The BIND backend was highly unstable under reloads, and leaked memory and file descriptors. Thanks to Mark Bergsma and Massimo Bandinelli for respectively pointing this out to us and testing large amounts of patches to fix the problem. The fixes have resulted in better performance, less code, and a remarkable simplification of this backend. Commits [1039](http://wiki.powerdns.com/projects/trac/changeset/1039), [1034](http://wiki.powerdns.com/projects/trac/changeset/1034), [1035](http://wiki.powerdns.com/projects/trac/changeset/1035), [1006](http://wiki.powerdns.com/projects/trac/changeset/1006), [999](http://wiki.powerdns.com/projects/trac/changeset/999), [905](http://wiki.powerdns.com/projects/trac/changeset/905) and previous.
+- BIND backend gave convincing NXDOMAINs on unloaded zones in some cases. Spotted and fixed by Daniel Bilik in [commit 984](http://wiki.powerdns.com/projects/trac/changeset/984).
+- SOA records in zone transfers sometimes contained the wrong SOA TTL. Spotted by Christian Kuehn, fixed in [commit 902](http://wiki.powerdns.com/projects/trac/changeset/902).
+- PowerDNS could get confused by very high SOA serial numbers. Spotted and fixed by Dan Bilik, fixed in [commit 626](http://wiki.powerdns.com/projects/trac/changeset/626).
+- Some versions of FreeBSD perform very strict checks on socket address sizes passed to 'connect', which could lead to problems retrieving zones over AXFR. Fixed in [commit 891](http://wiki.powerdns.com/projects/trac/changeset/891).
+- Some versions of FreeBSD perform very strict checks on IPv6 socket addresses, leading to problems. Discovered by Sten Spans, fixed in [commit 885](http://wiki.powerdns.com/projects/trac/changeset/885) and [commit 886](http://wiki.powerdns.com/projects/trac/changeset/886).
+- IXFR requests were not logged properly. Noted by Ralf van der Enden, fixed in [commit 990](http://wiki.powerdns.com/projects/trac/changeset/990).
+- Some NAPTR records needed an additional space character to encode correctly. Spotted by Heinrich Ruthensteiner, fixed in [commit 1029](http://wiki.powerdns.com/projects/trac/changeset/1029).
+- Many bugs in the TCP nameserver, leading to a PowerDNS process that did not respond to TCP queries over time. Many fixes provided by Dan Bilik, other problems were fixed by rewriting our TCP handling code. Commits [982](http://wiki.powerdns.com/projects/trac/changeset/982) and [980](http://wiki.powerdns.com/projects/trac/changeset/980), [950](http://wiki.powerdns.com/projects/trac/changeset/950), [924](http://wiki.powerdns.com/projects/trac/changeset/924), [889](http://wiki.powerdns.com/projects/trac/changeset/889), [874](http://wiki.powerdns.com/projects/trac/changeset/874), [869](http://wiki.powerdns.com/projects/trac/changeset/869), [685](http://wiki.powerdns.com/projects/trac/changeset/685), [684](http://wiki.powerdns.com/projects/trac/changeset/684).
+- Fix crashes on the ARM processor due to alignment errors. Thanks to Sjoerd Simons. Closes Debian bug 397031.
+- Missing data in generic SQL backends would sometimes lead to faked SOA serial data. Spotted by Leander Lakkas from True. Fix in [commit 866](http://wiki.powerdns.com/projects/trac/changeset/866).
+- When receiving two quick notifications in succession, the packet cache would sometimes "process" the second one, leading PowerDNS to ignore it. Spotted by Dan Bilik, fixed in [commit 686](http://wiki.powerdns.com/projects/trac/changeset/686).
+- Geobackend (by Mark Bergsma) did not properly override the getSOA method, breaking non-overlay operation of this fine backend. The geobackend now also skips '.hidden' configuration files, and now properly disregards empty configuration files. Additionally, the overlapping abilities were improved. Details available in [commit 876](http://wiki.powerdns.com/projects/trac/changeset/876), by Mark.
+
+## Features
+- Thanks to [EasyDNS](http://www.easydns.com), PowerDNS now supports multiple masters per domain. For configuration details, see [Slave operation](authoritative/modes-of-operation.md#slave-operation "Slave operation"). Implemented in [commit 1018](http://wiki.powerdns.com/projects/trac/changeset/1018), [commit 1017](http://wiki.powerdns.com/projects/trac/changeset/1017).
+- Thanks to [EasyDNS](http://www.easydns.com), PowerDNS now supports the KEY record type, as well the SPF record. In [commit 976](http://wiki.powerdns.com/projects/trac/changeset/976).
+- Added support for CERT, SSHFP, DNSKEY, DS, NSEC, RRSIG record types, as part of the move to the new DNS parsing/generating code.
+- Support for the AFSDB record type, as requested by 'Bastian'. Implemented in [commit 978](http://wiki.powerdns.com/projects/trac/changeset/978), closing [ticket 129](https://github.com/PowerDNS/pdns/issues/129).
+- Support for the MR record type. Implemented in [commit 941](http://wiki.powerdns.com/projects/trac/changeset/941) and [commit 1019](http://wiki.powerdns.com/projects/trac/changeset/1019).
+- Gsqlite3 backend was added by Antony Lesuisse in [commit 942](http://wiki.powerdns.com/projects/trac/changeset/942);
+- Added the ability to send out light-weight root-referrals that save bandwidth yet still placate mediocre resolver implementations. Implemented in [commit 912](http://wiki.powerdns.com/projects/trac/changeset/912), enable with 'root-referral=lean'.
+
+## Improvements
+- Miscellaneous OpenDBX and LDAP backend improvements by Norbert Sendetzky. Applied in [commit 977](http://wiki.powerdns.com/projects/trac/changeset/977) and [commit 1040](http://wiki.powerdns.com/projects/trac/changeset/1040).
+- SGML source of the documentation was cleaned up by Ruben Kerkhof in [commit 936](http://wiki.powerdns.com/projects/trac/changeset/936).
+- Speedups in core DNS label processing code. Implemented in [commit 928](http://wiki.powerdns.com/projects/trac/changeset/928), [commit 654](http://wiki.powerdns.com/projects/trac/changeset/654), [commit 1020](http://wiki.powerdns.com/projects/trac/changeset/1020).
+- When communicating with master servers and encountering errors, more useful details are logged. Reported by Stefan Arentz in [ticket 137](https://github.com/PowerDNS/pdns/issues/137), closed by [commit 1015](http://wiki.powerdns.com/projects/trac/changeset/1015).
+- Database errors are now logged with more details. Addressed in [commit 1004](http://wiki.powerdns.com/projects/trac/changeset/1004).
+- pdns\_control problems are now logged more verbosely. Change in [commit 910](http://wiki.powerdns.com/projects/trac/changeset/910).
+- Erroneous address configuration was logged unclearly. Spotted by River Tarnell, fixed in [commit 888](http://wiki.powerdns.com/projects/trac/changeset/888).
+- Example configuration shipped with PowerDNS was very old. Noted by Leen Besselink, fixed in [commit 946](http://wiki.powerdns.com/projects/trac/changeset/946).
+- PowerDNS neglected to chdir to the root when chrooted. This closes [ticket 110](https://github.com/PowerDNS/pdns/issues/110), fixed in [commit 944](http://wiki.powerdns.com/projects/trac/changeset/944).
+- Microsoft resolver had problems with responses we generated for CNAMEs pointing out of our bailiwick. Fixed in [commit 983](http://wiki.powerdns.com/projects/trac/changeset/983) and expedited by Locaweb.com.br.
+- Built-in webserver logs errors more verbosely. Closes [ticket 82](https://github.com/PowerDNS/pdns/issues/82), fixed in [commit 991](http://wiki.powerdns.com/projects/trac/changeset/991).
+- Queries containing '@' no longer flood the logs. Addressed in [commit 1014](http://wiki.powerdns.com/projects/trac/changeset/1014).
+- The build process now looks for PostgreSQL in more places. Implemented in [commit 998](http://wiki.powerdns.com/projects/trac/changeset/998), closes [ticket 90](https://github.com/PowerDNS/pdns/issues/90).
+- Speedups in the BIND backend now mean large installations enjoy startup times up to 30 times faster than with the original BIND nameserver. Many thanks to Massimo Bandinelli.
+- BIND backend now offers full support for query logging, implemented in [commit 1026](http://wiki.powerdns.com/projects/trac/changeset/1026), [commit 1029](http://wiki.powerdns.com/projects/trac/changeset/1029).
+- BIND backend named.conf parsing is now fully case-insensitive for domain names. This closes Debian bug 406461, fixed in [commit 1027](http://wiki.powerdns.com/projects/trac/changeset/1027).
+- IPv6 and IPv4 address parsing routines have been replaced, which should result in prettier output in some cases. [commit 962](http://wiki.powerdns.com/projects/trac/changeset/962), [commit 1012](http://wiki.powerdns.com/projects/trac/changeset/1012) and others.
+- 5 new regression tests have been added to insure old bugs do not return.
+- Fix small issues with very modern compilers and BOOST snapshots. Noted by Marcus Rueckert, addressed in [commit 954](http://wiki.powerdns.com/projects/trac/changeset/954), [commit 964](http://wiki.powerdns.com/projects/trac/changeset/964) [commit 965](http://wiki.powerdns.com/projects/trac/changeset/965), [commit 1003](http://wiki.powerdns.com/projects/trac/changeset/1003).
+
+# Recursor version 3.1.4
+Released the 13th of November 2006.
+
+This release contains almost no new features, but consists mostly of minor and major bug fixes. It also addresses two major security issues, which makes this release a highly recommended upgrade.
+
+## Security issues
+- Large TCP questions followed by garbage could cause the recursor to crash. This critical security issue has been assigned CVE-2006-4251, and is fixed in [commit 915](http://wiki.powerdns.com/projects/trac/changeset/915). More information can be found in [Section 5, “PowerDNS Security Advisory 2006-01: Malformed TCP queries can lead to a buffer overflow which might be exploitable”](security/powerdns-advisory-2006-01.md "5. PowerDNS Security Advisory 2006-01: Malformed TCP queries can lead to a buffer overflow which might be exploitable").
+- CNAME loops with zero second TTLs could cause crashes in some conditions. These loops could be constructed by malicious parties, making this issue a potential denial of service attack. This security issue has been assigned CVE-2006-4252 and is fixed by [commit 919](http://wiki.powerdns.com/projects/trac/changeset/919). More information can be found in [Section 6, “PowerDNS Security Advisory 2006-02: Zero second CNAME TTLs can make PowerDNS exhaust allocated stack space, and crash”](security/powerdns-advisory-2006-02.md "PowerDNS Security Advisory 2006-02: Zero second CNAME TTLs can make PowerDNS exhaust allocated stack space, and crash"). Many thanks to David Gavarret for helping pin down this problem.
+
+## Bugs
+- On certain error conditions, PowerDNS would neglect to close a socket, which might therefore eventually run out. Spotted by Stefan Schmidt, fixed in commits [892](http://wiki.powerdns.com/projects/trac/changeset/892), [897](http://wiki.powerdns.com/projects/trac/changeset/897), [899](http://wiki.powerdns.com/projects/trac/changeset/899).
+- Some nameservers (including PowerDNS in rare circumstances) emit a SOA record in the authority section. The recursor mistakenly interpreted this as an authoritative "NXRRSET". Spotted by Bryan Seitz, fixed in [commit 893](http://wiki.powerdns.com/projects/trac/changeset/893).
+- In some circumstances, PowerDNS could end up with a useless (not working, or no longer working) set of nameserver records for a domain. This release contains logic to invalidate such broken NSSETs, without overloading authoritative servers. This problem had previously been spotted by Bryan Seitz, 'Cerb' and Darren Gamble. Invalidations of NSSETs can be plotted using the "nsset-invalidations" metric, available through **rec\_control get**. Implemented in [commit 896](http://wiki.powerdns.com/projects/trac/changeset/896) and [commit 901](http://wiki.powerdns.com/projects/trac/changeset/901).
+- PowerDNS could crash while dumping the cache using **rec\_control dump-cache**. Reported by Wouter of WideXS and Stefan Schmidt and many others, fixed in [commit 900](http://wiki.powerdns.com/projects/trac/changeset/900).
+- Under rare circumstances (depleted TCP buffers), PowerDNS might send out incomplete questions to remote servers. Additionally, on big-endian systems (non-Intel and non-AMD generally), sending out large TCP answers questions would not work at all, and possibly crash. Brought to our attention by David Gavarret, fixed in [commit 903](http://wiki.powerdns.com/projects/trac/changeset/903).
+- The recursor contained the potential for a dead-lock processing an invalid domain name. It is not known how this might be triggered, but it has been observed by 'Cerb' on \#powerdns. Several dead-locks where PowerDNS consumed all CPU, but did not answer questions, have been reported in the past few months. These might be fixed by [commit 904](http://wiki.powerdns.com/projects/trac/changeset/904).
+- IPv6 'allow-from' matching had problems with the least significant bits, sometimes allowing disallowed addresses, but mostly disallowing allowed addresses. Spotted by Wouter from WideXS, fixed in [commit 916](http://wiki.powerdns.com/projects/trac/changeset/916).
+
+## Improvements
+- PowerDNS has support to drop answers from so called 'delegation only' zones. A statistic ("dlg-only-drops") is now available to plot how often this happens. Implemented in [commit 890](http://wiki.powerdns.com/projects/trac/changeset/890).
+- Hint-file parameter was mistakenly named "hints-file" in the documentation. Spotted by my Marco Davids, fixed in [commit 898](http://wiki.powerdns.com/projects/trac/changeset/898).
+- **rec\_control quit** should be near instantaneous now, as it no longer meticulously cleans up memory before exiting. Problem spotted by Darren Gamble, fixed in [commit 914](http://wiki.powerdns.com/projects/trac/changeset/914), closing [ticket 84](https://github.com/PowerDNS/pdns/issues/84).
+- init.d script no longer refers to the Recursor as the Authoritative Server. Spotted by Wouter of WideXS, fixed in [commit 913](http://wiki.powerdns.com/projects/trac/changeset/913).
+- A potentially serious warning for users of the GNU C Library version 2.5 was fixed. Spotted by Marcus Rueckert, fixed in [commit 920](http://wiki.powerdns.com/projects/trac/changeset/920).
+
+# Recursor version 3.1.3
+Released the 12th of September 2006.
+
+Compared to 3.1.2, this release again consists of a number of mostly minor bug fixes, and some slight improvements.
+
+Many thanks are again due to Darren Gamble who together with his team has discovered many misconfigured domains that do work with some other name servers. DNS has long been tolerant of misconfigurations, PowerDNS intends to uphold that tradition. Almost all of the domains found by Darren now work as well in PowerDNS as in other name server implementations.
+
+Thanks to some recent migrations, this release, or something very close to it, is powering over 40 million internet connections that we know of. We appreciate hearing about successful as well as unsuccessful migrations, please feel free to notify pdns.bd@powerdns.com of your experiences, good or bad.
+
+## Bug-fixes
+- The MThread default stack size was too small, which led to problems, mostly on 64-bit platforms. This stack size is now configurable using the **stack-size** setting should our estimate be off. Discovered by Darren Gamble, Sten Spans and a number of others. Fixed in [commit 868](http://wiki.powerdns.com/projects/trac/changeset/868).
+- Plug a small memory leak discovered by Kai and Darren Gamble, fixed in [commit 870](http://wiki.powerdns.com/projects/trac/changeset/870).
+- Switch from the excellent nedmalloc to dlmalloc, based on advice by the nedmalloc author. Nedmalloc is optimised for multithreaded operation, whereas the PowerDNS recursor is single threaded. The version of nedmalloc shipped contained a number of possible bugs, which are probably resolved by moving to dlmalloc. Some reported crashes on hitting 2G of allocated memory on 64 bit systems might be solved by this switch, which should also increase performance. See [commit 873](http://wiki.powerdns.com/projects/trac/changeset/873) for details.
+
+## Improvements
+- The cache is now explicitly aware of the difference between authoritative and unauthoritative data, allowing it to deal with some domains that have different data in the parent zone than in the authoritative zone. Patch in [commit 867](http://wiki.powerdns.com/projects/trac/changeset/867).
+- No longer try to parse DNS updates as if they were queries. Discovered and fixed by Jan Gyselinck, fix in [commit 871](http://wiki.powerdns.com/projects/trac/changeset/871).
+- Rebalance logging priorities for less log cluttering and add IP address to a remote server error message. Noticed and fixed by Jan Gyselinck ([commit 877](http://wiki.powerdns.com/projects/trac/changeset/877)).
+- Add **logging-facility** setting, allowing syslog to send PowerDNS logging to a separate file. Added in [commit 871](http://wiki.powerdns.com/projects/trac/changeset/871).
+
+# Recursor version 3.1.2
+Released Monday 26th of June 2006.
+
+Compared to 3.1.1, this release consists almost exclusively of bug-fixes and speedups. A quick update is recommended, as some of the bugs impact operators of authoritative zones on the internet. This version has been tested by some of the largest internet providers on the planet, and is expected to perform well for everybody.
+
+Many thanks are due to Darren Gamble, Stefan Schmidt and Bryan Seitz who all provided excellent feedback based on their large-scale tests of the recursor.
+
+## Bug-fixes
+- Internal authoritative server did not differentiate between 'NXDOMAIN' and 'NXRRSET', in other words, it would answer 'no such host' when an AAAA query came in for a domain that did exist, but did not have an AAAA record. This only affects users with **auth-zones** configured. Discovered by Bryan Seitz, fixed in [commit 848](http://wiki.powerdns.com/projects/trac/changeset/848).
+- ANY queries for hosts where nothing was present in the cache would not work. This did not cause real problems as ANY queries are not reliable (by design) for anything other than debugging, but did slow down the nameserver and cause unnecessary load on remote nameservers. Fixed in [commit 854](http://wiki.powerdns.com/projects/trac/changeset/854).
+- When exceeding the configured maximum amount of TCP sessions, TCP support would break and the nameserver would waste CPU trying to accept TCP connections on UDP ports. Noted by Bryan Seitz, fixed in [commit 849](http://wiki.powerdns.com/projects/trac/changeset/849).
+- DNS queries come in two flavours: recursion desired and non-recursion desired. The latter is not very useful for a recursor, but is sometimes (erroneously) used by monitoring software or load balancers to detect nameserver availability. A non-rd query would not only not recurse, but also not query authoritative zones, which is confusing. Fixed in [commit 847](http://wiki.powerdns.com/projects/trac/changeset/847).
+- Non-standard DNS TCP queries, that did occur however, could drive the recursor to 100% CPU usage for extended periods of time. This did not disrupt service immediately, but does waste a lot of CPU, possibly exhausting resources. Discovered by Bryan Seitz, fixed in [commit 858](http://wiki.powerdns.com/projects/trac/changeset/858), which is post-3.1.2-rc1.
+- The PowerDNS recursor did not honour the rare but standardised 'ANY' query class (normally 'ANY' refers to the query type, not class), upsetting the Wildfire Jabber server. Discovered and debugged by Daniel Nauck, fixed in [commit 859](http://wiki.powerdns.com/projects/trac/changeset/859), which is post-3.1.2-rc1.
+- Everybody's favorite, when starting up under high load, a bogus line of statistics was sometimes logged. Fixed in [commit 851](http://wiki.powerdns.com/projects/trac/changeset/851).
+- Remove some spurious debugging output on dropping a packet by an unauthorized host. Discovered by Kai. Fixed in [commit 854](http://wiki.powerdns.com/projects/trac/changeset/854).
+
+## Improvements
+- Misconfigured domains, with a broken nameserver in the parent zone, should now work better. Changes motivated and suggested by Darren Gamble. This makes PowerDNS more compliant with RFC 2181 by making it prefer authoritative data over non-authoritative data. Implemented in [commit 856](http://wiki.powerdns.com/projects/trac/changeset/856).
+- PowerDNS can now listen on multiple ports, using the **local-address** setting. Added in [commit 845](http://wiki.powerdns.com/projects/trac/changeset/845).
+- A number of speedups which should have a noticeable impact, implemented in commits [850](http://wiki.powerdns.com/projects/trac/changeset/850), [852](http://wiki.powerdns.com/projects/trac/changeset/852), [853](http://wiki.powerdns.com/projects/trac/changeset/853), [855](http://wiki.powerdns.com/projects/trac/changeset/855)
+- The recursor now works around an issue with the Linux kernel 2.6.8, as shipped by Debian. Fixed by Christof Meerwald in [commit 860](http://wiki.powerdns.com/projects/trac/changeset/860), which is post 3.1.2-rc1.
+
+# Recursor version 3.1.1
+Released on the 23rd of May 2006.
+
+**Warning**: 3.1.1 is identical to 3.1 except for a bug in the packet chaining code which would mainly manifest itself for IPv6 enabled Konqueror users with very fast connections to their PowerDNS installation. However, all 3.1 users are urged to upgrade to 3.1.1. Many thanks to Alessandro Bono for his quick aid in solving this problem.
+
+ Many thanks are due to the operators of some of the largest internet access providers in the world, each having many millions of customers, who have tested the various 3.1 pre-releases for suitability. They have uncovered and helped fix bugs that could impact us all, but are only (quickly) noticeable with such vast amounts of DNS traffic.
+
+After version 3.0.1 has proved to hold up very well under tremendous loads, 3.1 adds important new features
+
+- Ability to serve authoritative data from 'BIND' style zone files (using **auth-zones** statement).
+- Ability to forward domains so configured to external servers (using **forward-zones**).
+- Possibility of 'serving' the contents of `/etc/hosts` over DNS, which is very well suited to simple domestic router/DNS setups. Enabled using **export-etc-hosts**.
+- As recommended by recent standards documents, the PowerDNS recursor is now authoritative for RFC-1918 private IP space zones by default (suggested by Paul Vixie).
+- Full outgoing IPv6 support (off by default) with IPv6 servers getting equal treatment with IPv4, nameserver addresses are chosen based on average response speed, irrespective of protocol.
+- Initial Windows support, including running as a service ('NET START "POWERDNS RECURSOR"'). **rec\_channel** is still missing, the rest should work. Performance appears to be below that of the UNIX versions, this situation is expected to improve.
+
+## Bug fixes
+- No longer send out SRV and MX record priorities as zero on big-endian platforms (UltraSPARC). Discovered by Eric Sproul, fixed in [commit 773](http://wiki.powerdns.com/projects/trac/changeset/773).
+- SRV records need additional processing, especially in an Active Directory setting. Reported by Kenneth Marshall, fixed in [commit 774](http://wiki.powerdns.com/projects/trac/changeset/774).
+- The root-records were not being refreshed, which could lead to problems under inconceivable conditions. Fixed in [commit 780](http://wiki.powerdns.com/projects/trac/changeset/780).
+- Fix resolving domain names for nameservers with multiple IP addresses, with one of these addresses being lame. Other nameserver implementations were also unable to resolve these domains, so not a big bug. Fixed in [commit 780](http://wiki.powerdns.com/projects/trac/changeset/780).
+- For a period of 5 minutes after expiring a negative cache entry, the domain would not be re-cached negatively, leading to a lot of duplicate outgoing queries for this short period. This fix has raised the average cache hit rate of the recursor by a few percent. Fixed in [commit 783](http://wiki.powerdns.com/projects/trac/changeset/783).
+- Query throttling was not aggressive enough and not all sorts of queries were throttled. Implemented in [commit 786](http://wiki.powerdns.com/projects/trac/changeset/786).
+- Fix possible crash during startup when parsing empty configuration lines ([commit 807](http://wiki.powerdns.com/projects/trac/changeset/807)).
+- Fix possible crash when the first query after wiping a cache entry was for the just deleted entry. Rare in production servers. Fixed in [commit 820](http://wiki.powerdns.com/projects/trac/changeset/820).
+- Recursor would send out differing TTLs when receiving a misconfigured, standards violating, RRSET with different TTLs. Implement fix as mandated by RFC 2181, paragraph 5.2. Reported by Stephen Harker ([commit 819](http://wiki.powerdns.com/projects/trac/changeset/819)).
+- The **top-remotes** would list remotes more than once, once per source port. Discovered by Jorn Ekkelenkamp, fixed in [commit 827](http://wiki.powerdns.com/projects/trac/changeset/827), which is post 3.1-pre1.
+- Default **allow-from** allowed queries from fe80::/16, corrected to fe80::/10. Spotted by Niels Bakker, fixed in [commit 829](http://wiki.powerdns.com/projects/trac/changeset/829), which is post 3.1-pre1.
+- While PowerDNS blocks failing queries quickly, multiple packets could briefly be in flight for the same domain and nameserver. This situation is now explicitly detected and queries are chained to identical queries already in flight. Fixed in [commit 833](http://wiki.powerdns.com/projects/trac/changeset/833) and [commit 834](http://wiki.powerdns.com/projects/trac/changeset/834), post 3.1-pre1.
+
+## Improvements
+- ANY queries are now implemented as in other nameserver implementations, leading to a decrease in outgoing queries. The RFCs are not very clear on desired behaviour, what is implemented now saves bandwidth and CPU and brings us in line with existing practice. Previously ANY queries were not cached by the PowerDNS recursor. Implemented in [commit 784](http://wiki.powerdns.com/projects/trac/changeset/784).
+- **rec\_control** was very sparse in its error reporting, and user unfriendly as well. Reported by Erik Bos, fixed in [commit 818](http://wiki.powerdns.com/projects/trac/changeset/818) and [commit 820](http://wiki.powerdns.com/projects/trac/changeset/820).
+- IPv6 addresses were printed in a non-standard way, fixed in [commit 788](http://wiki.powerdns.com/projects/trac/changeset/788).
+- TTLs of records are now capped at two weeks, [commit 820](http://wiki.powerdns.com/projects/trac/changeset/820).
+- **allow-from** IPv4 netmasks now automatically work for IP4-to-IPv6 mapper IPv4 addresses, which appear when running on the wildcard **::** IPv6 address. Lack of feature noted by Marcus 'darix' Rueckert. Fixed in [commit 826](http://wiki.powerdns.com/projects/trac/changeset/826), which is post 3.1-pre1.
+- Errors before daemonizing are now also sent to syslog. Suggested by Marcus 'darix' Rueckert. Fixed in [commit 825](http://wiki.powerdns.com/projects/trac/changeset/825), which is post 3.1-pre1.
+- When launching without any form of configured network connectivity, all root-servers would be cached as 'down' for some time. Detect this special case and treat it as a resource-constraint, which is not accounted against specific nameservers. Spotted by Seth Arnold, fixed in [commit 835](http://wiki.powerdns.com/projects/trac/changeset/835), which is post 3.1-pre1.
+- The recursor now does not allow authoritative servers to keep supplying its own NS records into perpetuity, which causes problems when a domain is redelegated but the old authoritative servers are not updated to this effect. Noticed and explained at length by Darren Gamble of Shaw Communications, addressed by [commit 837](http://wiki.powerdns.com/projects/trac/changeset/837), which is post 3.1-pre2.
+- Some operators may want to follow RFC 2181 paragraph 5.2 and 5.4. This harms performance and does not solve any real problem, but does make PowerDNS more compliant. If you want this, enable **auth-can-lower-ttl**. Implemented in [commit 838](http://wiki.powerdns.com/projects/trac/changeset/838), which is post 3.1-pre2.
+
+# Recursor version 3.0.1
+Released 25th of April 2006, [download](http://www.powerdns.com/en/downloads.aspx).
+
+This release consists of nothing but tiny fixes to 3.0, including one with security implications. An upgrade is highly recommended.
+
+- Compilation used both `cc` and `gcc`, leading to the possibility of compiling with different compiler versions ([commit 766](http://wiki.powerdns.com/projects/trac/changeset/766)).
+- **rec\_control** would leave files named `lsockXXXXXX` around in the configured socket-dir. Operators may wish to remove these files from their socket-dir (often `/var/run`), quite a few might have accumulated already ([commit 767](http://wiki.powerdns.com/projects/trac/changeset/767)).
+- Certain malformed packets could crash the recursor. As far as we can determine these packets could only lead to a crash, but as always, there are no guarantees. A quick upgrade is highly recommended (commits [760](http://wiki.powerdns.com/projects/trac/changeset/760), [761](http://wiki.powerdns.com/projects/trac/changeset/761)). Reported by David Gavarret.
+- Recursor would not distinguish between NXDOMAIN and NXRRSET ([commit 756](http://wiki.powerdns.com/projects/trac/changeset/756)). Reported and debugged by Jorn Ekkelenkamp.
+- Some error messages and trace logging statements were improved (commits [756](http://wiki.powerdns.com/projects/trac/changeset/756), [758](http://wiki.powerdns.com/projects/trac/changeset/758), [759](http://wiki.powerdns.com/projects/trac/changeset/759)).
+- stderr was closed during daemonizing, but not dupped to /dev/null, leading to slight chance of odd behaviour on reporting errors ([commit 757](http://wiki.powerdns.com/projects/trac/changeset/757))
+
+## Operating system specific fixes
+- The stock Debian sarge Linux kernel, 2.6.8, claims to support epoll but fails at runtime. The epoll self-testing code has been improved, and PowerDNS will fall back to a select based multiplexer if needed ([commit 758](http://wiki.powerdns.com/projects/trac/changeset/758)) Reported by Michiel van Es.
+- Solaris 8 compilation and runtime issues were addressed. See the README for details ([commit 765](http://wiki.powerdns.com/projects/trac/changeset/765)). Reported by Juergen Georgi and Kenneth Marshall.
+- Solaris 10 x86\_64 compilation issues were addressed ([commit 755](http://wiki.powerdns.com/projects/trac/changeset/755)). Reported and debugged by Eric Sproul.
+
+# Recursor version 3.0
+Released 20th of April 2006, [download](http://www.powerdns.com/en/downloads.aspx).
+
+This is the first separate release of the PowerDNS Recursor. There are many reasons for this, one of the most important ones is that previously we could only do a release when both the recursor and the authoritative nameserver were fully tested and in good shape. The split allows us to release new versions when each part is ready.
+
+Now for the real news. This version of the PowerDNS recursor powers the network access of over two million internet connections. Two large access providers have been running pre-releases of 3.0 for the past few weeks and results are good. Furthermore, the various pre-releases have been tested nearly non-stop with DNS traffic replayed at 3000 queries/second.
+
+As expected, the 2 million households shook out some very rare bugs. But even a rare bug happens once in a while when there are this many users.
+
+We consider this version of the PowerDNS recursor to be the most advanced resolver publicly available. Given current levels of spam, phishing and other forms of internet crime we think no recursor should offer less than the best in spoofing protection. We urge all operators of resolvers without proper spoofing countermeasures to consider PowerDNS, as it is a Better Internet Nameserver Daemon.
+
+A good article on DNS spoofing can be found [here](http://www.securesphere.net/download/papers/dnsspoof.htm). Some more information, based on a previous version of PowerDNS, can be found on the [PowerDNS development blog](http://blog.netherlabs.nl/articles/2006/04/14/holy-cow-1-3-million-additional-ip-addresses-served-by-powerdns).
+
+**Warning**: Because of recent DNS based denial of service attacks, running an open recursor has become a security risk. Therefore, unless configured otherwise this version of PowerDNS will only listen on localhost, which means it does not resolve for hosts on your network. To fix, configure the **local-address** setting with all addresses you want to listen on. Additionally, by default service is restricted to RFC 1918 private IP addresses. Use **allow-from** to selectively open up the recursor for your own network. See [pdns\_recursor settings](recursor/settings.md#allow-from "pdns_recursor settings") for details.
+
+## Important new features of the PowerDNS recursor 3.0
+- Best spoofing protection and detection we know of. Not only is spoofing made harder by using a new network address for each query, PowerDNS detects when an attempt is made to spoof it, and temporarily ignores the data. For details, see [Anti-spoofing](recursor/security.md "Anti-spoofing").
+- First nameserver to benefit from epoll/kqueue/Solaris completion ports event reporting framework, for stellar performance.
+- Best statistics of any recursing nameserver we know of, see [Statistics](recursor/stats.md "Statistics").
+- Last-recently-used based cache cleanup algorithm, keeping the 'best' records in memory
+- First class Solaris support, built on a 'try and buy' Sun CoolThreads T 2000.
+- Full IPv6 support, implemented natively.
+- Access filtering, both for IPv4 and IPv6.
+- Experimental SMP support for nearly double performance. See [PowerDNS Recursor performance](recursor/performance.md "PowerDNS Recursor performance").
+
+Many people helped package and test this release. Jorn Ekkelenkamp of ISP-Services helped find the '8000 SOAs' bug and spotted many other oddities and [XS4ALL](http://www.xs4all.nl) internet funded a lot of the recent development. Joaquín M López Muñoz of the boost::multi\_index\_container was again of great help.
+
+# Version 2.9.20
+Released the 15th of March 2006
+
+Besides adding OpenDBX, this release is mostly about fixing problems and speeding up the recursor. This release has been made possible by [XS4ALL](http://www.xs4all.nl) and [True](http://true.nl). Thanks!
+
+Furthermore, we are very grateful for the help of Andrew Pinski, who hacks on gcc, and of Joaquín M López Muñoz, the author of [boost::multi\_index\_container](http://www.boost.org/libs/multi_index/doc/index.html). Without their near-realtime help this release would've been delayed a lot. Thanks!
+
+## Bugs fixed in the recursor
+- Possible stability issues in the recursor on encountering errors ([commit 532](http://wiki.powerdns.com/projects/trac/changeset/532), [commit 533](http://wiki.powerdns.com/projects/trac/changeset/533))
+- Memory leaks in recursor fixed ([commit 534](http://wiki.powerdns.com/projects/trac/changeset/534), [commit 572](http://wiki.powerdns.com/projects/trac/changeset/572)). In a test 800 million real life DNS packets have been sent to the recursor, representing several days of traffic from a major ISP, memory use was high (500MB), but stable.
+- Prune all data in PowerDNS - previously per-nameserver and per-query performance statistics were kept around forever ([commit 535](http://wiki.powerdns.com/projects/trac/changeset/535))
+- IPv6 additional processing was broken. Reported by Lionel Elie Mamane, who also provided a fix. The problem was fixed differently in the end. [commit 562](http://wiki.powerdns.com/projects/trac/changeset/562).
+- pdns\_recursor did not shuffle answers since 2.9.19, leading to problems sending mail to the Hotmail servers. Reported in [ticket 54](https://github.com/PowerDNS/pdns/issues/54), fixed in [commit 567](http://wiki.powerdns.com/projects/trac/changeset/567).
+- If a single nameserver had multiple IP addresses listed, PowerDNS would only use one of them. Noted by Mark Martin, fixed in [commit 570](http://wiki.powerdns.com/projects/trac/changeset/570), who depends on a domain with 4 nameserver IP addresses of which 2 are broken.
+
+## Improvements to the recursor
+- Commits [535](http://wiki.powerdns.com/projects/trac/changeset/535), [540](http://wiki.powerdns.com/projects/trac/changeset/540), [541](http://wiki.powerdns.com/projects/trac/changeset/541), [542](http://wiki.powerdns.com/projects/trac/changeset/542), [543](http://wiki.powerdns.com/projects/trac/changeset/543), [544](http://wiki.powerdns.com/projects/trac/changeset/544), [545](http://wiki.powerdns.com/projects/trac/changeset/545), [547](http://wiki.powerdns.com/projects/trac/changeset/547) and [548](http://wiki.powerdns.com/projects/trac/changeset/548), [574](http://wiki.powerdns.com/projects/trac/changeset/574) all speed up the recursor by a large factor, without altering the DNS algorithm.
+- Move recursor to the incredible boost::multi\_index\_container ([commit 580](http://wiki.powerdns.com/projects/trac/changeset/580)). This brings a huge improvement in cache pruning times.
+- [commit 549](http://wiki.powerdns.com/projects/trac/changeset/549) and [commit 550](http://wiki.powerdns.com/projects/trac/changeset/550) work around gcc bug [24704](http://gcc.gnu.org/bugzilla/show_bug.cgi?id=24704) if requested, which speeds up the recursor a lot, but involves a dirty hack. Enable with **./configure --enable-gcc-skip-locking**. No guarantees!
+
+## Bugs fixed in the authoritative nameserver
+- PowerDNS would no longer allow a '/' in domain names, fixed by [commit 537](http://wiki.powerdns.com/projects/trac/changeset/537), reported in [ticket 48](https://github.com/PowerDNS/pdns/issues/48).
+- Parameters to **pdns\_control notify-host** were not checked, leading to possible crashes. Reported in [ticket 24](https://github.com/PowerDNS/pdns/issues/24), fixed in [commit 565](http://wiki.powerdns.com/projects/trac/changeset/565).
+- On some compilers, processing of NAPTR records could cause the server to crash. Reported by Bernd Froemel in [ticket 29](https://github.com/PowerDNS/pdns/issues/29), fixed in [commit 538](http://wiki.powerdns.com/projects/trac/changeset/538).
+- Backend errors could make the whole nameserver exit under some circumstances, notably using the LDAP backend. Fixed in [commit 583](http://wiki.powerdns.com/projects/trac/changeset/583), reported in [ticket 62](https://github.com/PowerDNS/pdns/issues/62).
+- Referrals were subtly broken by recent CNAME/Wildcard improvements, fixed in [commit 539](http://wiki.powerdns.com/projects/trac/changeset/539). Fix and other improvements sponsored by [True](http://true.nl).
+- PowerDNS would try to insert records it has no knowledge about in slave zones, which did not work. Reported in [ticket 60](https://github.com/PowerDNS/pdns/issues/60), fixed in [commit 566](http://wiki.powerdns.com/projects/trac/changeset/566). A superior fix would be to implement the relevant unknown record standard.
+
+## Improvements to the authoritative nameserver
+- Pipebackend did not properly propagate the ABI version to its children, fixed in [commit 546](http://wiki.powerdns.com/projects/trac/changeset/546), reported by kickdaddy@gmail.com in [ticket 45](https://github.com/PowerDNS/pdns/issues/45).
+- [OpenDBX](http://www.linuxnetworks.de/pdnsodbx/index.html) backend added ([commit 559](http://wiki.powerdns.com/projects/trac/changeset/559), [commit 560](http://wiki.powerdns.com/projects/trac/changeset/560), [commit 561](http://wiki.powerdns.com/projects/trac/changeset/561)) by Norbert Sendetzky. From the website: “ The OpenDBX backend enables it to fetch DNS information from every DBMS supported by the OpenDBX library and combines the power of one of the best DNS server implementations with the flexibility of the OpenDBX library. ” OpenDBX adds some other features like database failover. Thanks Norbert!
+- LDAP fixes as reported in [ticket 37](https://github.com/PowerDNS/pdns/issues/37), fixed in [commit 558](http://wiki.powerdns.com/projects/trac/changeset/558), which make **pdns\_control notify** work.
+- Arjo Hooimeijer added support for soa-refresh-default, soa-retry-default, soa-expire-default, which were previously hardcoded. [commit 563](http://wiki.powerdns.com/projects/trac/changeset/563) and fallout in [commit 573](http://wiki.powerdns.com/projects/trac/changeset/573) (thanks to Wolfram Schlich).
+
+## Miscellaneous
+- Fixes for g++ 4.1. Compiling with 4.1 realizes notable speedups. [commit 568](http://wiki.powerdns.com/projects/trac/changeset/568), [commit 569](http://wiki.powerdns.com/projects/trac/changeset/569).
+- PowerDNS now reports if it is running in 32 or 64 bit mode, useful for bi-arch users that need to know if they are benefitting from [AMD's great processor](http://www.amd.com). [commit 571](http://wiki.powerdns.com/projects/trac/changeset/571).
+- **dnsscope** compiles again, [commit 551](http://wiki.powerdns.com/projects/trac/changeset/551), [commit 564](http://wiki.powerdns.com/projects/trac/changeset/564) (FreeBSD 64-bit time\_t).
+- **dnsreplay\_mindex** compiles again, fixed by [commit 572](http://wiki.powerdns.com/projects/trac/changeset/572). Its performance, and the performance of the recursor was improved by [commit 559](http://wiki.powerdns.com/projects/trac/changeset/559).
+- Build scripts were added, mostly for internal use but we know some PowerDNS users build their own packages too. [commit 553](http://wiki.powerdns.com/projects/trac/changeset/553), [commit 554](http://wiki.powerdns.com/projects/trac/changeset/554), [commit 555](http://wiki.powerdns.com/projects/trac/changeset/555), [commit 556](http://wiki.powerdns.com/projects/trac/changeset/556), [commit 557](http://wiki.powerdns.com/projects/trac/changeset/557).
+- `bootstrap` script was not included in release. Thanks to Stefan Arentz for noticing. Fixed in [commit 574](http://wiki.powerdns.com/projects/trac/changeset/574).
+
+# Version 2.9.19
+Released 29th of October 2005.
+
+As with other recent releases, the usage of PowerDNS appears to have skyrocketed. Informal, though strict, measurements show that PowerDNS now powers around 50% of all German domains, and somewhere in the order of 10-15% of the rest of the world. Furthermore, DNS is set to take a central role in connecting Voice over IP providers, with PowerDNS offering a very good feature set for these ENUM deployments. PowerDNS is already powering the E164.info ENUM zone and also acts as the backend for a major VoIP provisioning platform.
+
+Included in this release is the now complete packet parsing/generating, record parsing/generating infrastructure. Furthermore, this framework is used by the recursor, hopefully making it very fast, memory efficient and robust. Many records are now processed using a single line of code. This has made the recursor a lot stricter in packet parsing, you will see some error messages which did not appear before. Rest assured however that these only happen for queries which have no valid answer in any case.
+
+Furthermore, support for DNSSEC records is available in the new infrastructure, although is should be emphasised that there is more to DNSSEC than parsing records. There is no real support for DNSSEC (yet).
+
+Additionally, the BIND Backend has been replaced by what was up to now known as the 'Bind2Backend'. Initial benchmarking appears to show that this backend is faster, uses less memory and has shorter startup times. The code is also shorter.
+
+This release fixes a number of embarrassing bugs and is a recommended upgrade.
+
+Thanks are due to [XS4ALL](http://www.xs4all.nl) who are supporting continuing development of PowerDNS, the fruits of which can be found in this release already. Furthermore, a remarkable number of people have helped report bugs, validate solutions or have submitted entire patches. Many thanks!
+
+## Improvements
+- dnsreplay now has a help message and has received further massive updates, making the code substantially faster. It turns out that dnsreplay is often 'heavier' than the PowerDNS process being benchmarked.
+- PowerDNS recursor no longer prints out its queries by default as most recursor deployments have too much traffic for this to be useful.
+- PowerDNS recursor is now able to read its root-hints from disk, which is useful to operate with alternate roots, like the [Open Root Server Network](http://www.orsn.org). See [PowerDNS Recursor](recursor/index.md).
+- PowerDNS can now send out old-fashioned root-referrals when queried for domains for which it is not authoritative. Wastes some bandwidth but may solve incoming query floods if domains are delegated to you for which you are not authoritative, but which are queried by broken recursors.
+- PowerDNS now prints out a warning when running with legacy LinuxThreads implementation instead of the high performance NPTL library. [commit 455](http://wiki.powerdns.com/projects/trac/changeset/455).
+- A lot of superfluous calls to gettimeofday() have been removed, making PowerDNS and especially the recursor faster. Suggested by Kai.
+- SPF records are now supported natively. [commit 472](http://wiki.powerdns.com/projects/trac/changeset/472), closing [ticket 22](https://github.com/PowerDNS/pdns/issues/22).
+- Improved IPv6 'bound to' messages. Thanks to Niels Bakker, Wichert Akkerman and Gerty de Wolf for suggestions.
+- Separate graphs can now be made of IPv6 queries and answers. [commit 485](http://wiki.powerdns.com/projects/trac/changeset/485).
+- Out of zone additional processing is now on by default to better comply with standards. [commit 487](http://wiki.powerdns.com/projects/trac/changeset/487).
+- Regression tests have been expanded to deal with more record types (SRV, NAPTR, TXT, duplicate SRV).
+- Improved query-logging in Bindbackend, which can be used for debugging purposes.
+- Dropped libpcap dependency, making compilation easier
+- pdns\_control now has a help message.
+- Add RRSIG, DNSKEY, DS and NSEC records for DNSSEC-bis to new parser infrastructure.
+- Recursor now honours EDNS0 allowing it to send out larger answers.
+
+## Bugs fixed
+- Domain name validation has been made a lot stricter - it turns out PostgreSQL was interpreting some (corrupt) domain names as unicode. Tested and suggested by Register.com ([commit 451](http://wiki.powerdns.com/projects/trac/changeset/451)).
+- LDAP backend did not compile (commits [452](http://wiki.powerdns.com/projects/trac/changeset/452), [453](http://wiki.powerdns.com/projects/trac/changeset/453)) due to partially applied patch (Norbert Sendetzky)
+- Incoming zone transfers work reliably again. Fixed in [commit 460](http://wiki.powerdns.com/projects/trac/changeset/460) and beyond. And [commit 523](http://wiki.powerdns.com/projects/trac/changeset/523) - closing Debian bug 330184.
+- Recent g++ versions exposed a mistake in the PowerDNS recursor cache pruning code, causing random crashes. Fixed in [commit 465](http://wiki.powerdns.com/projects/trac/changeset/465). Reported by several Red Hat users.
+- PowerDNS recursor, and MTasker in general, did not work on Solaris. Patch by Juergen Ilse, [commit 471](http://wiki.powerdns.com/projects/trac/changeset/471). Also moved most of PowerDNS over to uint32\_t style typedefs, which eases compilation problems on Solaris, [commit 477](http://wiki.powerdns.com/projects/trac/changeset/477).
+- Bindbackend2 did not properly search its include path for $INCLUDE statements. Noted by Mark Bergsma, [commit 474](http://wiki.powerdns.com/projects/trac/changeset/474).
+- Bindbackend did not notice changed zones, this problem has been fixed by the move to Bind2.
+- Pipebackend did not clean up, leading to an additional pipe backend per AXFR or pdns\_control reload. Discovered by Marc Jauvin, fixed by [commit 525](http://wiki.powerdns.com/projects/trac/changeset/525).
+- Bindbackend (both old and current versions) did not honour 'include' statements in `named.conf` on **pdns\_control rediscover**. Noted by Marc Jauvin, fixed by [commit 526](http://wiki.powerdns.com/projects/trac/changeset/526).
+- Zone transfers were sometimes shuffled, which wastes useless time, [commit 478](http://wiki.powerdns.com/projects/trac/changeset/478).
+- CNAMEs and Wildcards now work as in Bind, fixing many complaints, [commit 487](http://wiki.powerdns.com/projects/trac/changeset/487).
+- NAPTR records were compressed, which would work, but was in violation of the RFC, commit 493.
+- NAPTR records were not always parsed correctly from BIND zone files, fixed, commit 494.
+- Geobackend needed additional include statement to compile on more recent Linux distributions, commit 496.
+
+# Version 2.9.18
+Released on the 16th of July 2005.
+
+The '8 million domains' release, which also marks the battle readiness of the PowerDNS Recursor. The latest improvements have been made possible by financial support and contributions by [Register.com](http://register.com) and [XS4ALL](http://www.xs4all.nl/). Thanks!
+
+This release brings a number of new features (vastly improved recursor, Generic Oracle Support, DNS analysis and replay tools, and more) but also has a new build dependency, the [Boost library](http://www.boost.org) (version 1.31 or higher).
+
+Currently several big ISPs are evaluating the PowerDNS recursor for their resolving needs, some of them have switched already. In the course of testing, over 350 million actual queries have been recorded and replayed, the answers turn out to be satisfactorily.
+
+This testing has verified that the pdns recursor, as shipped in this release, can stand up to heavy duty ISP loads (over 20000 queries/second) and in fact does so better than major other nameservers, giving more complete answers and being faster to boot.
+
+We invite ISPs who note recursor problems to record their problematic traffic and replay it using the tools described in [Tools to analyse DNS traffic](tools/analysis.md "Tools to analyse DNS traffic") to discover if PowerDNS does a better job, and to let us know the results.
+
+Additionally, the bind2backend is almost ready to replace the stock bind backend. If you run with Bind zones, you are cordially invited to substitute 'launch=bind2' for 'launch=bind'. This will happen automatically in 2.9.19!
+
+In other news, the entire Wikipedia constellation now runs on PowerDNS using the Geo Backend! Thanks to Mark Bergsma for keeping us updated.
+
+There are two bugs with security implications, which only apply to installations running with the LDAP backend, or installations providing recursion to a limited range of IP addresses. If any of these apply to you, an upgrade is highly advised
+
+- The LDAP backend did not properly escape all queries, allowing it to fail and not answer questions. We have not investigated further risks involved, but we advise LDAP users to update as quickly as possible (Norbert Sendetzky, Jan de Groot)
+- Questions from clients denied recursion could blank out answers to clients who are allowed recursion services, temporarily. Reported by Wilco Baan. This would've made it possible for outsiders to blank out a domain temporarily to your users. Luckily PowerDNS would send out SERVFAIL or Refused, and not a denial of a domain's existence.
+
+## General bugs fixed
+
+- TCP authoritative server would not relaunch a backend after failure (reported by Norbert Sendetzky)
+- Fix backend restarting logic (reported, and fix suggested by Norbert Sendetzky)
+- Launching identical backends multiple times, with different settings, did not work. Reported by Mario Manno.
+- Master/slave queries did not honour the **query-local-address** setting. Spotted by David Levy of Register.com. The fix also randomises the local port used, slightly improving security.
+
+## Compilation fixes
+- Fix compile on Solaris, they define 'PC' for some reason. Reported by Eric Yiu.
+- PowerDNS recursor would not compile on FreeBSD due to Linux specific defines, as reported in cvstrac ticket 26 (Ralf van der Enden)
+- Several 64 bits issues have been fixed, especially in the Logging subsystem.
+- SSQLite would fail to compile on recent Debian systems (Matthijs Möhlmann)
+- Generic MySQL would not compile on 64-bit platforms.
+
+## Improvements
+- PowerDNS now reports stray command line arguments, like when running '--local-port 5300' instead of '--local-port=5300'. Reported by Christian Welzel.
+- We now warn against erroneous logging-facility specification, ie specifying an unknown facility.
+- **--version** now outputs gcc version used, so we can tell people 2.95 is no longer supported.
+- Extended regression tests, moved them to the new 'sdig' tool (see below).
+- Bind2backend is now blazingly fast, and highly memory efficient to boot. As a special bonus it can read gzipped zones directly. The '.NET' zone is hosted using 401MB of memory, the same size as the zone on disk.
+- The Pipe Backend has been improved such that it can send out different answers based on the IP address the question was received ON. See [PipeBackend protocol](authoritative/backend-pipe.md#pipebackend-protocol) for how this changed the Pipe Backend protocol. Note that you need to set **pipebackend-abi-version** to benefit from this change, existing clients are not affected. Change and documentation contributed by Marc Jauvin of Register4Less.
+- LDAP backend has been updated (Norbert Sendetzky).
+
+## Recursor improvements and fixes.
+See [Recursion](authoritative/recursion.md "Recursion") for details. The changes below mean that all of the caveats listed for the recursor have now been addressed.
+
+- After half an hour of uptime, the entire cache would be pruned for each packet, which is a tad slow. It now appears the pdns recursor is among the fastest around.
+- Under high loads, or when unlucky, some query mthreads would get 'stuck', and show up in the statistics as eternally running queries.
+- Lots of redundant gettimeofday() and time() calls were removed, which has resulted in a measurable speedup.
+- pdns\_recursor can now listen on several addresses simultaneously.
+- Now supports setuid and setgid operation to allow running as a less privileged user (Bram Vandoren).
+- Return code of pdns\_recursor binary did not make sense (Matthijs Möhlmann and Thomas Hood)
+- Timeouts and errors are now split out in statistics.
+- Many people reported broken statistics, it turned out that no statistics were being reported if there had been no questions to base them on. We now log a message to that effect.
+- Add **query-local-address** support, which allows the recursor to send questions from a specific IP address. Useful for anycast setups.
+- Add outgoing TCP query support and proper truncated answer support. Needed for Worldnic Denial of Service protection, which sends out truncated packets to force clients to connect over TCP, which prevents spoofing.
+- Properly truncate our own answers.
+- Improve our TCP answers by using writev, which is slightly friendlier to the network.
+- On FreeBSD, TCP errors could cause the recursor to exit suddenly due to a SIGPIPE signal.
+- Maximum number of simultaneous client TCP connections can now be limited with the **max-tcp-clients** setting.
+- Add aggressive timeouts for TCP clients to make sure resources are not wasted. Defaults to two seconds, can be configured with the **client-tcp-timeout** setting.
+
+## Backend fixes
+- SQLite backend would not slave properly (Darron Broad)
+- Generic MySQL would not compile on 64-bit platforms.
+
+## New technology
+- Added the new DNS parser logic, called MOADNSParser. Completely modular, every memory access checked.
+- 'sdig', a simple dig work-alike with 'canonical' output, which is used for the regression tests. Based on the new DNS parser logic.
+- **dnswasher**, **dnsreplay** and **dnsscope**, all DNS analysis tools. See [Tools to analyse DNS traffic](tools/analysis.md "Tools to analyse DNS traffic") for more details.
+- Generic Oracle Backend, sponsored by Register.COM. See [Oracle specifics](authoritative/backend-generic-oracle.md "Oracle specifics").
+
+# Version 2.9.17
+
+See [the new timeline](http://wiki.powerdns.com/trac/timeline) for progress reports.
+
+The 'million domains' release - PowerDNS has now firmly established itself as a major player with the unofficial count (ie, guesswork) now at over two million PowerDNS domains! Also, the GeoBackend has been tested by a big website and may soon see wider deployment. Thanks to Mark Bergsma for spreading the word!
+
+It is also a release with lots of changes and fixes. Take care when deploying!
+
+## Security issues
+- PowerDNS could be temporarily DoSed using a random stream of bytes. Reported cause of this has been fixed.
+
+## Enhancements
+- Reported version can be changed, or removed - see the "version-string" setting.
+- Duplicate MX records are now no longer considered duplicate if their priorities differ. Some people need this feature for spam filtering.
+
+## Bug fixes
+- NAPTR records can now be slaved, patch by Lorens Kockum.
+- GMySQL now works on Solaris
+- PowerDNS could be confused by questions with a %-sign in them - fixing cvstrac ticket \#16 (reported by dilinger at voxel.net)
+- An authentication bug in the webserver was possibly fixed, please report if you were suffering from this. Being unable to authenticate to the webserver was what you would've noticed.
+- Fix for cvstrac ticket \#2, PowerDNS could lose sync when sending out a very large number of notifications. Excellent bug report by Martin Hoffman, who also improved our original bugfix.
+- Fix the oldest PowerDNS bug in existence - under some circumstances, PowerDNS would log to syslog one character at a time. This was cvstrac ticket \#4
+- HINFO records can now be slaved, fixing cvstrac ticket \#8.
+- pdns\_recursor could block under some circumstances, especially in case of corrupt UDP packets. Reported by Wichert Akkerman. Fix by Christopher Meer. This was cvstrac ticket \#13.
+- Large SOA serial numbers would sometimes be logged as a signed integer, leading to negative numbers in the log.
+- PowerDNS now fully supports 32 bit SOA serial numbers (thanks to Mark Bergsma), closing cvstrac ticket \#5.
+- pdns\_recursor --local-address help text was wrong.
+- Very devious bug - PowerDNS did not clear its cache before sending out update notifications, leading slaves to conclude there was no update to AXFR. Excellent debugging by mkuchar at wproduction.cz.
+- Probably fixed cvstrac ticket \#26, which caused pdns\_recursor to fail on recent FreeBSD 5.3 systems. Please check, I have no such system to test on.
+- Geobackend did not get built for Debian.
+
+# Version 2.9.16
+The 'it must still be Friday somewhere' release. Massive number of fixes, portability improvements and the new Geobackend by Mark Bergsma & friends.
+
+## New
+- The Geobackend which makes it possible to send different answers to different IP ranges. Initial documentation can be found in pdns/modules/geobackend/README.
+- qgen query generation tool. Nearly completely undocumented and hard to build too, it requires Boost. But very spiffy. Use **cd pdns; make qgen** to build it.
+
+## Bugfixes
+- The most reported bug ever was fixed. Zone2sql required the inclusion of unistd.h, except on Debian unstable.
+- PowerDNS tried to listen on its control "pipe" which does not work. Probably harmless, but might have caused some oddities.
+- The Packet Cache did not always set its TTL immediately, causing some packets to be inserted, even when running with the cache disabled (Mark Bergsma).
+- Valgrind found some uninitialized reads, causing bogus values in the priority field when it was not needed.
+- Valgrind found a bug in MTasker where we used delete instead of delete[].
+- SOA serials and other parameters are unsigned. This means that very large SOA serial numbers would be messed up (Michel Stol, Stefano Straus)
+- PowerDNS left its controlsocket around after exit and reported confusing errors if a socket was already in use.
+- The recursor proxy did not work on big endian systems like SPARC and some MIPS processors (Remco Post)
+- We no longer dump core on processing LOC records on UltraSPARC (Andrew Mulholland supplied a testing machine)
+
+## Improvements
+- MySQL can now connect to a specified port again (Chris Anderton).
+- When running chroot()ed and with master or slave support active, PowerDNS needs to resolve domain names to find slaves. This in turn may require access to certain libraries. Previously, these needed to be available in the chroot directory but by forcing an initial lookup, these libraries are now loaded before the chrooting.
+- pdns\_recursor was very slow after having done a larger number of queries because of the checks to see if a query should be throttled. This is now done using a set which is a lot faster than the previous full sequential scan.
+- The throttling code may not have throttled as much as was configured.
+- Yet another big LDAP update. The LDAP backend now load balances connections over several hosts (Norbert Sendetzky)
+- Updated b.root-servers.net address in the recursor
+
+# Version 2.9.15
+This release fixes up some of the shortcomings in 2.9.14, and adds some new features too.
+
+## Bugfixes
+- **allow-recursion-override** was on by default, it was meant to be off.
+- Logging was still off in daemon mode, fixed.
+- debian/rules forgot to build an sqlite package
+- Recursor accidentally linked in MySQL - this was the result of an experiment with a persistent recursor cache.
+- The PowerDNS recursor had stability problems. It now sorts nameservers (roughly) by responsiveness. The 'roughly' part upset the sorting algorithm used, the speeds being sorted on changed during sorting.
+- The recursor now outputs the nameserver average response times in trace mode
+- LDAP compiles again.
+
+## Improvements
+- zone2sql can now accept `-` as a file name which causes it to read stdin. This allows the following to work: **dig axfr example.org | zone2sql --gmysql --zone=- | mysql pdns**, which is a nice way to import a zone.
+- zone2sql now ignores duplicate SOA records which are identical - which also makes the above possible.
+- Remove libpqpp dependencies - since we now use the native C API for PostgreSQL
+
+# Version 2.9.14
+
+Big release with the fix for the all important 2^30 seconds problem and a lot of other news.
+- errno problems would cause compilation problems when using LDAP (Norbert Sendetzky)
+- The Generic SQL backend could cause crashes on PostgreSQL when using pdns\_control notify (Georg Bauer)
+- Debian compatible init.d script (Wichert Akkerman)
+- If using the master or slave features, pdns had the notion of eternity ending in 2038, except that due to a thinko, eternity ended out to be the 10th of January 2004. This caused a loop to timeout immediately. Many thanks to Jasper Spaans for spotting the bug within five minutes.
+- Parts of the SOA field were not canonicalized.
+- The loglevel could in fact cause nothing to be logged (Norbert Sendetzky)
+
+## Improvements
+- The recursor now chooses the fastest nameserver, which causes a big speedup!
+- LDAP now has different lookup models
+- Cleanups, better load distribution, better exception handling, zone2ldap improvements
+- The recursor was somewhat chatty about TCP connections
+- PostgreSQL now only depends on the C API and not on the deprecated C++ one
+- PowerDNS can now fully overrule external zones when doing recursion. See [Recursion](authoritative/recursion.md "Recursion").
+
+# Version 2.9.13
+
+Big news! Windows is back! Our great friend Michel Stol found the time to update the PowerDNS code so it works again under windows.
+
+Furthermore, big thanks go out to Dell who quickly repaired my trusty [laptop](http://ds9a.nl/dell-d800).
+
+His changes
+- Generic SQLite support added
+- Removed the ODBC backend, replaced it by the Generic ODBC Backend, which has all the cool configurability of the Generic MySQL and PostgreSQL backends.
+- The PowerDNS Recursor now runs as a Service. It defaults to running on port 5300, PowerDNS itself is configured to expect the Recursor on port 5300 now.
+- The PowerDNS Service is now known as 'PowerDNS' to Windows.
+- The Installer was redone, this time with [NSIS2](http://nsis.sf.net).
+- General updates and fixes.
+
+## Other news
+**Note**: There appears to be a problem with PowerDNS on Red Hat 7.3 with GCC 2.96 and self-compiled binaries. The symptoms are that PowerDNS works on the foreground but fails as a daemon. We're working on it.
+
+If you do note problems, let the list know, if you don't, please do so as well. Tell us if you use the RPM or compiled yourself.
+
+It is known that not compiling in MySQL support helps solve the problem, but then you don't have MySQL.
+
+There have been a number of reports on MySQL connections being dropped on FreeBSD 4.x, which sometimes causes PowerDNS to give up and reload itself. To combat this, MySQL error messages have been improved in some places in hopes of figuring out what is up. The initial indication is that MySQL itself sometimes terminates the connection and, amazingly, that switching to a Unix domain socket instead of TCP solves the problem.
+
+## Bug fixes
+- **allow-axfr-ips** did not work for individual IP addresses (bug & fix by Norbert Sendetzky)
+
+## Improvements
+- Opteron support! Thanks to Jeff Davey for providing a shell on an Opteron. The fixes should also help PowerDNS on other platforms with a 64 bit userspace.
+
+ Btw, the PowerDNS team has a strong desire for an Opteron :-)
+
+- pdns\_recursor jumbles answers now. This means that you can do poor man's round robin by supplying multiple A, MX or AAAA records for a service, and get a random one on top each time. Interestingly, this feature appeared out of nowhere, this change was made to the authoritative code but due to the wonders of code-reuse had an effect on pdns\_recursor too.
+- Big LDAP cleanup. Support for TLS was added. Zone2LDAP also gained the ability to generate ldif files containing a tree or a list of entries. (Norbert Sendetzky)
+- Zone2sql is now somewhat clearer when reporting malformed line errors - it did not always include the name of the file causing a problem, especially for big installations. Problem noted by Thom May.
+- pdns\_recursor now survives the expiration of all its root records, most often caused by prolonged disconnection from the net.
+
+# Version 2.9.12
+
+Release rich in features. Work on Verisign oddities, addition of SQLite backend, pdns\_recursor maturity.
+
+## New features
+- --version command (requested by Mike Benoit)
+- delegation-only, a Verisign special.
+- Generic [SQLite](http://www.sqlite.org) support, by Michel 'Who da man?' Stol. See [Generic SQLite backend](authoritative/backend-generic-sqlite.md).
+- init.d script for pdns\_recursor
+- Recursor now actually purges its cache, saving memory.
+- Slave configuration now no longer falls over when presented with a NULL master
+- Bindbackend2 now has supermaster support (Mark Bergsma, untested)
+- Answers are now shuffled! It turns out a few recursors don't do shuffling (pdns\_recursor, djbdns), so we do it now. Requested by Jorn Ekkelenkamp of ISP-Services. This means that if you have multiple IP addresses for one host, they will be returned in differing order every once in a while.
+
+## Bugs
+- 0.0.0.0/0 didn't use to work (Norbert Sendetzky)
+- pdns\_recursor would try to resolve IP address which to bind to, potentially causing chicken/egg problem
+- gpgsql no longer reports as gmysql (Sherwin Daganoto)
+- SRV would not be parsed right from disk (Christof Meerwald)
+- An AXFR from a zone hosted on the LDAP backend no longer transmits all the reverse entries too (Norbert Sendetzky)
+- PostgreSQL backend now does error checking. It would be a bit too trusting before.
+
+## Improvements, cleanups
+- PowerDNS now reports the numerical IP addresses it binds to instead of the, possibly, alphanumeric names the operator passed.
+- Removed only-soa hackery (noticed by Norbert Sendetzky)
+- Debian packaging fixes (Wichert Akkerman)
+- Some parameter descriptions were improved.
+- Cleanups by Norbert: getAuth moved to chopOff, arguments::contains massive cleanup, more.
+
+# Version 2.9.11
+Yet another iteration, hopefully this will be the last silly release.
+
+**Warning**: There has been a change in behaviour whereby **disable-axfr** does what it means now! From now on, setting **allow-axfr-ips** automatically disables AXFR from unmentioned subnets.
+
+This release enables AXFR again, **disable-axfr** did the opposite of what it claimed. Furthermore, the pdns\_recursor now cleans its cache, which should save some memory in the long run. Norbert contributed some small LDAP work which should come in useful in the future.
+
+# Version 2.9.10
+Small bugfixes, LDAP update. Released 3rd of July 2003. Apologies for the long delay, real life keeps interfering.
+
+**Warning**: Do not use or try to use 2.9.9, it was a botched release!
+
+**Warning**: There has been a change in behaviour whereby **disable-axfr** does what it means now! From now on, setting **allow-axfr-ips** automatically disables AXFR from unmentioned subnets.
+
+- 2.9.8 was prone to crash on adding additional records. Thanks to excellent debugging by PowerDNS users worldwide, the bug was found quickly and is in fact present in all earlier PowerDNS releases, but for some reason doesn't cause crashes there.
+- Notifications now jump in front of the queue of domains that need to be checked for changes, giving much greater perceived performance. This is needed if you have tens of thousands of slave domains and your master server is on a high latency link. Thanks to Mark Jeftovic of EasyDNS for suggesting this change and testing it on their platform.
+- Dean Mills reported that PowerDNS does confusing logging about changing GIDs and UIDs, fixed. Cosmetic only.
+- pdns\_recursor may have logged empty lines for some users, fixed. Solution suggested by Norbert Sendetzky.
+- LDAP: DNS TTLs were random values (Norbert Sendetzky, Stefan Pfetzing). New **ldap-default-ttl** option.
+- LDAP: Now works with OpenLDAP 2.1 (Norbert Sendetzky)
+- LDAP: error handling for invalid MX records implemented (Norbert Sendetzky)
+- LDAP: better exception handling (Norbert Sendetzky)
+- LDAP: code cleanup of lookup() (Norbert Sendetzky)
+- LDAP: added support for scoped searches (Norbert Sendetzky)
+
+# Version 2.9.8
+Queen's day release! 30th of April 2003.
+
+Added support for AIX, fixed negative SOA caching. Some other cleanups. Not a major release but enough reasons to upgrade.
+
+## Bugs fixed
+- Recursor had problems expiring negatively cached entries, which wasted memory and also led to the continued non-existence of hosts that since had come into existence.
+- The Generic SQL backends did not lowercase the names of records, which led to new records not being found by case sensitive databases (notably PostgreSQL). Found by Volker Goetz.
+- NS queries for zones for which we did not carry authority, but only had delegation information, had their NS records in the wrong section. Minor detail, but a standards violation nonetheless. Spotted by Stephane Bortzmeyer.
+
+## Improvements
+- Removed crypt.h dependency from powerldap.hh, which was a problem on some platforms (Richard Arends)
+- PowerDNS can't parse so called binary labels which we now detect and ignore, after printing a warning.
+- Specifying allow-axfr-ips now automatically disables AXFR for all non-mentioned addresses.
+- A Solaris ready init.d script is now part of the tar.gz (contributed, but I lost by whom).
+- Added some fixes to PowerDNS can work on AIX (spotted by Markus Heimhilcher).
+- Norbert Sendetzky contributed `zone2ldap`.
+- Everybody's favorite compiler warning from `zone2sql.cc` was removed!
+- Recursor now listens on TCP!
+
+# Version 2.9.7
+Released on 2003-03-20.
+
+This is a sweeping release in the sense of cleanup. There are some new features but mostly a lot of cleanup going on. Hiding inside is the `bind2backend`, the next generation of the bind backend. A work in progress. Those of you with overlapping zones, as mentioned in the changelog of 2.9.6, are invited to check it out by replacing **launch=bind** by **launch=bind2** and renaming all **bind-** parameters to **bind2-**. Be aware that if you run with many small zones, this backend is faster, but if you run with a few large ones, it is slower. This will improve.
+
+## Features
+- Mark Bergsma contributed **query-local-address** which allows the operator to select which source address to use. This is useful on servers with multiple source addresses and the operating system selecting an unintended one, leading to remotes denying access.
+- PowerDNS can now perform AAAA additional processing optionally, turned on by setting **do-ipv6-additional-processing**. Thanks to Stephane Bortzmeyer for pointing out the need.
+- Bind2backend, which is almost in compliance with the new IETF AXFR-clarify (some would say 'redefinition') draft.
+ This backend is not ready for primetime but you may want to try it if you currently have overlapping zones and note problems. An overlapping zone would be having "ipv6.powerdns.com" and "powerdns.com" zones on one server.
+
+## Improvements
+- Zone2sql would happily try to read from a directory and not give a useful error about this.
+- PowerDNS now reports the case where it can't figure out any IP address of slave nameservers for a zone
+- Removed **receiver-threads** setting which was experimental and in fact only made things worse.
+- LDAP backend updates from its author Norbert Sendetzky. Reverse lookups should work now too.
+- An error message about unparseable packets did not include the originating IP address (fixed by Mark Bergsma)
+- PowerDNS can now be started via path resolution while running with a guardian. Suggested by Maurice Nonnekes.
+- `pdns_recursor` moved to `sbin` (reported by Norbert Sendetzky)
+- Retuned some logger errorlevels, a lot of master/slave chatter was logged as 'Error'. Reported by Willem de Groot.
+
+## Bugs fixed
+- `zone2sql` did not remove trailing dots in SOA records.
+- ldapbackend did not include `utility.hh` which caused compilation problems on Solaris (reported by Remco Post)
+- `pdns_control` could leave behind remnants in case PowerDNS was not running (reported by dG)
+- Incoming AXFR did not work on Solaris and other big-endian systems (Willem de Groot helped debugging this long standing problem).
+- Recursor could crash on convoluted CNAME loops. Thanks to Dan Faerch for delivering core dumps.
+- Silly 'wuh' debugging output in zone2sql and bindbackend removed (spotted by Ivo van der Wijk).
+- Recursor neglected to differentiate between negative cache of NXDOMAIN and NOERROR, leading to problems with IPv6 enabled Windows clients. Thanks to Stuart Walsh for reporting this and testing the fix.
+- PowerDNS set the 'aa' bit on serving NS records in a zone for which it was authoritative. Most implementations drop the 'aa' bit in this case and Stephane Bortzmeyer informed us of this. PowerDNS now also drops the 'aa' bit in this case.
+- The webserver tended to fail after prolonged operation on FreeBSD, this was due to an uninitialised timeout, other platforms were lucky. Thanks to G.P. de Boer for helping debug this.
+- getAnswers() in dnspacket.cc could be forced to read bytes beyond the end of the packet, leading to crashes in the PowerDNS recursor. This is an ongoing project that needs more work. Reported by Dan Faerch, with a core dump proving the problem.
+
+# Version 2.9.6
+Two new backends - Generic ODBC (windows only) and LDAP. Furthermore, a few important bugs have been fixed which may have hampered sites seeing a lot of outgoing zone transfers. Additionally, the pdns recursor now has 'query throttling' which is pretty cool. In short this makes sure that PowerDNS does not send out heaps of queries if a nameserver is unable to provide an answer. Many operators of authoritative setups are all too aware of recursing nameservers that hammer them for zones they don't have, PowerDNS won't do that anymore now, no matter what clients request of it.
+
+**Warning**: There is an unresolved issue with the BIND backend and 'overlapping' slave zones. So if you have 'example.com' and also have a separate slave zone called 'external.example.com', things may go wrong badly. Thanks to Christian Laursen for working with us a lot in finding this issue. We hope to resolve it soon.
+
+- BIND Backend now honours notifies, code to support this was accidentally left out. Thanks to Christian Laursen for noticing this.
+- Massive speedup for those of you using the slightly deprecated MBOXFW records. Thanks to Jorn of [ISP Services](http://www.ISP-Services.nl) for helping and testing this improvement.
+- $GENERATE had an off-by-one bug where it would omit the last record to be generated (Christian Laursen)
+- Simultaneous AXFRs may have been problematic on some backends. Thanks to Jorn of ISP-Services again for helping us resolve this issue.
+- Added LDAP backend by Norbert Sendetzky, see [LDAP Backend](authoritative/backend-ldap.md).
+- Added Generic ODBC backend for Windows by Michel Stol.
+- Simplified 'out of zone data' detection in incoming AXFR support, hopefully removing a case sensitivity bug there. Thanks again to Christian Laursen for reporting this issue.
+- $include in-zonefile was broken under some circumstances, losing the last character of a file name. Thanks to Joris Vandalon for noticing this.
+- The zone parser was more case-sensitive than BIND, refusing to accept 'in' as well as 'IN'. Thanks to Joris Vandalon for noticing this.
+
+# Version 2.9.5
+Released on 2002-02-03.
+
+This version is almost entirely about recursion with major changes to both the pdns recursor, which is renamed to '`pdns_recursor`' and to the main PowerDNS binary to make it interact better with the recursing component.
+
+Sadly, due to [technical reasons](http://sources.redhat.com/ml/libc-alpha/2003-01/msg00245.html), compiling the pdns recursor and pdns authoritative nameserver into one binary is not immediately possible. During the release of 2.9.4 we stated that the recursing nameserver would be integrated in the next release - this won't happen now.
+
+However, this turns out to not be that bad at all. The recursor can now be restarted without having to restart the rest of the nameserver, for example. Cooperation between the both halves of PowerDNS is also almost seamless. As a result, 'non-lazy recursion' has been dropped. See [Recursion](authoritative/recursion.md "Recursion") for more details.
+
+Furthermore, the recursor only works on Linux, Windows and Solaris (not entirely). FreeBSD does not support the required functions. If you know any important FreeBSD people, plea with them to support set/get/swapcontext! Alternatively, FreeBSD coders could read the solution presented here [in figure 5](http://www.eng.uwaterloo.ca/~ejones/software/threading.html).
+
+The 'Contributor of the Month' award goes to Mark Bergsma who has responded to our plea for help with the label compressor and contributed a wonderfully simple and right fix that allows PowerDNS to compress just as well as other nameservers out there. An honorary mention goes to Ueli Heuer who, despite having no C++ experience, submitted an excellent SRV record implementation.
+
+Excellent work was also performed by Michel Stol, the Windows guy, in fixing all our non-portable stuff again. Christof Meerwald has also done wonderful work in porting MTasker to Windows, which was then used by Michel to get the recursor functioning on Windows.
+
+## Other changes
+- dnspacket.cc was cleaned up by factoring out common operations
+- Heaps of work on the recursing nameserver. Has now achieved *days* of uptime!
+- Recursor renamed from syncres to `pdns_recursor`
+- PowerDNS can now serve records it does not know about. To benefit from this slightly undocumented feature, add 1024 to the numerical type of a record and include the record in binary form in your database. Used internally by the recursing nameserver but you can use it too.
+- PowerDNS now knows about SIG and KEY records *names*. It does not support them yet but can at least report so now.
+- HINFO records can now be transferred from a master to PowerDNS (thanks to Ueli Heuer for noticing it didn't work).
+- Yet more UltraSPARC alignment issues fixed (Chris Andrews).
+- Dropped non-lazy recursion, nobody was using it. Lazy recursion became even more lazy after Dan Bernstein pointed out that additional processing is not vital, so PowerDNS does its best to do additional processing on recursive queries, but does not scream murder if it does not succeed. Due to caching, the next identical query will be successfully additionally processed.
+- Label compression was improved so we can now fit all . records in 436 bytes, this used to be 460! (Code & formal proof of correctness by Mark Bergsma).
+- SRV support (incoming and outgoing), submitted by Ueli Heuer.
+- Generic backends do not support SOA serial autocalculation, it appears. Could lead to random SOA serials in case of a serial of 0 in the database. Fixed so that 0 stays zero in that case. Don't set the SOA serial to 0 when using Generic MySQL or Generic PostgreSQL!
+- J root-server address was updated to its new location.
+- SIGUSR1 now forces the recursor to print out statistics to the log.
+- Meaning of recursor logging was changed a bit - a cache hit is now a question that was answered with 0 outgoing packets needed. Used to be a weighted average of internal cache hits.
+- MySQL compilation did not include -lz which causes problems on some platforms. Thanks to James H. Cloos Jr for reporting this.
+- After a suggestion by Daniel Meyer and Florus Both, the built in webserver now reports the configuration name when multiple PowerDNS instances are active.
+- Brad Knowles noticed that zone2sql had problems with the root.zone, fixed. This also closes some other zone2sql annoyances with converting single zones.
+
+# Version 2.9.4
+Yet another grand release. Big news is the addition of a recursing nameserver which has sprung into existence over the past week. It is in use on several computers already but it is not ready for prime time. Complete integration with PowerDNS is expected around 2.9.5, for now the recursor is a separate program.
+
+In preliminary tests, the recursor appears to be four times faster than BIND 9 on a naive benchmark starting from a cold cache. BIND 9 managed to get through to some slower nameservers however, which were given up on by PowerDNS. We will continue to tune the recursor. See [PowerDNS Recursor](recursor/index.md) for further details.
+
+The BIND Backend has also been tested (see the **bind-domain-status** item below) rather heavily by several parties. After some discussion online, one of the BIND authors ventured that the newsgroup comp.protocols.dns.bind may now in fact be an appropriate venue for discussing PowerDNS. Since this discussion, traffic to the PowerDNS pages has increased sixfold and shows no signs of slowing down.
+
+From this, it is apparent that far more people are interested in PowerDNS than yet know about it. So spread the word!
+
+In other news, we now have a security page at [Security](security/index.md). Furthermore, Maurice Nonnekes contributed an OpenBSD port! See [his page](http://www.codeninja.nl/openbsd/powerdns/) for more details!
+
+## New features and improvements
+- All SQL queries in the generic backends are now available for configuration. (Martin Klebermass, Bert Hubert). See [Generic SQL backends](authoritative/backend-generic-sql.md).
+- A recursing nameserver! See [PowerDNS Recursor](recursor/index.md).
+- An incoming AXFR now only starts a backend zone replacement transaction after the first record arrived successfully, thus making sure no work is done when a remote nameserver is unable/unwilling to AXFR a zone to us.
+- Zone parser error messages were improved slightly (thanks to Stef van Dessel for spotting this shortcoming)
+- XS4ALL's Erik Bos checked how PowerDNS reacted to a BIND installation with almost 60.000 domains, some of which with \>100.000 records, and he discovered the pdns\_control **bind-domain-status** command became very slow with larger numbers of domains. Fixed, 60.000 domains are now listed in under one second.
+- If a remote nameserver disconnects during an incoming AXFR, the update is now rolled back, unless the AXFR was properly terminated.
+- The migration chapter mentioned the use of deprecated backends.
+
+## A tremendous number of bugs were discovered and fixed
+- Zone parser would only accept $include and not $INCLUDE
+- Zone parser had problems with $lines with comments on the end
+- Wildcard ANY queries were broken (thanks Colemarcus for spotting this)
+- A connection failure with the Generic backends would lead to a powerdns reload (cast of many)
+- Generic backends had some semantic problems with slave support. Symptoms were oft-repeated notifications and transfers (thanks to Mark Bergsma for helping resolve this).
+- Solaris version compiles again. Thanks to Mohamed Lrhazi for reporting that it didn't.
+- Some UltraSPARC alignment fixes. Thanks to Mohamed Lrhazi for being helpful in spotting these. One problem is still outstanding, Mohamed sent a core dump that tells us where the problem is. Expect the fix to be in 2.9.5. Volunteers can grep the source for 'UltraSPARC' to find where the problem is.
+- Our support of IPv6 on FreeBSD had phase of moon dependent bugs, fixed by Peter van Dijk.
+- Some crashes of and by pdns\_control were fixed, thanks to Mark Bergsma for helping resolve these.
+- Outgoing AXFR in pdns installations with multiple loaded backends was broken (thanks to Stuart Walsh for reporting this).
+- A failed BIND Backend incoming AXFR would block the zone until it succeeded again.
+- Generic PostgreSQL backend wouldn't compile with newer libpq++, fixed by Julien Lemoine/SpeedBlue.
+- Potential bug (not observed) when listening on multiple interfaces fixed.
+- Some typos in manpages fixed (reported by Marco Davids).
+
+# Version 2.9.3a
+
+**Note**: 2.9.3a is identical to 2.9.3 except that zone2sql does work
+
+Broad range of huge improvements. We now have an all-static .rpm and .deb for Linux users and a link to an OpenBSD port. Major news is that work on the Bind backend has progressed to the point that we've just retired our last Bind server and replaced it with PowerDNS in Bind mode! This server is operating a number of master and slave setups so it should stress the Bind backend somewhat.
+
+This version is rapidly approaching the point where it is a better-Bind-than-Bind and nearly a drop-in replacement for authoritative setups. PowerDNS is now equipped with a powerful master/slave apparatus that offers a lot of insight and control to the user, even when operating from Bind zone files and a Bind configuration. Observe.
+
+After the SOA of example.org was raised
+
+```
+pdns[17495]: All slave domains are fresh
+pdns[17495]: 1 domain for which we are master needs notifications
+pdns[17495]: Queued notification of domain 'example.org' to 195.193.163.3
+pdns[17495]: Queued notification of domain 'example.org' to 213.156.2.1
+pdns[17520]: AXFR of domain 'example.org' initiated by 195.193.163.3
+pdns[17520]: AXFR of domain 'example.org' to 195.193.163.3 finished
+pdns[17521]: AXFR of domain 'example.org' initiated by 213.156.2.1
+pdns[17521]: AXFR of domain 'example.org' to 213.156.2.1 finished
+pdns[17495]: Removed from notification list: 'example.org' to 195.193.163.3 (was acknowledged)
+pdns[17495]: Removed from notification list: 'example.org' to 213.156.2.1 (was acknowledged)
+pdns[17495]: No master domains need notifications
+```
+
+If however our slaves would ignore us, as some are prone to do, we can send some additional notifications
+
+```
+$ sudo pdns_control notify example.org
+Added to queue
+pdns[17492]: Notification request for domain 'example.org' received
+pdns[17492]: Queued notification of domain 'example.org' to 195.193.163.3
+pdns[17492]: Queued notification of domain 'example.org' to 213.156.2.1
+pdns[17495]: Removed from notification list: 'example.org' to 195.193.163.3 (was acknowledged)
+pdns[17495]: Removed from notification list: 'example.org' to 213.156.2.1 (was acknowledged)
+```
+
+Conversely, if PowerDNS needs to be reminded to retrieve a zone from a master, a command is provided
+
+```
+$ sudo pdns_control retrieve forfun.net
+Added retrieval request for 'forfun.net' from master 212.187.98.67
+pdns[17495]: AXFR started for 'forfun.net', transaction started
+pdns[17495]: Zone 'forfun.net' (/var/cache/bind/forfun.net) reloaded
+pdns[17495]: AXFR done for 'forfun.net', zone committed
+```
+
+Also, you can force PowerDNS to reload a zone from disk immediately with **pdns\_control bind-reload-now**. All this happens 'live', per your instructions. Without instructions, the right things also happen, but the operator is in charge.
+
+For more about all this coolness, see [“pdns\_control”](authoritative/running.md#pdnscontrol "pdns_control") and [“pdns\_control commands”](authoritative/backend-bind.md#bind-control-commands "pdns_control commands").
+
+**Warning**: Again some changes in compilation instructions. The hybrid pgmysql backend has been split up into 'gmysql' and 'gpgsql', sharing a common base within the PowerDNS server itself. This means that you can no longer compile **--with-modules="pgmysql" --enable-mysql --enable-pgsql** but that you should now use: **--with-modules="gmysql gpgsql"**. The old launch-names remain available.
+
+If you launch the Generic PostgreSQL backend as gpgsql2, all parameters will have gpgsql2 as a prefix, for example **gpgsql2-dbname**. If launched as gpgsql, the regular names are in effect.
+
+**Warning**: The pdns\_control protocol was changed which means that older pdns\_controls cannot talk to 2.9.3. The other way around is broken too. This may lead to problems with automatic upgrade scripts, so pay attention if your daemon is truly restarted.
+
+Also make sure no old pdns\_control command is around to confuse things.
+
+## Improvements
+- Bind backend can now deal with missing files and try to find them later.
+- Bind backend is now explicitly master capable and triggers the sending of notifications.
+- General robustness improvements in Bind backend - many errors are now non-fatal.
+- Accessibility, Serviceability. New **pdns\_server** commands like **bind-list-rejects** (lists zones that could not be loaded, and the reason why), **bind-reload-now** (reload a zone from disk NOW), **rediscover** (reread named.conf NOW). More is coming up.
+- Added support for retrieving RP (Responsible Person) records from remote masters. Serving them was already possible.
+- Added support for LOC records, which encode the geographical location of a host, both serving and retrieving (thanks to Marco Davids using them on our last Bind server, forcing us to implement this silly record).
+- Configuration file parser now strips leading spaces too, allowing "chroot= /tmp" to work, as well as "chroot=/tmp" (Thanks to Hub Dohmen for reporting this for months on end).
+- Added **bind-domain-status** command that shows the status of all domains (when/if they were parsed, any errors encountered while parsing them).
+- Added **bind-reload-now** command that tries to reload a zone from disk NOW, and reports back errors to the operator immediately.
+- Added **retrieve** command that queues a request to retrieve a zone from its master.
+- Zones retrieved from masters are now stored way smaller on disk because the domain is stripped from records, which is derived from the configuration file. Retrieved zones are now prefixed with some information on where they came from.
+
+## Changes
+- gpgsql and gmysql backends split out of the hybrid pgmysqlbackend. This again changed compilation instructions!
+- **pdns\_control** now uses the rarely seen SOCK\_STREAM Unix Domain socket variety so it can transport large amounts of text, which is needed for the **bind-domain-status** command, for which see [Pdns\_control commands](authoritative/backend-bind.md#bind-control-commands "Pdns_control commands"). This breaks compatibility with older pdns\_control and pdns\_server binaries!
+- Bind backend now ignores 'hint' and 'forward' and other unsupported zone types.
+- AXFRs are now logged more heavily by default. An AXFR is a heavy operation anyhow, some more logging does not further increase the load materially. Does help in clearing up what slaves are doing.
+- A lot of master/slave chatter has been silenced, making output more relevant. No more repetitive 'No master domains need notifications' etc, only changes are reported now.
+
+## Bugfixes
+- Windows version did not compile without minor changes.
+- Confusing error reporting on Windows 98 (which does not support PowerDNS) fixed
+- Potential crashes with shortened packets addressed. An upgrade is advised!
+- **notify** (which was already there, just badly documented) no longer prints out debugging garbage.
+- pgmysql backend had problems launching when not compiled in but available as a module. Workaround for 2.9.2 is 'load-modules=pgmysql', but even then gpgsql would not work! gmysql would then, however. These modules are now split out, removing such issues.
+
+# Version 2.9.2
+Bugfixes galore. Solaris porting created some issues on all platforms. Great news is that PowerDNS is now in Debian 'sid' (unstable). The 2.9.1 packages in there currently aren't very good but the 2.9.2 ones will be. Many thanks to Wichert Akkerman, our 'downstream' for making this possible.
+
+**Warning**: The Generic MySQL backend, part of the Generic MySQL & PostgreSQL backend, is now the DEFAULT! The previous default, the 'mysql' backend (note the lack of 'g') is now DEPRECATED. This was the source of much confusion. The 'mysql' backend does not support MASTER or SLAVE operation. The Generic backends do.
+
+To get back the mysql backend, add --with-modules="mysql" or --with-dynmodules="mysql" if you prefer to load your modules at runtime.
+
+## Bugs fixed
+- Silly debugging output removed from the webserver (found by Paul Wouters)
+- SEVERE: due to Solaris portability fixes, qtypes\<127 were broken. These include NAPTR, ANY and AXFR. The upshot is that powerdns wasn't performing outgoing AXFRs nor ANY queries. These were the 'question for type -1' warnings in the log
+- incoming AXFR could theoretically miss some trailing records (not observed, but could happen)
+- incoming AXFR did not support TXT records (spotted by Paul Wouters)
+- with some remotes, an incoming AXFR would not terminate until a timeout occurred (observed by Paul Wouters)
+- Documentation bug, pgmysql != mypgsql
+
+## Documentation
+- Documented the 'random backend', see [Random Backend](authoritative/backend-random.md "Random Backend").
+- Wichert Akkerman contributed three manpages.
+- Building PowerDNS on Unix is now documented somewhat more, see [Compiling PowerDNS on Unix](appendix/compiling-powerdns.md#on-unix "Compiling PowerDNS on Unix").
+
+## Features
+- pdns init.d script is now +x by default
+- OpenBSD is on its way of becoming a supported platform! As of 2.9.2, PowerDNS compiles on OpenBSD but swiftly crashes. Help is welcome.
+- ODBC backend (for Windows only) was missing from the distribution, now added.
+- xdb backend added - see [XDB Backend](authoritative/backend-deprecated.md#xdb-backend). Designed for use by root-server operators.
+- Dynamic modules are back which is good news for distributors who want to make a pdns packages that does not depend one every database under the sun.
+
+# Version 2.9.1
+Thanks to the great enthusiasm from around the world, powerdns is now available for Solaris and FreeBSD users again! Furthermore, the Windows build is back. We are very grateful for the help of
+
+- Michel Stol
+- Wichert Akkerman
+- Edvard Tuinder
+- Koos van den Hout
+- Niels Bakker
+- Erik Bos
+- Alex Bleker
+- Steven Stillaway
+- Roel van der Made
+- Steven Van Steen
+
+We are happy to have been able to work with the open source community to improve PowerDNS!
+
+## Changes
+- The monitor command **set** no longer allows the changing of non-existent variables.
+- IBM Universal Database DB2 backend now included in source distribution (untested!)
+- Oracle backend now included in source distribution (slightly tested!)
+- configure script now searches for postgresql and mysql includes
+- Bind parser now no longer dies on records with a ' in them (Erik Bos)
+- The pipebackend was accidentally left out of 2.9
+- FreeBSD fixes (with help from Erik Bos, Alex Bleeker, Niels Bakker)
+- Heap of Solaris work (with help from Edvard Tuinder, Stefan Van Steen, Koos van den Hout, Roel van der Made and especially Mark Bakker). Now compiles in 2.7 and 2.8, haven't tried 2.9. May be a bit dysfunctional on 2.7 though - it won't do IPv6 and it won't serve AAAA. Patches welcome!
+- Windows 32 build is back! Michel Stol updated his earlier work to the current version.
+- S/Linux (Linux on Sparc) build works now (with help from Steven Stillaway).
+- Silly debugging message ('sd.ttl from cache') removed
+- .deb files are back, hopefully in 'sid' soon! (Wichert Akkerman)
+- Removal of bzero and other less portable constructs. Discovered that recent Linux glibc's need -D\_GNU\_SOURCE (Wichert Akkerman).
+
+# Version 2.9
+Open source release. Do not deploy unless you know what you are doing. Stability is expected to return with 2.9.1, as are the binary builds.
+
+- License changed to the GNU General Public License version 2.
+- Cleanups by Erik Bos @ xs4all.
+- Build improvements by Wichert Akkerman
+- Lots of work on the build system, entirely revamped. By PowerDNS.
+
+# Version 2.8
+From this release onwards, we'll concentrate on stabilising for the 3.0 release. So if you have any must-have features, let us know soonest. The 2.8 release fixes a bunch of small stability issues and add two new features. In the spirit of the move to stability, this release has already been running 24 hours on our servers before release.
+
+- pipe backend gains the ability to restricts its invocation to a limited number of requests. This allows a very busy nameserver to still serve packets from a slow perl backend.
+- pipe backend now honors query-logging, which also documents which queries were blocked by the regex.
+- pipe backend now has its own backend chapter.
+- An incoming AXFR timeout at the wrong moment had the ability to crash the binary, forcing a reload. Thanks to our bug spotting champions Mike Benoit and Simon Kirby of NetNation for reporting this.
+
+# Version 2.7 and 2.7.1
+This version fixes some very long standing issues and adds a few new features. If you are still running 2.6, upgrade yesterday. If you were running 2.6.1, an upgrade is still strongly advised.
+
+## Features
+- The controlsocket is now readable and writable by the 'setgid' user. This allows for non-root access to PowerDNS which is nice for mrtg or cricket graphs.
+- MySQL backend (the non-generic one) gains the ability to read from a different table using the **mysql-table** setting.
+- pipe backend now has a configurable timeout using the **pipe-timeout** setting. Thanks to Steve Bromwich for pointing out the need for this.
+- Experimental backtraces. If PowerDNS crashes, it will log a lot of numbers and sometimes more to the syslog. If you see these, please report them to us. Only available under Linux.
+
+## Bugs
+- 2.7 briefly broke the mysql backend, so don't use it if you use that. 2.7.1 fixes this.
+- SOA records could sometimes have the wrong TTL. Thanks to Jonas Daugaard for reporting this.
+- An ANY query might lead to duplicate SOA records being returned under exceptional circumstances. Thanks to Jonas Daugaard for reporting this.
+- Underlying the above bug, packet compression could sometimes suddenly be turned off, leading to overly large responses and non-removal of duplicate records.
+- The **allow-axfr-ips** setting did not accept IP ranges (192.0.2.0/24) which the documentation claimed it did (thanks to Florus Both of Ascio technologies for being sufficiently persistent in reporting this).
+- Killed backends were not being respawned, leading to suboptimal behaviour on intermittent database errors. Thanks to Steve Bromwich for reporting this.
+- Corrupt packets during an incoming AXFR when acting as a slave would cause a PowerDNS reload instead of just failing that AXFR. Thanks to Mike Benoit and Simon Kirby of NetNation for reporting this.
+- Label compression in incoming AXFR had problems with large offsets, causing the above mentioned errors. Thanks to Mike Benoit and Simon Kirby of NetNation for reporting this.
+
+# Version 2.6.1
+
+Quick fix release for a big cache problem.
+
+# Version 2.6
+Performance release. A lot of work has been done to raise PowerDNS performance to staggering levels in order to take part in benchmarketing efforts. Together with our as yet unnamed partner, PowerDNS has been benchmarked at 60.000 mostly cached queries/second on off the shelf PC hardware. Uncached performance was 17.000 uncached DNS queries/second on the .ORG domain.
+
+Performance has been increased by both making PowerDNS itself quicker but also by lowering the number of backend queries typically needed. Operators will typically see PowerDNS taking less CPU and the backend seeing less load.
+
+Furthermore, some real bugs were fixed. A couple of undocumented performance switches may appear in --help output but you are advised to stay away from these.
+
+Developers: this version needs the pdns-2.5.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [Backend writers' guide](appendix/backend-writers-guide.md "Backend writers' guide").
+
+## Performance
+- A big error in latency calculations - cached packets were weighed 50 times less, leading to inflated latency reporting. Latency calculations are now correct and way lower - often in the microseconds range.
+- It is now possible to run with 0 second cache TTLs. This used to cause very frequent cache cleanups, leading to performance degradation.
+- Many tiny performance improvements, removing duplicate cache key calculations, etc. The cache itself has also been reworked to be more efficient.
+- First 'CNAME' backend query replaced by an 'ANY' query, which most of the time returns the actual record, preventing the need for a separate CNAME lookup, halving query load.
+- Much of the same for same-level-NS records on queries needing delegation.
+
+## Bugs fixed
+- Incidentally, the cache count would show 'unknown' packets, which was harmless but confusing. Thanks to Mike and Simon of NetNation for reporting this.
+- SOA hostmaster with a . in the local-part would be cached wrongly, leading to a stray backslash in case of multiple successively SOA queries. Thanks to Ascio Technologies for spotting this bug.
+- zone2sql did not parse Verisign zone files correctly as these contained a $TTL statement in mid-record.
+- Sometimes packets would not be accounted, leading to 'udp-queries' and 'udp-answers' divergence.
+
+## Features
+- 'cricket' command added to init.d scripts that provides unadorned output for parsing by 'Cricket'.
+
+# Version 2.5.1
+[Brown paper bag](http://www.tuxedo.org/~esr/jargon/html/entry/brown-paper-bag-bug.html) release fixing a huge memory leak in the new Query Cache.
+
+Developers: this version needs the new pdns-2.5.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [Backend writers' guide](appendix/backend-writers-guide.md "Backend writers' guide").
+
+And some small changes
+
+- Added support for RFC 2308 compliant negative-answer caching. This allows remotes to cache the fact that a domain does not exist and will not exist for a while. Thanks to Chris Thompson for [pointing out how tiny our minds are](http://ops.ietf.org/lists/namedroppers/namedroppers.2002/msg01697.html). This feature may cause a noticeable reduction in query load.
+- Small speedup to non-packet-cached queries, incidentally fixing the huge memory leak.
+- **pdns\_control ccounts** command outputs statistics on what is in the cache, which is useful to help optimize your caching strategy.
+
+# Version 2.5
+An important release which has seen quite a lot of trial and error testing. As a result, PowerDNS can now run with a huge cache and concurrent invalidations. This is useful when running of a slower database or under high traffic load with a fast database.
+
+Furthermore, the gpgsql2 backend has been validated for use and will soon supplant the gpgsql backend entirely. This also bodes well for the gmysql backend which is the same code.
+
+Also, a large amount of issues biting large scale slave operators were addressed. Most of these issues would only show up after prolonged uptime.
+
+## New features
+- Query cache. The old Packet Cache only cached entire questions and their answers. This is very CPU efficient but does not lead to maximum hitrate. Two packets both needing to resolve smtp.you.com internally would not benefit from any caching. Furthermore, many different DNS queries lead to the same backend queries, like 'SOA for .COM?'.
+
+ PowerDNS now also caches backend queries, but only those having no answer (the majority) and those having one answer (almost the rest).
+
+ In tests, these additional caches appear to halve the database backend load numerically and perhaps even more in terms of CPU load. Often, queries with no answer are more expensive than those having one.
+
+ The default **ttl**s for the query-cache and negquery-cache are set to safe values (20 and 60 seconds respectively), you should be seeing an improvement in behaviour without sacrificing a lot in terms of quick updates.
+
+ The webserver also displays the efficiency of the new Query Cache.
+
+ The old Packet Cache is still there (and useful) but see [Authoritative Server Performance](authoritative/performance.md) for more details.
+
+- There is now the ability to shut off some logging at a very early stage. High performance sites doing thousands of queries/second may in fact spend most of their CPU time on attempting to write out logging, even though it is ignored by syslog. The new flag **log-dns-details**, on by default, allows the operator to kill most informative-only logging before it takes any cpu.
+- Flags which can be switched 'on' and 'off' can now also be set to 'off' instead of only to 'no' to turn them off.
+
+## Enhancements
+- Packet Cache is now case insensitive, leading to a higher hitrate because identical queries only differing in case now both match. Care is taken to restore the proper case in the answer sent out.
+- Packet Cache stores packets more efficiently now, savings are estimated at 50%.
+- The Packet Cache is now asynchronous which means that PowerDNS continues to answer questions while the cache is busy being purged or queried. Incidentally this will mean a cache miss where previously the question would wait until the cache became available again.
+
+ The upshot of this is that operators can call **pdns\_control purge** as often as desired without fearing performance loss. Especially the full, non-specific, purge was sped up tremendously.
+
+ This optimization is of little merit for small sites but is very important when running with a large packetcache, such as when using recursion under high load.
+
+- AXFR log messages now all contain the word 'AXFR' to ease grepping.
+- Linux static version now compiled with gcc 3.2 which is known to output better and faster code than the previously used 3.0.4.
+
+## Bugs fixed
+- Packetcache would sometimes send packets back with slightly modified flags if these differed from the flags of the cached copy.
+- Resolver code did bad things with file descriptors leading to fd exhaustion after prolonged uptimes and many slave SOA currency checks.
+- Resolver code failed to properly log some errors, leading to operator uncertainty regarding to AXFR problems with remote masters.
+- After prolonged uptime, slave code would try to use privileged ports for originating queries, leading to bad replication efficiency.
+- Masters sending back answers in differing case from questions would lead to bogus 'Master tried to sneak in out-of-zone data' errors and failing AXFRs.
+
+# Version 2.4
+
+Developers: this version is compatible with the pdns-2.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [*Backend writers' guide*](appendix/backend-writers-guide.md "Backend writers' guide").
+
+This version fixes some stability issues with malformed or malcrafted packets. An upgrade is advised. Furthermore, there are interesting new features.
+
+## New features
+- Recursive queries are now also cached, but in a separate namespace so non-recursive queries don't get recursed answers and vice versa. This should mean way lower database load for sites running with the current default lazy-recursion. Up to now, each and every recursive query would lead to a large amount of SQL queries.
+
+ To prevent the packetcache from becoming huge, a separate **recursive-cache-ttl** can be specified.
+
+- The ability to change parameters at runtime was added. Currently, only the new **query-logging** flag can be changed.
+- Added **query-logging** flag which hints a backend that it should output a textual representation of queries it receives. Currently only gmysql and gpgsql2 honor this flag.
+- Gmysql backend can now also talk to PostgreSQL, leading to less code. Currently, the old postgresql driver ('gpgsql') is still the default, the new driver is available as 'gpgsql2' and has the benefit that it does query logging. In the future, gpgsql2 will become the default gpgsql driver.
+- DNS recursing proxy is now more verbose in logging odd events which may be caused by buggy recursing backends.
+- Webserver now displays peak queries/second 1 minute average.
+
+## Bugs fixed
+- Failure to connect to database in master/slave communicator thread could lead to an unclean reload, fixed.
+
+Documentation: added details for **strict-rfc-axfrs**. This feature can be used if very old clients need to be able to do zone transfers with PowerDNS. Very slow.
+
+# Version 2.3
+
+Developers: this version is compatible with the pdns-2.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [Backend writers' guide](appendix/backend-writers-guide.md "Backend writers' guide")
+
+This release adds the Generic MySQL backend which allows full master/slave semantics with MySQL and InnoDB tables (or other tables that support transactions). See [Generic MySQL backend](authoritative/backend-generic-mysql.md "Generic MySQL backend").
+
+## Other new features
+- Improved error messages in master/slave communicator will help down track problems.
+- **slave-cycle-interval** setting added. Very large sites with thousands of slave domains may need to raise this value above the default of 60. Every cycle, domains in indeterminate state are checked for their condition. Depending on the health of the masters, this may entail many SOA queries or attempted AXFRs.
+
+## Bugs fixed
+- 'pdns\_control purge **`domain`**' and 'pdns\_control purge **`domain$`**' were broken in version 2.2 and did not in fact purge the cache. There is a slight risk that domain-specific purge commands could force a reload in previous version. Thanks to Mike Benoit of NetNation for discovering this.
+- Master/slave communicator thread got confused in case of delayed answers from slow masters. While not causing harm, this caused inefficient behaviour when testing large amounts of slave domains because additional 'cycles' had to pass before all domains would have their status ascertained.
+- Backends implementing special SOA semantics (currently only the undocumented 'pdns express backend', or homegrown backends) would under some circumstances not answer the SOA record in case of an ANY query. This should put an end to the last DENIC problems. Thanks to DENIC for helping us find the problem.
+
+# Version 2.2
+Developers: this version is compatible with the pdns-2.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [Backend writers' guide](appendix/backend-writers-guide.md "Backend writers' guide")
+
+Again a big release. PowerDNS is seeing some larger deployments in more demanding environments and these are helping shake out remaining issues, especially with recursing backends.
+
+The big news is that wildcard CNAMEs are now supported, an oft requested feature and nearly the only part in which PowerDNS differed from BIND in authoritative capabilities.
+
+If you were seeing signal 6 errors in PowerDNS causing reloads and intermittent service disruptions, please upgrade to this version.
+
+For operators of PowerDNS Express trying to host .DE domains, the very special **soa-serial-offset** feature has been added to placate the new DENIC requirement that the SOA serial be at least six digits. PowerDNS Express uses the SOA serial as an actual serial and not to insert dates and hence often has single digit soa serial numbers, causing big problems with .DE redelegations.
+
+## Bugs fixed
+
+- Malformed or shortened TCP recursion queries would cause a signal 6 and a reload. Same for EOF from the TCP recursing backend. Thanks to Simon Kirby and Mike Benoit of NetNation for helping debug this.
+- Timeouts on the TCP recursing backend were far too long, leading to possible exhaustion of TCP resolving threads.
+- **pdns\_control purge domain** accidentally cleaned all packets with that name as a prefix. Thanks to Simon Kirby for spotting this.
+- Improved exception error logging - in some circumstances PowerDNS would not properly log the cause of an exception, which hampered problem resolution.
+
+## New features
+- Wildcard CNAMEs now work as expected!
+- **pdns\_control purge** can now also purge based on suffix, allowing operators to purge an entire domain from the packet cache instead of only specific records. See also [pdns\_control](authoritative/running.md#pdnscontrol "pdns_control") Thanks to Mike Benoit for this suggestion.
+- **soa-serial-offset** for installations with small SOA serial numbers wishing to register .DE domains with DENIC which demands six-figure SOA serial numbers. See also [Chapter 21, *Index of all Authoritative Server settings*](authoritative/settings.md "Index of all Authoritative Server settings").
+
+# Version 2.1
+This is a somewhat bigger release due to pressing demands from customers. An upgrade is advised for installations using Recursion. If you are using recursion, it is vital that you are aware of changes in semantics. Basically, local data will now override data in your recursing backend under most circumstances. Old behaviour can be restored by turning **lazy-recursion** off.
+
+Developers: this version has a new pdns-2.1 development kit, available on <http://downloads.powerdns.com/releases/dev>. See also [Backend writers' guide](appendix/backend-writers-guide.md).
+
+**Warning**: Most users will run a static version of PowerDNS which has no dependencies on external libraries. However, some may need to run the dynamic version. This warning applies to these users.
+
+To run the dynamic version of PowerDNS, which is needed for backend drivers which are only available in source form, gcc 3.0 is required. RedHat 7.2 comes with gcc 3.0 as an optional component, RedHat 7.3 does not. However, the RedHat 7.2 Update gcc rpms install just fine on RedHat 7.3. For Debian, we suggest running 'woody' and installing the g++-3.0 package. We expect to release a FreeBSD dynamic version shortly.
+
+## Bugs fixed
+- RPM releases sometimes overwrote previous configuration files. Thanks to Jorn Ekkelenkamp of Hubris/ISP Services for reporting this.
+- TCP recursion sent out overly large responses due to a byte order mistake, confusing some clients. Thanks to the capable engineers of NetNation for bringing this to our attention.
+- TCP recursion in combination with a recursing backend on a non-standard port did not work, leading to a non-functioning TCP listener. Thanks to the capable engineers of NetNation for bringing this to our attention.
+
+## Unexpected behaviour
+- Wildcard URL records where not implemented because they are a performance penalty. To turn these on, enable **wildcard-url** in the configuration.
+- Unlike other nameservers, local data did not override the internet for recursing queries. This has mostly been brought into conformance with user expectations. If a recursive question can be answered entirely from local data, it is. To restore old behaviour, disable **lazy-recursion**. Also see [Recursion](authoritative/recursion.md "Recursion").
+
+## Features
+- Oracle support has been tuned, leading to the first public release of the Oracle backend. Zone2sql now outputs better SQL and the backend is now fully documented. Furthermore, the queries are compatible with the PowerDNS XML-RPC product, allowing PowerDNS express to run off Oracle. See [Oracle backend](authoritative/backend-oracle.md "Oracle backend").
+- Zone2sql now accepts --transactions to wrap zones in a transaction for PostgreSQL and Oracle output. This is a major speedup and also makes for better isolation of inserts. See [Zone2sql](authoritative/migration.md#zone2sql "Zone2sql").
+- **pdns\_control** now has the ability to purge the PowerDNS cache or parts of it. This enables operators to raise the TTL of the Packet Cache to huge values and only to invalidate the cache when changes are made. See also [Authoritative Server Performance](authoritative/performance.md "Authoritative Server Performance") and [pdns\_control](authoritative/running.md#pdnscontrol "pdns_control").
+
+# Version 2.0.1
+Maintenance release, fixing three small issues.
+
+Developers: this version is compatible with 1.99.11 backends.
+
+- PowerDNS ignored the **logging-facility** setting unless it was specified on the command line. Thanks to Karl Obermayer from WebMachine Technologies for noticing this.
+- Zone2sql neglected to preserve 'slaveness' of domains when converting to the slave capable PostgreSQL backend. Thanks to Mike Benoit of NetNation for reporting this. Zone2sql now has a **--slave** option.
+- SOA Hostmaster addresses with dots in them before the @-sign were mis-encoded on the wire.
+
+# Version 2.0
+Two bugfixes, one stability/security related. No new features.
+
+Developers: this version is compatible with 1.99.11 backends.
+
+Bugfixes
+- zone2sql refused to work under some circumstances, taking 100% cpu and not functioning. Thanks to Andrew Clark and Mike Benoit for reporting this.
+- Fixed a stability issue where malformed packets could force PowerDNS to reload. Present in all earlier 2.0 versions.
+
+# Version 2.0 Release Candidate 2
+Mostly bugfixes, no really new features.
+
+Developers: this version is compatible with 1.99.11 backends.
+
+## Bugs fixed
+- chroot() works again - 2.0rc1 silently refused to chroot. Thanks to Hub Dohmen for noticing this.
+- setuid() and setgid() security features were silently not being performed in 2.0rc1. Thanks to Hub Dohmen for noticing this.
+- MX preferences over 255 now work as intended. Thanks to Jeff Crowe for noticing this.
+- IPv6 clients can now also benefit from the recursing backend feature. Thanks to Andy Furnell for proving beyond any doubt that this did not work.
+- Extremely bogus code removed from DNS notification reception code - please test! Thanks to Jakub Jermar for working with us in figuring out just how broken this was.
+- AXFR code improved to handle more of the myriad different zone transfer dialects available. Specifically, interoperability with Bind 4 was improved, as well as Bind 8 in 'strict rfc conformance' mode. Thanks again for Jakub Jermar for running many tests for us. If your transfers failed with 'Unknown type 14!!' or words to that effect, this was it.
+
+## Features
+- Win32 version now has a zone2sql tool.
+- Win32 version now has support for specifying how urgent messages should be before they go to the NT event log.
+
+## Remaining issues
+- One persistent report of the default 'chroot=./' configuration not working.
+- One report of disable-axfr and allow-axfr-ips not working as intended.
+- Support for relative paths in zones and in Bind configuration is not bug-for-bug compatible with bind yet.
+
+# Version 2.0 Release Candidate 1
+The MacOS X release! A very experimental OS X 10.2 build has been added. Furthermore, the Windows version is now in line with Unix with respect to capabilities. The ODBC backend now has the code to function as both a master and a slave.
+
+Developers: this version is compatible with 1.99.11 backends.
+
+- Implemented native packet response parsing code, allowing Windows to perform AXFR and NS and SOA queries.
+- This is the first version for which we have added support for Darwin 6.0, which is part of the forthcoming Mac OS X 10.2. Please note that although this version is marked RC1, that we have not done extensive testing yet. Consider this a technology preview.
+ - The Darwin version has been developed on Mac OS X 10.2 (6C35). Other versions may or may not work.
+ - Currently only the random, bind, mysql and pdns backends are included.
+ - The menu based installer script does not work, you will have to edit pathconfig by hand as outlined in chapter 2.
+ - On Mac OS X Client, PowerDNS will fail to start because a system service is already bound to port 53.
+
+ This version is distributed as a compressed tar file. You should follow the generic UNIX installation instructions.
+
+## Bugs fixed
+- Zone2sql PostgreSQL mode neglected to lowercase $ORIGIN. Thanks to Maikel Verheijen of Ladot for spotting this.
+- Zone2sql PostgreSQL mode neglected to remove a trailing dot from $ORIGIN if present. Thanks to Thanks to Maikel Verheijen of Ladot for spotting this.
+- Zone file parser was not compatible with bind when $INCLUDING non-absolute file names. Thanks to Jeff Miller for working out how this should work.
+- Bind configuration parser was not compatible with bind when including non-absolute file names. Thanks to Jeff Miller for working out how this should work.
+- Documentation incorrectly listed the Bind backend as 'slave capable'. This is not yet true, now labeled 'experimental'.
+
+Windows changes. We are indebted to Dimitry Andric who educated us in the ways of distributing Windows software.
+
+- `pdns.conf` is now read if available.
+- Console version responds to ^c now.
+- Default pdns.conf added to distribution
+- Uninstaller missed several files, leaving remnants behind
+- DLLs are now installed locally, with the pdns executable.
+- pdns\_control is now also available on Windows
+- ODBC backend can now act as master and slave. Experimental.
+- The example zone missed indexes and had other faults.
+- A runtime DLL that is present on most windows systems (but not all!) was missing.
+
+# Version 1.99.12 Prerelease
+The Windows release! See [Installing on Microsoft Windows](authoritative/installation.md). Beware, windows support is still very fresh and untested. Feedback is very welcome.
+
+Developers: this version is compatible with 1.99.11 backends.
+
+- Windows 2000 code base merge completed. This resulted in quite some changes on the Unix end of things, so this may impact reliability.
+- ODBC backend added for Windows. See [ODBC backend](authoritative/backend-deprecated.md#odbc-backend).
+- IBM DB2 Universal Database backend available for Linux. See [DB2 backend](authoritative/backend-deprecated.md#db2-backend "DB2 backend").
+- Zone2sql now understands $INCLUDE. Thanks to Amaze Internet for nagging about this
+- The SOA Minimum TTL now has a configurable default (**soa-minimum-ttl**)value to placate the DENIC requirements.
+- Added a limit on the simultaneous numbers of TCP connections to accept (**max-tcp-connections**). Defaults to 10.
+
+## Bugs fixed
+- When operating in virtual hosting mode (See [Virtual hosting](authoritative/running.md#virtual-hosting "Virtual hosting")), the additional init.d scripts would not function correctly and interface with other pdns instances.
+- PowerDNS neglected to conserve case on answers. So a query for WwW.PoWeRdNs.CoM would get an answer listing the address of www.powerdns.com. While this did not confuse resolvers, it is better to conserve case. This has semantic consequences for all backends, which the documentation now spells out.
+- PostgreSQL backend was case sensitive and returned only answers in case an exact match was found. The Generic PostgreSQL backend is now officially all lower case and zone2sql in PostgreSQL mode enforces this. Documentation has been been updated to reflect the case change. Thanks to Maikel Verheijen of Ladot for spotting this!
+- Documentation bug - postgresql create/index statements created a duplicate index. If you've previously copy pasted the commands and not noticed the error, execute **CREATE INDEX rec\_name\_index ON records(name)** to remedy. Thanks to Jeff Miller for reporting this. This also lead to depressingly slow 'ANY' lookups for those of you doing benchmarks.
+
+## Features
+- pdns\_control (see [pdns\_control](authoritative/running.md#pdnscontrol "pdns_control")) now opens the local end of its socket in `/tmp` instead of next to the remote socket (by default `/var/run`). This eases the way for allowing non-root access to pdns\_control. When running chrooted (see [Chapter 7, *Security settings & considerations*](common/security.md "Security settings & considerations")), the local socket again moves back to `/var/run`.
+- pdns\_control now has a 'version' command. See [Section 1.1, “pdns\_control”](authoritative/running.md#pdnscontrol "1.1. pdns_control").
+
+# Version 1.99.11 Prerelease
+This release is important because it is the first release which is accompanied by an Open Source Backend Development Kit, allowing external developers to write backends for PowerDNS. Furthermore, a few bugs have been fixed
+
+- Lines with only whitespace in zone files confused PowerDNS (thanks Henk Wevers)
+- PowerDNS did not properly parse TTLs with symbolic suffixes in zone files, ie 2H instead of 7200 (thanks Henk Wevers)
+
+# Version 1.99.10 Prerelease
+**IMPORTANT**: there has been a tiny license change involving free public webbased dns hosting, check out the changes before deploying!
+
+PowerDNS is now feature complete, or very nearly so. Besides adding features, a lot of 'fleshing out' work is done now. There is an important performance bug fix which may have lead to disappointing benchmarks - so if you saw any of that, please try either this version or 1.99.8 which also does not have the bug.
+
+This version has been very stable for us on multiple hosts, as was 1.99.9.
+
+PostgreSQL users should be aware that while 1.99.10 works with the schema as presented in earlier versions, advanced features such as master or slave support will not work unless you create the new 'domains' table as well.
+
+## Bugs fixed
+- Wildcard AAAA queries sometimes received an NXDOMAIN error where they should have gotten an empty NO ERROR. Thanks to Jeroen Massar for spotting this on the .TK TLD!
+- Do not disable the packetcache for 'recursion desired' packets unless a recursor was configured. Thanks to Greg Schueler for noticing this.
+- A failing backend would not be reinstated. Thanks to 'Webspider' for discovering this problem with PostgreSQL connections that die after prolonged inactivity.
+- Fixed loads of IPv6 transport problems. Thanks to Marco Davids and others for testing. Considered ready for production now.
+- **Zone2sql** printed a debugging statement on range $GENERATE commands. Thanks to Rene van Valkenburg for spotting this.
+
+## Features
+- PowerDNS can now act as a master, sending out notifications in case of changes and allowing slaves to AXFR. Big rewording of replication support, domains are now either 'native', 'master' or 'slave'. See [Master/Slave operation & replication](authoritative/modes-of-operation.md "Master/Slave operation & replication") for lots of details.
+- **Zone2sql** in PostgreSQL mode now populates the 'domains' table for easy master, slave or native replication support.
+- Ability to run on IPv6 transport only
+- Logging can now happen under a 'facility' so all PowerDNS messages appear in their own file. See [Operational logging using syslog](common/logging.md "Operational logging using syslog").
+- Different OS releases of PowerDNS now get different install path defaults. Thanks to Mark Lastdrager for nagging about this and to Nero Imhard and Frederique Rijsdijk for suggesting saner defaults.
+- Infrastructure for 'also-notify' statements added.
+
+# Version 1.99.9 Early Access Prerelease
+This is again a feature and an infrastructure release. We are nearly feature complete and will soon start work on the backends to make sure that they are all master, slave and 'superslave' capable.
+
+## Bugs fixed
+- PowerDNS sometimes sent out duplicate replies for packets passed to the recursing backend. Mostly a problem on SMP systems. Thanks to Mike Benoit for noticing this.
+- Out-of-bailiwick CNAMEs (ie, a CNAME to a domain not in PowerDNS) caused a 'ServFail' packet in 1.99.8, indicating failure, leading to hosts not resolving. Thanks to Martin Gillstrom for noticing this.
+- Zone2sql balked at zones edited under operating systems terminating files with ^Z (Windows). Thanks Brian Willcott for reporting this.
+- PostgreSQL backend logged the password used to connect. Now only does so in case of failure to connect. Thanks to 'Webspider' for noticing this.
+- Debian unstable distribution wrongly depended on home compiled PostgreSQL libraries. Thanks to Konrad Wojas for noticing this.
+
+## Features
+- When operating as a slave, AAAA records are now supported in the zone. They were already supported in master zones.
+- IPv6 transport support - PowerDNS can now listen on an IPv6 socket using the **local-ipv6** setting.
+- Very silly randombackend added which appears in the documentation as a sample backend. See [Backend writers' guide](appendix/backend-writers-guide.md).
+- When transferring a slave zone from a master, out of zone data is now rejected. Malicious operators might try to insert bad records otherwise.
+- 'Supermaster' support for automatic provisioning from masters. See [Supermaster automatic provisioning of slaves](authoritative/modes-of-operation.md#supermaster "Supermaster automatic provisioning of slaves").
+- Recursing backend can now live on a non-standard (!=53) port. See [Recursion](authoritative/recursion.md "Recursion").
+- Slave zone retrieval is now queued instead of immediate, which scales better and is more resilient to temporary failures.
+- **max-queue-length** parameter. If this many packets are queued for database attention, consider the situation hopeless and respawn.
+
+## Internal
+- SOA records are now 'special' and each backend can optionally generate them in special ways. PostgreSQL backend does so when operating as a slave.
+- Writing backends is now a lot easier. See [Backend writers' guide](appendix/backend-writers-guide.md "Backend writers' guide").
+- Added Bindbackend to internal regression tests, confirming that it is compliant.
+
+# Version 1.99.8 Early Access Prerelease
+A lot of infrastructure work gearing up to 2.0. Some stability bugs fixed and a lot of new features.
+
+## Bugs fixed
+- Bindbackend was overly complex and crashed on some systems on startup. Simplified launch code.
+- SOA fields were not always properly filled in, causing default values to go out on the wire
+- Obscure bug triggered by malicious packets (we know who you are) in SOA finding code fixed.
+- Magic serial number calculation contained a double free leading to instability.
+- Standards violation, questions for domains for which PowerDNS was unauthoritative now get a SERVFAIL answer. Thanks to the IETF Namedroppers list for helping out with this.
+- Slowly launching backends were being relaunched at a great rate when queries were coming in while launching backends.
+- MySQL-on-unix-domain-socket on SMP systems was overwhelmed by the quick connection rate on launch, inserted a small 50ms delay.
+- Some SMP problems appear to be compiler related. Shifted to GCC 3.0.4 for Linux.
+- Ran ispell on documentation.
+
+## Feature enhancements
+- Recursing backend. See [Recursion](authoritative/recursion.md "Recursion"). Allows recursive and authoritative DNS on the same IP address.
+- [NAPTR support](types.md#naptr), which is especially useful for the ENUM/E.164 community.
+- Zone transfers can now be allowed per [netmask instead of only per IP address](authoritative/settings.md#allow-axfr-ips).
+- Preliminary support for slave operation included. Only for the adventurous right now! See [Slave operation](authoritative/modes-of-operation.md "Slave operation")
+- All record types now documented, see [Supported record types and their storage](types.md "Supported record types and their storage").
+
+## Known bugs
+- Wildcard CNAMEs do not work as they do with bind.
+- Recursion sometimes sends out duplicate packets (fixed in 1.99.9 snapshots)
+- Some stability issues which are caught by the guardian
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend
+
+# Version 1.99.7 Early Access Prerelease
+Named.conf parsing got a lot of work and many more bind configurations can now be parsed. Furthermore, error reporting was improved. Stability is looking good.
+
+## Bugs fixed
+- Bind parser got confused by file names with underscores and colons.
+- Bind parser got confused by spaces in quoted names
+- FreeBSD version now stops and starts when instructed to do so.
+- Wildcards were off by default, which violates standards. Now on by default.
+- --oracle was broken in zone2sql
+
+## Feature enhancements
+- Line number counting goes on as it should when including files in named.conf
+- Added --no-config to enable users to start the pdns daemon without parsing the configuration file.
+- zone2sql now has --bare for unformatted output which can be used to generate insert statements for different database layouts
+- zone2sql now has --gpgsql, which is an alias for --mysql, to output in a format useful for the default Generic PostgreSQL backend
+- zone2sql is now documented.
+
+## Known bugs
+Wildcard CNAMEs do not work as they do with bind.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.6 Early Access Prerelease
+
+This version is now running on dns-eu1.powerdns.net and working very well for us. But please remain cautious before deploying!
+
+## Bugs fixed
+- Webserver neglected to show log messages
+- TCP question/answer miscounted multiple questions over one socket. Fixed misnaming of counter
+- Packetcache now detects clock skew and times out entries
+- named.conf parser now reports errors with line number and offending token
+- File names in named.conf can now contain:
+
+## Feature enhancements
+- The webserver now by default does not print out configuration statements, which might contain database backends. Use **webserver-print-arguments** to restore the old behaviour.
+- Generic PostgreSQL backend is now included. Still rather beta.
+
+## Known bugs
+- FreeBSD version does not stop when requested to do so.
+- Wildcard CNAMEs do not work as they do with bind.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.5 Early Access Prerelease
+The main focus of this release is stability and TCP improvements. This is the first release PowerDNS-the-company actually considers for running on its production servers!
+
+## Major bugs fixed
+- Zone2sql received a floating point division by zero error on named.confs with less than 100 domains.
+- Huffman encoder failed without specific error on illegal characters in a domain
+- Fixed huge memory leaks in TCP code.
+- Removed further file descriptor leaks in guardian respawning code
+- Pipebackend was too chatty.
+- pdns\_server neglected to close fds 0, 1 & 2 when daemonizing
+
+## Feature enhancements
+- bindbackend can be instructed not to check the ctime of a zone by specifying **bind-check-interval=0**, which is also the new default.
+- **pdns\_server --list-modules** lists all available modules.
+
+## Performance enhancements
+- TCP code now only creates a new database connection for AXFR.
+- TCP connections timeout rather quickly now, leading to less load on the server.
+
+## Known bugs
+- FreeBSD version does not stop when requested to do so.
+- Wildcard CNAMEs do not work as they do with bind.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend, gpgsqlbackend
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.4 Early Access Prerelease
+A lot of new named.confs can now be parsed, zone2sql & bindbackend have gained features and stability.
+
+## Major bugs fixed
+- Label compression was not always enabled, leading to large reply packets sometimes.
+- Database errors on TCP server lead to a nameserver reload by the guardian.
+- MySQL backend neglected to close its connection properly.
+- BindParser miss parsed some IP addresses and netmasks.
+- Truncated answers were also truncated on the packetcache, leading to truncated TCP answers.
+
+## Feature enhancements
+- Zone2sql and the bindbackend now understand the Bind $GENERATE{} syntax.
+- Zone2sql can optionally gloss over non-existing zones with **--on-error-resume-next**.
+- Zone2sql and the bindbackend now properly expand @ also on the right hand side of records.
+- Zone2sql now sets a default TTL.
+- DNS UPDATEs and NOTIFYs are now logged properly and sent the right responses.
+
+## Performance enhancements
+- 'Fancy records' are no longer queried for on ANY queries - this is a big speedup.
+
+## Known bugs
+- FreeBSD version does not stop when requested to do so.
+- Zone2sql refuses named.confs with less than 100 domains.
+- Wildcard CNAMEs do not work as they do with bind.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend, gpgsqlbackend
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.3 Early Access Prerelease
+The big news in this release is the BindBackend which is now capable of parsing many more named.conf Bind configurations. Furthermore, PowerDNS has successfully parsed very large named.confs with large numbers of small domains, as well as small numbers of large domains (TLD).
+
+Zone transfers are now also much improved.
+
+Major bugs fixed
+- zone2sql leaked file descriptors on each domain, used wrong Bison recursion leading to parser stack overflows. This limited the amount of domains that could be parsed to 1024.
+- zone2sql can now read all known zone files, with the exception of those containing $GENERATE
+- Guardian relaunching a child lost two file descriptors
+- Don't die on a connection reset by peer during zone transfer.
+- Webserver does not crash anymore on ringbuffer resize
+
+## Feature enhancements
+- AXFR can now be disabled, and re-enabled per IP address
+- --help accepts a parameter, will then show only help items with that prefix.
+- zone2sql now accepts a --zone-name parameter
+- BindBackend maturing - 9500 zones parsed in 3.5 seconds. No longer case sensitive.
+
+## Performance enhancements
+- Implemented RFC-breaking AXFR format (which is the industry standard). Zone transfers now zoom along at wire speed (many megabits/s).
+
+## Known bugs
+- FreeBSD version does not stop when requested to do so.
+- BindBackend cannot parse zones with $GENERATE statements.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+
+- gmysqlbackend, oraclebackend, gpgsqlbackend
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.2 Early Access Prerelease
+
+## Major bugs fixed
+- Database backend reload does not hang the daemon anymore
+- Buffer overrun in local socket address initialisation may have caused binding problems
+- setuid changed the uid to the gid of the selected user
+- zone2sql doesn't crash (dump core) on invocation anymore. Fixed lots of small issues.
+- Don't parse configuration file when creating configuration file. This was a problem with reinstalling.
+
+## Performance improvements
+- removed a lot of unnecessary gettimeofday calls
+- removed needless select(2) call in case of listening on only one address
+- removed 3 useless syscalls in the fast path
+
+Having said that, more work may need to be done. Testing on a 486 saw packet rates in a simple setup (question/wait/answer/question..) improve from 200 queries/second to over 400.
+
+## Usability improvements
+- Fixed error checking in init.d script (**show**, **mrtg**)
+- Added 'uptime' to the mrtg output
+- removed further GNUisms from installer and init.d scripts for use on FreeBSD
+- Debian package and apt repository, thanks to Wichert Akkerman.
+- FreeBSD /usr/ports, thanks to Peter van Dijk (in progress).
+
+Stability may be an issue as well as performance. This version has a tendency to log a bit too much which slows the nameserver down a lot.
+
+## Known bugs
+- Decreasing a ringbuffer on the website is a sure way to crash the daemon. Zone2sql, while improved, still has problems with a zone in the following format
+
+```
+name IN A 192.0.2.4
+ IN A 192.0.2.5
+```
+
+To fix, add 'name' to the second line.
+
+Zone2sql does not close file descriptors.
+
+FreeBSD version does not stop when requested via the init.d script.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release
+- gmysqlbackend, oraclebackend, gpgsqlbackend
+- fully functioning bindbackend - will try to parse named.conf, but probably fail
+
+Some of these features will be present in newer releases.
+
+# Version 1.99.1 Early Access Prerelease
+This is the first public release of what is going to become PowerDNS 2.0. As such, it is not of production quality. Even PowerDNS-the-company does not run this yet.
+
+Stability may be an issue as well as performance. This version has a tendency to log a bit too much which slows the nameserver down a lot.
+
+## Known bugs
+Decreasing a ringbuffer on the website is a sure way to crash the daemon. Zone2sql is very buggy.
+
+## Missing features
+Features present in this document, but disabled or withheld from the current release:
+
+- gmysqlbackend, oraclebackend, gpgsqlbackend
+- fully functioning bindbackend - will not parse configuration files
+
+Some of these features will be present in newer releases.
--- /dev/null
+In a production environment, you will want to be able to monitor PowerDNS performance. Furthermore, PowerDNS can perform a configurable amount of operational logging. This chapter also explains how to configure syslog for best results.
+
+# Logging
+This chapter assumes familiarity with syslog, the unix logging device. PowerDNS logs messages with different levels. The more urgent the message, the lower the 'priority'. By default, PowerDNS will only log messages with an urgency of 3 or lower, but this can be changed using the [loglevel](../authoritative/settings.md#loglevel) setting in the configuration file. Setting it to 0 will eliminate all logging, 9 will log everything.
+
+By default, logging is performed under the 'DAEMON' facility which is shared with lots of other programs. If you regard nameserving as important, you may want to have it under a dedicated facility so PowerDNS can log to its own files, and not clutter generic files.
+
+For this purpose, syslog knows about 'local' facilities, numbered from LOCAL0 to LOCAL7. To move PowerDNS logging to LOCAL0, add [`logging-facility`](../authoritative/settings.md#logging-facility)`=0` to your configuration.
+
+Furthermore, you may want to have separate files for the differing priorities - preventing lower priority messages from obscuring important ones.
+
+A sample syslog.conf might be:
+
+```
+local0.info -/var/log/pdns.info
+local0.warn -/var/log/pdns.warn
+local0.err /var/log/pdns.err
+```
+
+Where local0.err would store the really important messages. For performance and disk space reasons, it is advised to audit your `syslog.conf` for statements also logging PowerDNS activities. Many `syslog.conf`s have a '\*.\*' statement to /var/log/syslog, which you may want to remove.
+
+For performance reasons, be especially certain that no large amounts of synchronous logging take place. Under Linux, this is indicated by file names not starting with a '-' - indicating a synchronous log, which hurts performance.
+
+Be aware that syslog by default logs messages at the configured priority and higher! To log only info messages, use `local0.=info`
+
+# Performance Monitoring
+Both PowerDNS daemons generate ample metrics which can be used to monitor performance. These metrics can be polled using the rec\_control and pdns\_control commands, and they are also available via the http-based API. Finally, they can be pushed to a Carbon/Graphite server, either native carbon, or our own Metronome implementation.
+
+## Webserver
+To launch the internal webserver, add a [`webserver`](../authoritative/settings.md#webserver) statement to the `pdns.conf`. This will instruct the PowerDNS daemon to start a webserver on localhost at port 8081, without password protection. Only local users (on the same host) will be able to access the webserver by default, but we still strongly advise the use of a password protection. The webserver lists a lot of information about the PowerDNS process, including frequent queries, frequently failing queries, lists of remote hosts sending queries, hosts sending corrupt queries etc. The webserver does not allow remote management of the daemon. The following webserver related configuration items are available:
+
+* `webserver`: If set to anything but 'no', a webserver is launched.
+* `webserver-address`: Address to bind the webserver to. Defaults to 127.0.0.1, which implies that only the local computer is able to connect to the nameserver! To allow remote hosts to connect, change to 0.0.0.0 or the physical IP address of your nameserver.
+* `webserver-password`: If set, viewers will have to enter this plaintext password in order to gain access to the statistics.
+* `webserver-port`: Port to bind the webserver to.
+* `webserver-print-arguments`: Whether or not the webserver should print the server arguments.
+
+## Via init.d commands
+As mentioned before, the init.d commands **dump**, **show** and **mrtg** fetch data from a running PowerDNS process. Especially **mrtg** is powerful - it outputs data in a format that is ready for processing by the MRTG graphing tool.
+
+MRTG can make insightful graphics on the performance of your nameserver, enabling the operator to easily spot trends. MRTG can be found on the [MRTG website](http://oss.oetiker.ch/mrtg/).
+
+A sample mrtg.conf:
+
+```
+Interval: 5
+WorkDir: /var/www/mrtg
+WriteExpires: yes
+Options[_]: growright,nopercent
+XSize[_]: 600
+
+#---------------------------------------------------------------
+
+Target[udp-queries]: `/etc/init.d/pdns mrtg udp-queries udp-answers`
+Options[udp-queries]: growright,nopercent,perminute
+MaxBytes[udp-queries]: 600000
+AbsMax[udp-queries]: 600000
+Title[udp-queries]: Queries per minute
+PageTop[udp-queries]: <H2>Queries per minute</H2>
+WithPeak[udp-queries]: ymwd
+YLegend[udp-queries]: queries/minute
+ShortLegend[udp-queries]: q/m
+LegendI[udp-queries]: udp-questions
+LegendO[udp-queries]: udp-answers
+
+
+Target[perc-failed]: `/etc/init.d/pdns mrtg udp-queries udp-answers`
+Options[perc-failed]: growright,dorelpercent,perminute
+MaxBytes[perc-failed]: 600000
+AbsMax[perc-failed]: 600000
+Title[perc-failed]: Queries per minute, with percentage success
+PageTop[perc-failed]: <H2>Queries per minute, with percentage success</H2>
+WithPeak[perc-failed]: ymwd
+YLegend[perc-failed]: queries/minute
+ShortLegend[perc-failed]: q/m
+LegendI[perc-failed]: udp-questions
+LegendO[perc-failed]: udp-answers
+
+
+Target[packetcache-rate]: `/etc/init.d/pdns mrtg packetcache-hit udp-queries`
+Options[packetcache-rate]: growright,dorelpercent,perminute
+Title[packetcache-rate]: packetcache hitrate
+MaxBytes[packetcache-rate]: 600000
+AbsMax[packetcache-rate]: 600000
+PageTop[packetcache-rate]: <H2>packetcache hitrate</H2>
+WithPeak[packetcache-rate]: ymwd
+YLegend[packetcache-rate]: queries/minute
+ShortLegend[packetcache-rate]: q/m
+LegendO[packetcache-rate]: total
+LegendI[packetcache-rate]: hit
+
+Target[packetcache-missrate]: `/etc/init.d/pdns mrtg packetcache-miss udp-queries`
+Options[packetcache-missrate]: growright,dorelpercent,perminute
+Title[packetcache-missrate]: packetcache MISSrate
+MaxBytes[packetcache-missrate]: 600000
+AbsMax[packetcache-missrate]: 600000
+PageTop[packetcache-missrate]: <H2>packetcache MISSrate</H2>
+WithPeak[packetcache-missrate]: ymwd
+YLegend[packetcache-missrate]: queries/minute
+ShortLegend[packetcache-missrate]: q/m
+LegendO[packetcache-missrate]: total
+LegendI[packetcache-missrate]: MISS
+
+Target[latency]: `/etc/init.d/pdns mrtg latency`
+Options[latency]: growright,nopercent,gauge
+MaxBytes[latency]: 600000
+AbsMax[latency]: 600000
+Title[latency]: Query/answer latency
+PageTop[latency]: <H2>Query/answer latency</H2>
+WithPeak[latency]: ymwd
+YLegend[latency]: usec
+ShortLegend[latency]: usec
+LegendO[latency]: latency
+LegendI[latency]: latency
+
+Target[recursing]: `/etc/init.d/pdns mrtg recursing-questions recursing-answers`
+Options[recursing]: growright,nopercent,gauge
+MaxBytes[recursing]: 600000
+AbsMax[recursing]: 600000
+Title[recursing]: Recursive questions/answers
+PageTop[recursing]: <H2>Recursing questions/answers</H2>
+WithPeak[recursing]: ymwd
+YLegend[recursing]: queries/minute
+ShortLegend[recursing]: q/m
+LegendO[recursing]: recursing-questions
+LegendI[recursing]: recursing-answers
+```
+
+## Sending to Carbon/Graphite/Metronome
+For carbon/graphite/metronome, we use the following namespace. Everything starts with 'pdns.', which is then followed by the local hostname. Thirdly, we add either 'auth' or 'recursor' to siginify the daemon generating the metrics. This is then rounded off with the actual name of the metric. As an example: 'pdns.ns1.recursor.questions'.
+
+**Warning**: If your hostname includes dots, beyond 3.6.2 they will be
+replaced by underscores so as not to confuse the namespace. In 3.6.2 and earlier,
+any dots will remain unchanged. See below for how to override the hostname.
+
+Care has been taken to make the sending of statistics as unobtrusive as possible, the daemons will not be hindered by an unreachable carbon server, timeouts or connection refused situations.
+
+To benefit from our carbon/graphite support, either install Graphite, or use our own lightweight statistics daemon, Metronome, currently available on [GitHub](https://github.com/ahupowerdns/metronome/).
+
+Secondly, set [`carbon-server`](../authoritative/settings.md#carbon-server),
+possibly [`carbon-interval`](../authoritative/settings.md#carbon-interval)
+and possibly [`carbon-ourname`](../authoritative/settings.md#carbon-ourname)
+in the configuration.
+
+**Warning**: If you include dots in `carbon-ourname`, they will not be replaced by underscores,
+since PowerDNS assumes you know what you are doing if you override your hostname.
+
--- /dev/null
+# Security Settings
+PowerDNS has several options to easily allow it to run more securely. Most notable are the [`chroot`](../authoritative/settings.md#chroot), [`setuid`](../authoritative/settings.md#setuid) and [`setgid`](../authoritative/settings.md#setgid) options which can be specified.
+
+For additional information on PowerDNS security, PowerDNS security incidents and PowerDNS security policy, see [our security policy](../security/index.md).
+
+## Running as a less privileged identity
+
+By specifying [`setuid`](../authoritative/settings.md#setuid) and [`setgid`](../authoritative/settings.md#setgid), PowerDNS changes to this identity shortly after binding to the privileged DNS ports. These options are highly recommended. It is suggested that a separate identity is created for PowerDNS as the user 'nobody' is in fact quite powerful on most systems.
+
+Both these parameters can be specified either numerically or as real names. You should set these parameters immediately if they are not set!
+
+## Jailing the process in a chroot
+
+The [`chroot`](../authoritative/settings.md#chroot) option secures PowerDNS to its own directory so that even if it should become compromised and under control of external influences, it will have a hard time affecting the rest of the system.
+
+Even though this will hamper hackers a lot, chroot jails have been known to be broken.
+
+**Warning**: When chrooting PowerDNS, take care that backends will be able to get to their files. Many databases need access to a UNIX domain socket which should live within the chroot. It is often possible to hardlink such a socket into the chroot dir.
+
+When running with master or slave support, be aware that many operating systems need access to specific libraries (often `/lib/libnss*`) in order to support resolution of domain names! You can also hardlink these.
+
+In addition, make sure that `/dev/log` is available from within the chroot. Logging will silently fail over time otherwise (on logrotate).
+
+The default PowerDNS configuration is best chrooted to `./`, which boils down to the configured location of the controlsocket.
+
+This is achieved by adding the following to pdns.conf: `chroot=./`, and restarting PowerDNS.
+
+# Security Considerations
+In general, make sure that the PowerDNS process is unable to execute commands on your backend database. Most database backends will only need SELECT privilege. Take care to not connect to your database as the 'root' or 'sa' user, and configure the chosen user to have very slight privileges.
+
+Databases empathically do not need to run on the same machine that runs PowerDNS! In fact, in benchmarks it has been discovered that having a separate database machine actually improves performance.
+
+Separation will enhance your database security highly. Recommended.
+
+# Security Polling
+As of Authoritative Server 3.4.1 and Recursor 3.6.2, PowerDNS products can poll the security status of their respective versions. This polling, naturally, happens over DNS. If the result is that a given version has a security problem, the software will report this at level 'Error' during startup, and repeatedly during operations.
+
+By default, security polling happens on the domain 'secpoll.powerdns.com', but this can be changed with the security-poll-suffix. If this setting is made empty, no polling will take place. Organizations wanting to host their own security zones can do so by changing this setting to a domain name under their control.
+
+To make this easier, the zone used to host secpoll.powerdns.com is available [here](https://github.com/PowerDNS/pdns/blob/master/docs/secpoll.zone).
+
+To enable distributors of PowerDNS to signal that they have backported versions, the PACKAGEVERSION compilation-time macro can be used to set a distributor suffix.
+
+## Details
+PowerDNS software sadly sometimes has critical security bugs. Even though we send out notifications of these via all channels available, we find that not everybody actually find out about our security releases.
+
+To solve this, PowerDNS software will start polling for security notifications, and log these periodically. Secondly, the security status of the software will be reported using the built-in metrics. This allows operators to poll for the PowerDNS security status and alert on it.
+
+In the implementation of this idea, we have taken the unique role of operating system distributors into account. Specifically, we can deal with backported security fixes.
+
+Finally, this feature can be disabled, or operators can have the automated queries point at their own status service.
+
+### Implementation
+PowerDNS software periodically tries to resolve 'auth-x.y.z.security-status.secpoll.powerdns.com|TXT' or 'recursor-x.y.z.security-status.secpoll.powerdns.com'.
+
+The data returned is in one of the following forms:
+
+* NXDOMAIN or resolution failure -> 0
+* "1 Ok" -> 1
+* "2 Upgrade recommended for security reasons, see http://powerdns.com/..." -> 2
+* "3 Upgrade mandatory for security reasons, see http://powerdns.com/..." -> 3
+
+In cases 2 or 3, periodic logging commences. The metric security-status is set to 2 or 3 respectively. If at a later date, resolution fails, the security-status is not reset to 1. It could be lowered however if we discover the security status is less urgent than we thought.
+
+If resolution fails, and the previous security-status was 1, the new security-status becomes 0 ('no data'). If the security-status was higher than 1, it will remain that way, and not get set to 0.
+
+In this way, security-status of 0 really means 'no data', and can not mask a known problem.
+
+### Distributions
+Distributions frequently backport security fixes to the PowerDNS versions they ship. This might lead to a version number that is known to us to be insecure to be secure in reality.
+
+To solve this issue, PowerDNS can be compiled with a distribution setting which will move the security polls from: 'auth-x.y.z.security-status.secpoll.powerdns.com' to 'auth-x.y.z-n.debian.security-status.secpoll.powerdns.com
+
+Note two things, one, there is a separate namespace for debian, and secondly, we use the package version of this release. This allows us to know that 3.6.0-1 (say) is insecure, but that 3.6.0-2 is not.
+
+### Configuration Details
+The configuration setting 'security-poll-suffix' is by default set to 'secpoll.powerdns.com'. If empty, nothing is polled. This can be moved to 'secpoll.yourorganization.com'.
+
+If compiled with PACKAGEVERSION=3.1.6-abcde.debian, queries will be sent to "auth-3.1.6-abcde.debian.security-status.security-poll-suffix".
+
+### Delegation
+If a distribution wants to host its own file with version information, we can delegate dist.security-status.secpoll.powerdns.com to their nameservers directly.
--- /dev/null
+# Getting support, free and paid FAQ
+PowerDNS is an open source program so you may get help from the PowerDNS users'
+community or from its authors. You may also help others (please do).
+
+The PowerDNS company provides free support on the public mailing lists, and can
+help or support you in private as well. For first class and rapid support,
+please contact <a href="mailto:powerdns.support@powerdns.com">powerdns.support@powerdns.com</a>
+, or see [www.powerdns.com](http://www.powerdns.com).
+
+More information about the PowerDNS community, and its mailing lists, can be
+found on [its Wiki](http://wiki.powerdns.com). On the wiki, you will also find
+information on how to file bugs.
+
+Below, please find a list of common questions asked on our public mailing lists.
+
+## Help!
+Please try harder :-) Specifically, before people will be able to help you,
+they need to know a lot about your system. If you list more details, chances are
+you'll get better answers.
+
+## I have a question, what details should I supply?
+Start out with stating what you think should be happening. Quite often, wrong
+expectations are the actual problem. Furthermore, which database backend you
+use, your operating system, which version of PowerDNS you use and where you got
+it from (RPM, .DEB, tar.bz2). If you compiled it yourself, what were the
+./configure parameters.
+
+If at **all** possible, supply the actual name of your domain and the IP address
+of your server(s).
+
+## Where should I send my question?
+To a mailing list. Please email the authors directly only if you previously
+entered a support contract with them, or are considering doing so. For mailing
+list details, see [the mailing lists page](http://mailman.powerdns.com/mailman/listinfo/).
+
+Questions about using PowerDNS should be sent to the pdns-users list, questions
+about compiler errors or feature requests to pdns-dev.
+
+Before posting, read all FAQs.
+
+## My information is confidential, must I send it to the mailing list?
+If you desire privacy, please consider entering a support relationship with us,
+in which case we invite you to contact <a href="mailto:powerdns.support.sales@netherlabs.eu">powerdns.support.sales@netherlabs.eu</a>.
--- /dev/null
+# End of life statements
+The currently supported release train of PowerDNS is 3.x. The development train is 4.x.
+2.x is end of life.
+
+## PowerDNS Authoritative Server 2.x
+21st of May 2015
+
+PowerDNS Authoritative Server 2.9.22 was released more than 6 years ago, in
+January 2009. Because of its immense and durable popularity, some patch
+releases have been provided, the last one of which (2.9.22.6) was made
+available over three years ago in January 2012.
+
+The 2.9.22.x series contains a number of probable and actual violations of
+the DNS standards. In addition, some behaviours of 2.9.22.x are standards
+conforming but cause interoperability problems in 2015. Finally, 2.9.22.4
+and earlier are impacted by [PowerDNS Security Advisory 2012-01](https://doc.powerdns.com/md/security/powerdns-advisory-2012-01/), which means
+PowerDNS can be used in a Denial of Service attack.
+
+Although we have long been telling users that we can no longer support the
+use of 2.x, and urging upgrades to 3.x, with this statement we formally
+declare 2.x end of life.
+
+This means that any 2.x issues will not be addressed. This has been the case
+for a long time, but with this statement we make it formal.
+
+To upgrade to 3.x, please consult the [instructions on how to upgrade the
+database](https://doc.powerdns.com/md/authoritative/upgrading/#29x-to-30). If you need help with upgrading, we provide [migration services](https://www.powerdns.com/support-services-consulting.html) to
+our supported users. If you are currently running 2.9.22 and need help to
+tide you over, we can also provide that as part of a [support agreement](https://www.powerdns.com/support-services-consulting.html).
+
+But we urge everyone to move on to PowerDNS Authoritative Server 3.4 or
+later - it is a faster, more standards conforming and more powerful
+nameserver!
+
--- /dev/null
+PowerDNS API
+============
+
+PowerDNS features a built-in API. For the Authoritative Server, starting with
+version 3.4, for the Recursor starting with version 3.6.
+
+The released versions use the standard webserver password for authentication,
+while newer versions use a static API key mechanism (shown below).
+
+Try it
+------
+
+Install PowerDNS Authoritative with one of the gsql backends (i.e. MySQL,
+PostgreSQL or SQLite3).
+
+Then configure as follows:
+
+ api=yes
+ api-key=changeme
+ webserver=yes
+
+
+After restarting `pdns_server`, the following examples should start working:
+
+ # List zones
+ curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
+
+ # Create new zone "example.org" with nameservers ns1.example.org, ns2.example.org
+ curl -X POST --data '{"name":"example.org.", "kind": "Native", "masters": [], "nameservers": ["ns1.example.org.", "ns2.example.org."]}' -v -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones | jq .
+
+ # Show the new zone
+ curl -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org. | jq .
+
+ # Add a new record to the new zone (would replace any existing test.example.org/A records)
+ curl -X PATCH --data '{"rrsets": [ {"name": "test.example.org.", "type": "A", "ttl": 86400, "changetype": "REPLACE", "records": [ {"content": "192.0.5.4", "disabled": false } ] } ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org. | jq .
+
+ # Combined replacement of multiple RRsets
+ curl -X PATCH --data '{"rrsets": [
+ {"name": "test1.example.org.",
+ "type": "A",
+ "ttl": 86400,
+ "changetype": "REPLACE",
+ "records": [ {"content": "192.0.2.5", "disabled": false} ]
+ },
+ {"name": "test2.example.org.",
+ "type": "AAAA",
+ "ttl": 86400,
+ "changetype": "REPLACE",
+ "records": [ {"content": "2001:db8::6", "disabled": false} ]
+ }
+ ] }' -H 'X-API-Key: changeme' http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org. | jq .
+
+`jq` is a highly recommended tool for pretty-printing JSON. If you don't have
+`jq`, try `json_pp` or `python -mjson.tool` instead.
+
+When running multiple instances you might want to specify on which address the web server should run:
+
+ # IP Address of web server to listen on
+ webserver-address=127.0.0.1
+ # Port of web server to listen on
+ webserver-port=8081
+ # Web server access is only allowed from these subnets
+ webserver-allow-from=0.0.0.0/0,::/0
+
+Try it (Recursor edition)
+-------------------------
+
+Install PowerDNS Recursor, configured as follows:
+
+ webserver=yes
+ api-key=changeme
+ auth-zones=
+ forward-zones=
+ forward-zones-recurse=
+
+
+After restarting `pdns_recursor`, the following examples should start working:
+
+ curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/api/v1/servers/localhost | jq .
+ curl -v -H 'X-API-Key: changeme' http://127.0.0.1:8082/api/v1/servers/localhost/zones | jq .
+
+
+API Specification
+-----------------
+
+The complete API docs are available in [`api_spec.md`](http://doc.powerdns.com/md/httpapi/api_spec/).
+
+
+Additional help
+---------------
+
+For additional help, come to the `#powerdns` IRC channel on `irc.oftc.net`.
+
+
+Examples (Authoritative Server)
+===============================
+
+Show zone information and records
+---------------------------------
+
+ curl -H 'X-API-Key: changeme' \
+ http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org. | jq .
+
+Response:
+
+ {
+ "id": "example.org.",
+ "url": "api/v1/servers/localhost/zones/example.org.",
+ "name": "example.org.",
+ "kind": "Master",
+ "dnssec": false,
+ "account": "",
+ "masters": [],
+ "serial": 2015120401,
+ "notified_serial": 0,
+ "last_check": 0,
+ "soa_edit_api": "",
+ "soa_edit": "",
+ "rrsets": [
+ {
+ "comments": [],
+ "name": "example.org.",
+ "records": [
+ {
+ "content": "ns2.example.org.",
+ "disabled": false
+ },
+ {
+ "content": "ns1.example.org.",
+ "disabled": false
+ }
+ ],
+ "ttl": 86400,
+ "type": "NS"
+ },
+ {
+ "comments": [],
+ "name": "example.org.",
+ "type": "SOA",
+ "ttl": 86400,
+ "records": [
+ {
+ "disabled": false,
+ "content": "ns1.example.org. hostmaster.example.org. 2015120401 10800 15 604800 10800"
+ }
+ ]
+ },
+ {
+ "comments": [],
+ "name": "ns1.example.org.",
+ "type": "A",
+ "ttl": 86400,
+ "records": [
+ {
+ "content": "192.168.0.1",
+ "disabled": false
+ }
+ ]
+ },
+ {
+ "comments": [],
+ "name": "www.example.org.",
+ "type": "A",
+ "ttl": 86400,
+ "records": [
+ {
+ "disabled": false,
+ "content": "192.168.0.2"
+ }
+ }
+ }
+ ]
+ }
+
+
+Replace ns1.example.org
+-----------------------
+
+Based on the example.org zone above, replace the ns1.example.org A record with
+192.0.2.5:
+
+ curl -X PATCH --data '{"rrsets": [{
+ "name": "ns1.example.org.",
+ "type": "A",
+ "changetype": "REPLACE",
+ "records": [ {
+ "content": "192.0.2.5",
+ "disabled": false,
+ "name": "ns1.example.org.",
+ "ttl": 86400,
+ "type": "A"
+ }]
+ }]}' -H 'X-API-Key: changeme' \
+ http://127.0.0.1:8081/api/v1/servers/localhost/zones/example.org. | jq .
+
+Response:
+
+ {
+ "id": "example.org.",
+ ...
+ "records": [
+ {
+ "name": "ns1.example.org.",
+ "type": "A",
+ "ttl": 86400,
+ "disabled": false,
+ "content": "192.0.2.5"
+ },
+ ...
+ ],
+ ...
+ }
--- /dev/null
+API Spec
+========
+
+This API runs over HTTP, preferably HTTPS.
+
+Design Goals
+------------
+
+* Discovery endpoint
+* Unified API Scheme for Daemons & Console.
+ Think of the Console Server as a proxy for all your PowerDNS deployments.
+* Have API documentation (this!) for other consumers
+
+Data format
+-----------
+
+Input data format: JSON.
+
+Output data formats: JSON.
+
+The `Accept:` header determines the output format. An unknown value or
+`*/*` will cause a `400 Bad Request`.
+
+All text is UTF-8 and HTTP headers will reflect this.
+
+Data types:
+
+ * empty fields: `null` but present
+ * Regex: implementation defined
+ * Dates: ISO 8601
+
+
+REST
+----
+
+* GET: List/Retrieve. Success reply: `200 OK`
+* POST: Create. Success reply: `201 Created`, with new object as body.
+* PUT: Update. Success reply: `200 OK`, with modified object as body. For some operations, `204 No Content` is returned instead (and the modified object is not given in the body).
+* DELETE: Delete. Success reply: `200 OK`, no body.
+
+not-so-REST
+-----------
+
+For interactions that do not directly map onto CRUD, we use these:
+
+* GET: Query. Success reply: `200 OK`
+* PUT: Action/Execute. Success reply: `200 OK`
+
+Action/Execute methods return a JSON body of this format:
+
+ {
+ "message": "result message"
+ }
+
+
+Authentication
+--------------
+
+The PowerDNS daemons accept a static API Key, configured with the
+[`api-key`]('../authoritative/settings.md#api-key')
+option, which has to be sent in the `X-API-Key` header.
+
+Note: Authoritative Server 3.4.0 and Recursor 3.6.0 and 3.6.1 use HTTP
+Basic Authentication instead.
+
+
+Errors
+------
+
+Response code `4xx` or `5xx`, depending on the situation. Never return `2xx`
+for an error!
+
+* Invalid JSON body from client: `400 Bad Request`
+* JSON body from client not a hash: `400 Bad Request`
+* Input validation failed: `422 Unprocessable Entity`
+
+Error responses have a JSON body of this format:
+
+ {
+ "error": "short error message",
+ "errors": [
+ { ... },
+ ]
+ }
+
+Where `errors` is optional, and the contents are error-specific.
+
+
+Common Error Causes
+-------------------
+
+##### 400 Bad Request
+
+1. The client body was not a JSON document, or it could not be parsed, or the root element of the JSON document was not a hash.
+2. The client did not send an `Accept:` header, or it was set to `*/*`.
+3. For requests that operate on a zone, the `zone_id` URL part was invalid. To get a valid `zone_id`, list the zones with the `/api/v1/servers/:server_id/zones` endpoint.
+
+
+URL: /api
+---------
+
+Version discovery endpoint.
+
+Allowed methods: `GET`
+
+ [
+ {
+ "url": "/api/v1",
+ "version": 1
+ }
+ ]
+
+
+URL: /api/v1
+------------
+
+Allowed methods: `GET`
+
+ {
+ "server_url": "/api/v1/servers{/server}",
+ "api_features": []
+ }
+
+**TODO**:
+
+* Not yet implemented.
+* `api_features`
+ * `servers_modifiable`
+ * `oauth`
+
+
+General Collections Interface
+=============================
+
+Collections generally support `GET` and `POST` with these meanings:
+
+GET
+---
+
+Retrieve a list of all entries.
+
+The special `type` and `url` fields are included in the response objects:
+
+ * `type`: name of the resource type
+ * `url`: url to the object
+
+
+Response format:
+
+ [
+ obj1
+ [, further objs]
+ ]
+
+Example:
+
+ [
+ {
+ "type": "AType",
+ "id": "anid",
+ "url": "/atype/anid",
+ "a_field": "a_value"
+ },
+ {
+ "type": "AType",
+ "id": "anotherid",
+ "url": "/atype/anotherid",
+ "a_field": "another_value"
+ }
+ ]
+
+
+POST
+----
+
+Create a new entry. The client has to supply the entry in the request body,
+in JSON format. `application/x-www-form-urlencoded` data MUST NOT be sent.
+
+Clients SHOULD not send the 'url' field.
+
+Client body:
+
+ obj1
+
+Example:
+
+ {
+ "type": "AType",
+ "id": "anewid",
+ "a_field": "anew_value"
+ }
+
+
+
+
+Servers
+=======
+
+**TODO**: further routes
+
+
+server_resource
+---------------
+
+Example with server `"localhost"`, which is the only server returned by
+pdns\_server or pdns\_recursor.
+
+pdnsmgrd and pdnscontrol MUST NOT return “localhost”, but SHOULD return
+other servers.
+
+ {
+ "type": "Server",
+ "id": "localhost",
+ "url": "/api/v1/servers/localhost",
+ "daemon_type": "recursor",
+ "version": "VERSION",
+ "config_url": "/api/v1/servers/localhost/config{/config_setting}",
+ "zones_url": "/api/v1/servers/localhost/zones{/zone}",
+ }
+
+Note: On a pdns\_server or pdns\_recursor, the servers collection is read-only,
+and the only allowed returned server is read-only as well.
+On a pdnscontrol server, the servers collection is read-write, and the
+returned server resources are read-write as well. Write permissions may
+depend on the credentials you have supplied.
+
+* daemon_type
+ May be one of `authoritative`, `recursor`.
+
+
+URL: /api/v1/servers
+--------------------
+
+Collection access.
+
+Allowed REST methods:
+
+* pdns\_server: `GET`
+* pdns\_recursor: `GET`
+* pdnsmgrd: `GET`
+* pdnscontrol: `GET`, `PUT`, `POST`, `DELETE`
+
+
+URL: /api/v1/servers/:server\_id
+--------------------------------
+
+Returns a single server_resource.
+
+
+
+Config
+======
+
+
+config\_setting\_resource
+-------------------------
+
+ {
+ "type": "ConfigSetting",
+ "name": "config_setting_name",
+ "value": "config_setting_value"
+ }
+
+
+URL: /api/v1/servers/:server\_id/config
+---------------------------------------
+
+Collection access.
+
+Allowed REST methods: `GET`, `POST`
+
+#### POST
+
+Creates a new config setting. This is useful for creating configuration for new backends.
+
+**TODO**: Not yet implemented.
+
+
+URL: /api/v1/servers/:server\_id/config/:config\_setting\_name
+--------------------------------------------------------------
+
+Allowed REST methods: `GET`, `PUT`
+
+**NOTE**: only the Recursors `allow_from` configuration setting can be retrieved or modified.
+
+
+Zones
+=====
+
+Authoritative DNS Zones.
+
+A Resource Record Set (below as "RRset") are all records for a given name and type.
+
+Comments are per-RRset.
+
+
+zone_collection
+---------------
+
+ {
+ "id": "<id>",
+ "name": "<string>",
+ "type": "Zone",
+ "url": "/api/v1/servers/:server_id/zones/:id",
+ "kind": "<kind>",
+ "serial": <int>,
+ "notified_serial": <int>,
+ "masters": ["<ip>", ...],
+ "dnssec": <bool>,
+ "nsec3param": "<nsec3param record>",
+ "nsec3narrow": <bool>,
+ "presigned": <bool>,
+ "soa_edit": "<string>",
+ "soa_edit_api": "<string>",
+ "account": "<string>",
+ "nameservers": ["<string>", ...],
+ "servers": ["<string>", ...],
+ "recursion_desired": <bool>,
+ "rrsets": [<RRset>, ...],
+ }
+
+
+Where `RRset` is defined as:
+
+ {
+ "name": "<string>",
+ "type": "<type>",
+ "ttl": <int>,
+ "records": [<Record>, ...],
+ "comments": [<Comment>, ...]
+ }
+
+
+Where `Record` is defined as:
+
+ {
+ "content": "<string>",
+ "disabled": <bool>
+ }
+
+
+Where `Comment` is defined as:
+
+ {
+ "content": "<string>",
+ "account": "<string>",
+ "modified_at": <int>
+ }
+
+
+##### Parameters:
+
+* `id`
+ Opaque zone id (string), assigned by the Server. Do not interpret.
+ Guaranteed to be safe for embedding in URLs.
+
+* `name`
+ Zone name, always including the trailing dot. Example: `example.org.`
+ Note: Before 4.0.0, zone names were taken/given without the trailing dot.
+
+* `kind`
+ Authoritative: `<kind>`: `Native`, `Master` or `Slave`
+ Recursor: `<kind>`: `Native`, or `Forwarded`
+
+* `dnssec`
+ inferred from `presigned` being `true` XOR presence of at
+ least one cryptokey with `active` being `true`.
+
+ Switching `dnssec` to `true` (from `false`) sets up DNSSEC signing
+ based on the other flags, this includes running the equivalent of
+ `secure-zone` and `rectify-zone`. This also applies to newly created
+ zones.
+ If `presigned` is `true`, no DNSSEC changes will be made to the zone
+ or cryptokeys.
+ **Note**: Authoritative only.
+
+ **TODO**: `dnssec`, `nsec3narrow`, `nsec3param`, `presigned` are not yet implemented.
+
+* `soa_edit` MAY be set to change the `SOA-EDIT` zone setting. See
+ [the `SOA-EDIT` documentation](../authoritative/domainmetadata.md#soa-edit)
+ for more information.
+ **Note**: Authoritative only.
+
+* `soa_edit_api` MAY be set. If it is set, on changes to the contents of
+ a zone made through the API, the SOA record will be edited according to
+ the SOA-EDIT-API rules. (Which are the same as the SOA-EDIT-DNSUPDATE rules.)
+ If not set at all during zone creation, defaults to `DEFAULT`.
+ **Note**: Authoritative only.
+
+* `account` MAY be set. Its value is defined by local policy.
+ **Note**: Authoritative only.
+
+* `notified_serial`, `serial` MUST NOT be sent in client bodies.
+ **Note**: Authoritative only.
+
+* `nameservers` MAY be sent in client bodies during creation, and MUST
+ NOT be sent by the server. Simple list of strings of nameserver names,
+ including the trailing dot. Note: Before 4.0.0, names were taken without
+ the trailing dot.
+ **Note**: Authoritative only. Not required for slave zones.
+
+* `servers`: list of forwarded-to servers, including port.
+ **Note**: Recursor only.
+
+* `recursion_desired`: for `Forwarded` zones, if the RD bit should
+ be set.
+ **Note**: Authoritative only.
+
+* `rrsets`: list of DNS records and comments in the zone.
+ **Note**: Modifications are supported on Authoritative only.
+
+Please see the description for `PATCH` for details on the fields in
+`RRset`, `Record` and `Comment`.
+
+##### Notes:
+
+Turning on DNSSEC with custom keys: just create the zone with `dnssec`
+set to `false`, and add keys using the cryptokeys REST interface. Have
+at least one of them `active` set to `true`. **TODO**: not yet
+implemented.
+
+Changes made through the Zones API will always yield valid zone data,
+and the zone will be properly "rectified" (**TODO**: not yet
+implemented). If changes are made through other means (e.g. direct
+database access), this is not guaranteed to be true and clients SHOULD
+trigger rectify.
+
+Backends might implement additional features (by coincidence or not).
+These things are not supported through the API.
+
+When creating a slave zone, it is recommended to not set any of
+`nameservers`, `records`.
+
+
+URL: /api/v1/servers/:server\_id/zones
+--------------------------------------
+
+Allowed REST methods: `GET`, `POST`
+
+#### POST
+Creates a new domain.
+
+* `dnssec`, `nsec3narrow`, `presigned`, `nsec3param`, `active-keys` are OPTIONAL.
+* `dnssec`, `nsec3narrow`, `presigned` default to `false`.
+* The server MUST create a SOA record. The created SOA record SHOULD have
+serial set to the value given as `serial` (or 0 if missing), use the
+nameserver name, email, TTL values as specified in the PowerDNS configuration
+(`default-soa-name`, `default-soa-mail`, etc).
+These default values can be overridden by supplying a custom SOA record in
+the records list.
+If `soa_edit_api` is set, the SOA record is edited according to the SOA-EDIT-API
+rules before storing it. (Also applies to custom SOA records.)
+
+**TODO**: `dnssec`, `nsec3narrow`, `nsec3param`, `presigned` are not yet implemented.
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_id
+------------------------------------------------
+
+Allowed methods: `GET`, `PUT`, `DELETE`, `PATCH`.
+
+#### GET
+Returns zone information.
+
+#### DELETE
+Deletes this zone, all attached metadata and rrsets.
+
+#### PATCH
+
+Modifies present RRsets and comments.
+Returns `204 No Content` on success.
+
+**Note**: Authoritative only.
+
+Client body for PATCH:
+
+ { "rrsets":
+ [
+ {
+ "name": <string>,
+ "type": <string>,
+ "ttl": <int>,
+ "changetype": <changetype>,
+ "records":
+ [
+ {
+ "content": <string>,
+ "disabled": <bool>,
+ "set-ptr": <bool>
+ }, ...
+ ],
+ "comments":
+ [
+ {
+ "account": <string>,
+ "content": <string>,
+ "modfied_at": <int>
+ }, ...
+ ]
+ },
+ { ... }
+ ]
+ }
+
+
+* `name`
+ Full name of the RRset to modify. (Example: `foo.example.org.`)
+
+* `type`
+ Type of the RRset to modify. (Example: `AAAA`)
+
+* `ttl`
+ DNS TTL to apply to records replaced, in seconds. MUST NOT be included when `changetype` is set to `DELETE`.
+
+* `changetype`
+ Must be `REPLACE` or `DELETE`.
+ With `DELETE`, all existing RRs matching `name` and `type` will be deleted, including all comments.
+ With `REPLACE`: when `records` is present, all existing RRs matching `name` and `type` will be deleted, and then new records given in `records` will be created.
+ If no records are left, any existing comments will be deleted as well.
+ When `comments` is present, all existing comments for the RRs matching `name` and `type` will be deleted, and then new comments given in `comments` will be created.
+
+* `records`
+ List of new records (replacing the old ones). Must be empty when `changetype` is set to `DELETE`.
+ An empty list results in deletion of all records (and comments).
+ A record consists of these fields:
+ * `content`: the record content. Must confirm to the DNS content rules for the specified `type`. (PowerDNS hint: includes the backend's `priority` field.)
+ * `disabled`: if this record will be hidden from DNS. (true: hidden, false: visible (the default)).
+ * `set-ptr`: If set to true, the server will find the matching reverse zone and create a `PTR` there. Existing `PTR` records are replaced. If no matching reverse Zone, an error is thrown. Only valid in client bodies, only valid for `A` and `AAAA` types. Not returned by the server. Only valid for the Authoritative server.
+
+* `comments`
+ List of new comments (replacing the old ones). Must be empty when `changetype` is set to `DELETE`.
+ An empty list results in deletion of all comments.
+ `modified_at` is optional and defaults to the current server time.
+ `account` is a field with user-defined meaning.
+
+#### PUT
+
+Modifies basic zone data (metadata).
+
+Allowed fields in client body: all except `id` and `url`.
+Returns `204 No Content` on success.
+
+Changing `name` renames the zone, as expected.
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/notify
+-------------------------------------------------------
+
+Allowed methods: `PUT`
+
+Send a DNS NOTIFY to all slaves.
+
+Fails when zone kind is not `Master` or `Slave`, or `master` and `slave` are
+disabled in pdns configuration. Only works for `Slave` if renotify is on.
+
+Not supported for recursors.
+
+Clients MUST NOT send a body.
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/axfr-retrieve
+--------------------------------------------------------------
+
+Allowed methods: `PUT`
+
+Retrieves the zone from the master.
+
+Fails when zone kind is not `Slave`, or `slave` is disabled in PowerDNS.
+configuration.
+
+Not supported for recursors.
+
+**Note**: Added in 3.4.2
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/export
+-------------------------------------------------------
+
+Allowed methods: `GET`
+
+Returns the zone in AXFR format.
+
+Not supported for recursors.
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_id/check
+------------------------------------------------------
+
+Allowed methods: `GET`
+
+Verify zone contents/configuration.
+
+Return format:
+
+ {
+ "zone": "<zone_name>",
+ "errors": ["error message1", ...],
+ "warnings": ["warning message1", ...]
+ }
+
+**TODO**: Not yet implemented.
+
+Zone Metadata
+=============
+
+zone\_metadata\_resource
+------------------------
+
+ {
+ "type": "Metadata",
+ "kind": <metadata_kind>,
+ "metadata": [
+ "value1",
+ ...
+ ]
+ }
+
+Valid values for `<metadata_kind>` are specified in
+[the `domainmetadata` documentation](../authoritative/domainmetadata.md).
+
+Clients MUST NOT modify `NSEC3PARAM`, `NSEC3NARROW` or `PRESIGNED`
+through this interface. The server SHOULD reject updates to these
+metadata.
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/metadata
+-----------------------------------------------------------
+
+Collection access.
+
+Allowed methods: `GET`, `POST`
+
+**TODO**: Not yet implemented.
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/metadata/:metadata\_kind
+---------------------------------------------------------------------------
+
+Allowed methods: `GET`, `PUT`, `DELETE`
+
+**TODO**: Not yet implemented.
+
+CryptoKeys
+==========
+
+cryptokey\_resource
+-------------------
+
+ {[
+ "type": "CryptoKey",
+ "id": <int>,
+ "active": <bool>,
+ "keytype": <keytype>,
+ "dnskey": <string>,
+ "privatekey": <string>,
+ "ds": [ <ds>,
+ <ds>,
+ .... ]
+ ]}
+
+
+##### Parameters:
+
+`id`: read-only.
+
+`keytype`: `<keytype>` is one of the following: `ksk`, `zsk`, `csk`.
+
+`dnskey`: the DNSKEY for this key
+
+`ds`: an array with all DSes for this key
+
+`privatekey`: private key data (in ISC format).
+
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/cryptokeys
+-------------------------------------------------------------
+
+Allowed methods: `GET`, `POST`
+
+#### GET
+
+Returns all public data about cryptokeys, but not `privatekey`.
+
+#### POST
+
+Creates a new, single cryptokey.
+
+**TODO**: Not yet implemented.
+
+##### Parameters:
+
+`content`: if `null`, the server generates a new key. In this case, the
+following additional fields MAY be supplied:
+
+* `bits`: `<int>`
+* `algo`: `<algo>`
+
+Where `<algo>` is one of the supported key algorithms in lowercase OR the
+numeric id, see [`the list`](../authoritative/dnssec.md#supported-algorithms).
+
+URL: /api/v1/servers/:server\_id/zones/:zone\_name/cryptokeys/:cryptokey\_id
+----------------------------------------------------------------------------
+
+Allowed methods: `GET`, `PUT`, `DELETE`
+
+#### GET
+
+Returns all public data about cryptokeys, including `privatekey`.
+
+#### PUT
+
+**TODO**: Not yet implemented.
+
+#### DELETE
+
+**TODO**: Not yet implemented.
+
+Cache Access
+============
+
+**TODO**: Not yet implemented: Peek at the cache, clear the cache, possibly read cache?
+
+URL: /api/v1/servers/:server\_id/cache/flush?domain=:domain
+--------------------------------------------
+
+Allowed methods: `PUT` (Execute)
+
+#### PUT (Execute)
+
+Flush the cache for a given domain name `:domain`. Response body:
+
+ {
+ "count": 10,
+ "result": "Flushed cache."
+ }
+
+Implementation detail: On Authoritative servers, this clears the packet cache.
+On Recursors, this clears the positive, negative and packet cache.
+
+
+Logging & Statistics
+====================
+
+URL: /api/v1/servers/:server\_id/search-log?q=:search\_term
+-----------------------------------------------------------
+
+Allowed methods: `GET` (Query)
+
+#### GET (Query)
+
+Query the log, filtered by `:search_term` (query parameter). Response body:
+
+ [
+ "<log_line>",
+ ...
+ ]
+
+URL: /api/v1/servers/:server\_id/statistics
+-------------------------------------------
+
+Allowed methods: `GET` (Query)
+
+#### GET (Query)
+
+Query PowerDNS internal statistics. Response body:
+
+ [
+ {
+ "type": "StatisticItem",
+ "name": "<name>",
+ "value": "<value>"
+ },
+ ...
+ ]
+
+The statistic entries are dependent on the daemon type.
+Values are returned as strings.
+
+
+URL: /api/v1/servers/:server\_id/trace
+--------------------------------------
+
+**TODO**: Not yet implemented.
+
+#### PUT (Configure)
+
+Configure query tracing.
+
+Client body:
+
+ {
+ "domains": "<regex_string>"
+ }
+
+Set `domains` to `null` to turn off tracing.
+
+#### GET (Query)
+
+Retrieve query tracing log and current config. Response body:
+
+ {
+ "domains": "<Regex>",
+ log: [
+ "<log_line>",
+ ...
+ ]
+ }
+
+
+URL: /api/v1/servers/:server\_id/failures
+-----------------------------------------
+
+**TODO**: Not yet implemented.
+
+#### PUT
+
+Configure query failure logging.
+
+Client body:
+
+ {
+ "top-domains": <int>,
+ "domains": "<Regex>",
+ }
+
+##### Parameters:
+
+`top-domains` are the number of top resolved domains that are
+automatically monitored for failures.
+
+`domains` is a Regex of domains that are additionally monitored for
+resolve failures.
+
+
+#### GET
+
+Retrieve query failure logging and current config.
+
+Response body:
+
+ {
+ "top-domains": <int>,
+ "domains": "<Regex>",
+ "log": [
+ {
+ "first_occurred": <timestamp>,
+ "domain": "<full domain>",
+ "qtype": "<qtype>",
+ "failure": <failure_code>,
+ "failed_parent": "<full parent domain>",
+ "details": "<log message>",
+ "queried_servers": [
+ {
+ "name": <name>,
+ "address": <address>
+ }, ...
+ ]
+ },
+ ...
+ ]
+ }
+
+##### Parameters:
+
+`failed_parent` is generally OPTIONAL.
+
+Where `<failure_code>` is one of these:
+
+ + `dnssec-validation-failed`
+
+ DNSSEC Validation failed for this domain.
+
+ + `dnssec-parent-validation-failed`
+
+ DNSSEC Validation failed for one of the parent domains. Response
+ MUST contain failed\_parent.
+
+ + `nxdomain`
+
+ This domain was not present on the authoritative nameservers.
+
+ + `nodata`
+ + `all-servers-unreachable`
+
+ All auth nameservers that have been tried did not respond.
+
+ + `parent-unresolvable`
+
+ Response MUST contain `failed_parent`.
+
+ + `refused`
+
+ All auth nameservers that have been tried responded with REFUSED.
+
+ + `servfail`
+
+ All auth nameservers that have been tried responded with SERVFAIL.
+
+ + **TODO**: further failures
+
+Data Overrides
+==============
+
+**TODO**: Not yet implemented.
+
+override\_type
+--------------
+
+`created` is filled by the Server.
+
+
+ {
+ "type": "Override",
+ "id": <int>,
+ "override": "ignore-dnssec",
+ "domain": "nl",
+ "until": <timestamp>,
+ "created": <timestamp>
+ }
+
+
+ {
+ "type": "Override",
+ "id": <int>,
+ "override": "replace",
+ "domain": "www.cnn.com.",
+ "rrtype": "AAAA",
+ "values": ["203.0.113.4", "203.0.113..2"],
+ "until": <timestamp>,
+ "created": <timestamp>
+ }
+
+**TODO**: what about validation here?
+
+ {
+ "type": "Override",
+ "id": <int>,
+ "override": "purge",
+ "domain": "example.net.",
+ "created": <timestamp>
+ }
+
+Clears recursively all cached data ("plain" DNS + DNSSEC)
+
+**TODO**: should this be stored? (for history)
+
+URL: /api/v1/servers/:server\_id/overrides
+------------------------------------------
+
+**TODO**: Not yet implemented.
+
+Collection access.
+
+Allowed Methods: `GET`, `POST`
+
+URL: /api/v1/servers/:server\_id/overrides/:override\_id
+--------------------------------------------------------
+
+**TODO**: Not yet implemented.
+
+Allowed methods: `GET`, `PUT`, `DELETE`
--- /dev/null
+
+Features that should be doable using the API
+============================================
+
+New Console Features
+--------------------
+
+* RBAC
+* User Management
+* Audit Trail, light Edition
+* Cache Viewing
+* Versioning / Rollback
+ * for Zone data?
+* pcap capture triggering (-> pdnsmgr)
+* Zone (de)provisioning
+ * with DNSSEC
+* Improved Graphite
+
+DNSSEC Console for Recursor
+---------------------------
+
+* recent failures (not just DNSSEC)
+* trigger live logging (e.g. for “*.nl”)
+* DNSSEC partial blanking (“don’t check *.gov”)
+* DNSSEC temporary blanking (“not for next 24h”)
+
+Meta Features enabled by pdnsmgrd
+---------------------------------
+
+* start
+* stop
+* upgrade
+* restart
+ * TODO: can/should we do this inproc?
+* *pcap*
+ * TODO: How will this work?
+ * Should this happen in-daemon?
+
--- /dev/null
+Everything open for discussion.
+
+TODO:
+
+ * Everything marked as **TODO**
+ * Finish data management (tsigkeys, …)
+ * Incorporate applicable ideas from http://mailman.powerdns.com/pipermail/pdns-users/2013-February/009613.html
+
+Big Picture
+===========
+
+* HTTP with SSL in-process in Auth & Recursor
+* JSON API
+ * make it really great for us and other consumers
+ * “unified” API across Daemons and Console
+* pdnsmgrd
+ * cease to do SSL proxying
+ * become completely optional component
+ * only for “meta” features
+* Console
+ * get rid of all the API hacks
+ * new features as detailed below
+* CLI tool
+ * should talk to daemons and Console (if there)
+* “Pure” OOTB install
+ * miniature single page js app for users not installing pdnscontrol
+
+“Secondary” goals
+=================
+
+* keep everything lean
+* minimal intrusions into existing code
--- /dev/null
+> It is a book about a Spanish guy called Manual. You should read it.
+>
+> -- Dilbert
+
+# PowerDNS Nameserver
+There are two PowerDNS nameserver products: the [Authoritative Server](authoritative/index.md) and the [Recursor](recursor/index.md). While most other nameservers fully combine these functions, PowerDNS offers them separately, but can mix both authoritative and recursive usage seamlessly.
+The Authoritative Server will answer questions about domains it knows about, but will not go out on the net to resolve queries about other domains. However, it can use a recursing backend to provide that functionality. Depending on your needs, this backend can either be the PowerDNS recursor or an external one.
+When the Authoritative Server answers a question, it comes out of the database, and can be trusted as being authoritative. There is no way to pollute the cache or to confuse the daemon.
+
+The Recursor, conversely, by default has no knowledge of domains itself, but will always consult other authoritative servers to answer questions given to it.
+
+PowerDNS has been designed to serve both the needs of small installations by
+being easy to setup, as well as for serving very large query volumes on
+large numbers of domains. Additionally, through use of clever programming
+techniques, PowerDNS offers very high domain resolution performance.
+
+Another prime goal is security. By the use of language features, the PowerDNS
+source code is reasonably small which makes auditing easy. In the same way,
+library features have been used to mitigate the risks of buffer overflows.
+
+Finally, PowerDNS is able to give a lot of statistics on its operation which
+is both helpful in determining the scalability of an installation as well as
+for spotting problems.
+
+# Getting help
+There are several ways of getting help:
+
+* [The pretty .com website](https://www.powerdns.com) for commercial support
+* This documentation => [Getting support](common/support.md)
+* [The mailing lists](https://www.powerdns.com/mailing-lists.html)
+* \#powerdns on [irc.oftc.net](irc://irc.oftc.net/#powerdns)
+
+# About this document
+If you are reading this document from disk, you may want to check <http://doc.powerdns.com> for updates.
+
+To add to the PowerDNS documentation, or to fix mistakes, head to [Documentation details](appendix/documentation.md).
--- /dev/null
+# DNS64 support in the PowerDNS Recursor
+DNS64, described in [RFC 6147](https://tools.ietf.org/html/rfc6147) is a technology
+to allow IPv6-only clients to receive special IPv6 addresses that are proxied to
+IPv4 addresses. This proxy service is then called NAT64.
+
+So, as an example, let's say an IPv6 only client would want to connect to
+`www.example.com`, it would request the AAAA records for that name. However, if
+`example.com` does not actually have an IPv6 address, what we do is 'fake up' an
+IPv6 address. We do this by retrieving the A records for `www.example.com`, and
+translating them to AAAA records. Elsewhere, a NAT64 device listens on these IPv6
+addresses, and extracts the IPv4 address from each packet, and proxies it on.
+
+For maximum flexibility, DNS64 support is included in the [Lua scripting engine](scripting.md).
+This allows for example to hand out custom IPv6 gateway ranges depending on the
+location of the requestor, enabling the use of NAT64 services close to the user.
+
+
+Apart from faking AAAA records, it is also possible to also generate the
+associated PTR records. This makes sure that reverse lookup of DNS64-generated
+IPv6 addresses generate the right name. The procedure is similar, a request for
+an IPv6 PTR is converted into one for the corresponding IPv4 address.
+
+To setup DNS64, with both forward and reverse records, create the following Lua
+script and save it to a file called `dns64.lua`
+
+```
+!!include ../pdns/dns64.lua
+```
+
+Where fe80::21b::77ff:0:0 is your "Pref64" translation prefix and the "ip6.arpa"
+string is the reversed form of this Pref64 address. Now ensure your script gets
+loaded by specifying it with [`lua-dns-script=dns64.lua`](#settings.md#lua-dns-script).
+
+To enhance DNS64, see the [Lua scripting](scripting.md) documentation.
--- /dev/null
+# DNSSEC in the PowerDNS Recursor
+As of 4.0.0, the PowerDNS Recursor has support for DNSSEC processing and
+experimental support for DNSSEC validation.
+
+# DNSSEC settings
+The PowerDNS Recursor has 5 different levels of DNSSEC processing, which can be
+set with the [`dnssec`](settings.md#dnssec) setting in the `recursor.conf`. In
+order from least to most processing, these are:
+
+## `off`
+In this mode, **no** DNSSEC processing takes place. The PowerDNS Recursor will
+not set the DNSSEC OK (DO) bit in the outgoing queries and will ignore the DO and
+AD bits in queries. In this mode, the behaviour is equal to the PowerDNS Recursor
+3.X.
+
+## `process-no-validate`
+The default mode. In this mode the Recursor acts as a "security aware, non-validating"
+nameserver, meaning it will set the DO-bit on outgoing queries and will provide
+DNSSEC related RRsets (NSEC, RRSIG) to clients that ask for them (by means of a
+DO-bit in the query). It will not do any validation in this mode, not even when
+requested by the client.
+
+## `process`
+When `dnssec` is set to `process` the behaviour is similar to [`process-no-validate`](#process-no-validate).
+However, the recursor will try to validate the data if at least one of the DO or AD bits is set in the query; in that case, it will set the AD-bit in the response when the data is validated successfully, or send SERVFAIL when the validation comes up bogus.
+
+**Note:** in 4.0.0, only the AD-bit was considered when determining whether to validate.
+This lead to interoperability issues with older client software.
+From 4.0.1-onward, the DO-bit is also taken into account when determining whether to validate.
+
+## `log-fail`
+In this mode, the recursor will attempt to validate all data it retrieves from
+authoritative servers, regardless of the client's DNSSEC desires, and will log the
+validation result. This mode can be used to determine the extra load and amount
+of possibly bogus answers before turning on full-blown validation. Responses to
+client queries are the same as with `process`.
+
+## `validate`
+The highest mode of DNSSEC processing. In this mode, all queries will be be validated
+and will be answered with a SERVFAIL in case of bogus data, regardless of the
+client's request.
+
+## What, when?
+The descriptions above are a bit terse, here's a table describing different scenarios
+with regards to the `dnssec` mode.
+
+| | `off` | `process-no-validate` | `process` | `log-fail` | `validate` |
+|:------------|:-------|:-------------|:-------------|:-------------|:-------------|
+|Perform validation| No | No | Only on +AD or +DO from client | Always (logs result) | Always |
+|SERVFAIL on bogus| No | No | Only on +AD or +DO from client | Only on +AD or +DO from client | Always |
+|AD in response on authenticated data| Never | Never | Only on +AD or +DO from client | Only on +AD or +DO from client | Only on +AD or +DO from client |
+|RRSIGs/NSECs in answer on +DO from client| No | Yes | Yes | Yes | Yes |
+
+**Note**: the `dig` tool sets the AD-bit in the query. This might lead to unexpected
+query results when testing. Set `+noad` on the `dig` commandline when this is the
+case.
+
+# Trust Anchor Management
+In the PowerDNS Recursor, both positive and negative trust anchors can be configured
+during startup (from a persistent configuration file) and at runtime (which is
+volatile).
+However, all trust anchors are configurable.
+
+## Trust Anchors
+The PowerDNS Recursor ships with the DNSSEC Root key built-in. **Note**: is has
+no support yet for [RFC 5011](https://tools.ietf.org/html/rfc5011) key rollover
+and does not persist a changed root trust anchor to disk.
+
+Configuring DNSSEC key material must be done in the [`lua-config-file`](settings.md#lua-config-file),
+using `addDS`. This function takes 2 arguments, the node in the DNS-tree and the
+data of the corresponding DS record. To e.g. add a trust anchor for the root and
+powerdns.com, use the following config in the Lua file:
+
+```lua
+addDS('.', "63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a") -- This is not an ICANN root
+addDS('powerdns.com', "44030 8 2 D4C3D5552B8679FAEEBC317E5F048B614B2E5F607DC57F1553182D49 AB2179F7")
+```
+
+Now (re)start the recursor to load these trust anchors.
+
+### Runtime Configuration of Trust Anchors
+To change or add trust anchors at runtime, use the [`rec_control`](running.md)
+tool. These runtime settings are not saved to disk. To make them permanent, they
+should be added to the `lua-config-file` as described above.
+
+Adding a trust anchor is done with the `add-ta` command:
+
+```
+$ rec_control add-ta domain.example 63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a
+Added Trust Anchor for domain.example. with data 63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a
+```
+
+To view the currently configured trust anchors, run `show-tas`:
+
+```
+$ rec_control show-tas
+Configured Trust Anchors:
+. 63149 13 1 a59da3f5c1b97fcd5fa2b3b2b0ac91d38a60d33a
+net. 2574 13 1 a5c5acb889a7ba9b5aa5bef2b0ac9fe1565ddaab
+```
+
+To remove a trust anchor, run `clear-ta`:
+
+```
+$ rec_control clear-ta domain.example
+Removed Trust Anchor for subdomain.example
+```
+
+**Note**: The root trust anchor cannot be removed in this manner.
+
+## Negative Trust Anchors
+Negative trust anchors (defined in [RFC 7646](https://tools.ietf.org/html/rfc7646)
+can be used to temporarily disable DNSSEC validation for a part of the DNS-tree.
+This can be done when e.g. a TLD or high-traffic zone goes bogus. Note that it is
+good practice to verify that this is indeed the case and not because of malicious
+actions.
+
+To configure a negative trust anchor, use the `addNTA()` function in the
+[`lua-config-file`](settings.md#lua-config-file) and restart the recursor. This
+function requires the name of the zone and an optional reason:
+
+```lua
+addNTA('example.', "Someone messed up the delegation")
+addNTA('powerdns.com') -- No reason given
+```
+
+### Runtime Configuration of Negative Trust Anchors
+The [`rec_control`](running.md) command can be used to manage the negative trust
+anchors of a running instance. These runtime settings are lost when restarting
+the recursor, more permanent NTAs should be added to the `lua-config-file` with
+`addNTA()`.
+
+Adding a negative trust anchor is done with the `add-nta` command (that optionally
+accepts a reason):
+
+```
+$ rec_control add-nta domain.example botched keyroll
+Added Negative Trust Anchor for domain.example. with reason 'botched keyroll'
+```
+
+To view the currently configured negative trust anchors, run `show-ntas`:
+
+```
+$ rec_control show-ntas
+Configured Negative Trust Anchors:
+subdomain.example. Operator failed key-roll
+otherdomain.example. DS in parent, no DNSKEY in zone
+```
+
+To remove negative trust anchor(s), run `clear-nta`:
+
+```
+$ rec_control clear-nta subdomain.example
+Removed Negative Trust Anchors for subdomain.example
+```
+
+`clear-nta` accepts multiple domain-names and accepts '*' (beware the shell quoting)
+to remove all negative trust anchors.
--- /dev/null
+# PowerDNS Recursor
+The PowerDNS recursor is part of the source tarball of the main PowerDNS distribution, but it is released separately. Starting from the version 3.0 pre-releases, there are zero known bugs or issues with the recursor. It is known to power the resolving needs of over 100 million internet connections.
+
+The documentation is only for the 3.0 series, users of older versions are urged to upgrade!
+
+## Notable features:
+- Uses [MTasker](http://ds9a.nl/mtasker)
+- Can handle thousands of concurrent questions. A quad Xeon 3GHz has been measured functioning very well at 40000 real life replayed packets per second, with 40% cpu idle. More testing equipment is needed to max out the recursor.
+- Powered by a highly modern DNS packet parser that should be resistant against many forms of buffer overflows.
+- Best spoofing protection that we know about, involving both source port randomisation and spoofing detection.
+- Uses 'connected' UDP sockets which allow the recursor to react quickly to unreachable hosts or hosts for which the server is running, but the nameserver is down. This makes the recursor faster to respond in case of misconfigured domains, which are sadly very frequent.
+- Special support for FreeBSD, Linux and Solaris stateful multiplexing (kqueue, epoll, completion ports, /dev/poll).
+- Very fast, and contains innovative query-throttling code to save time talking to obsolete or broken nameservers.
+- Code is written linearly, sequentially, which means that there are no problems with 'query restart' or anything.
+- Relies heavily on Standard C++ Library infrastructure, which makes for little code (406 core lines).
+- Is very verbose in showing how recursion actually works, when enabled to do so with --verbose.
+- The algorithm is simple and quite nifty.
+
+The PowerDNS recursor is controlled and queried using the `rec_control` tool.
+
+## Configuration
+At startup, the recursing nameserver reads the file `recursor.conf` from the configuration directory, often `/etc/powerdns` or `/usr/local/etc`. Each setting can appear on the command line, prefixed by '--', or in the configuration file. The command line overrides the configuration file.
+
+A switch can be set to on simply by passing it, like '--daemon', and turned off explicitly by '--daemon=off' or '--daemon=no'.
+
+All settings can be found [here](settings.md)
+
+# `pdns_recursor` command line
+All configuration settings from the previous section can also be passed on the command line, and will override the configuration file. In addition, the following options make sense on the command line:
+
+* --config: Emit a default configuration file.
+* --help: Output all configuration settings and command line flags.
--- /dev/null
+# Design and Engineering of the PowerDNS Recursor
+**Warning**: This section is aimed at programmers wanting to contribute to the recursor, or to help fix bugs. It is not required reading for a PowerDNS operator, although it might prove interesting.
+
+The PowerDNS Recursor consists of very little code, the core DNS logic is less than a thousand lines.
+
+This smallness is achieved through the use of some fine infrastructure: MTasker, MOADNSParser, MPlexer and the C++ Standard Library/Boost. This page will explain the conceptual relation between these components, and the route of a packet through the program.
+
+# The PowerDNS Recursor
+
+The Recursor started out as a tiny project, mostly a technology demonstration. These days it consists of the core plus 9000 lines of features. This combined with a need for very high performance has made the recursor code less accessible than it was. The page you are reading hopes to rectify this situation.
+
+# Synchronous code using MTasker
+
+The original name of the program was **syncres**, which is still reflected in the file name `syncres.cc`, and the class SyncRes. This means that PowerDNS is written naively, with one thread of execution per query, synchronously waiting for packets, Normally this would lead to very bad performance (unless running on a computer with very fast threading, like possibly the Sun CoolThreads family), so PowerDNS employs [MTasker](http://ds9a.nl/mtasker) for very fast userspace threading.
+
+MTasker, which was developed separately from PowerDNS, does not provide a full multithreading system but restricts itself to those features a nameserver needs. It offers cooperative multitasking, which means there is no forced preemption of threads. This in turn means that no two **MThreads** ever really run at the same time.
+
+This is both good and bad, but mostly good. It means PowerDNS does not have to think about locking. No two threads will ever be talking to the DNS cache at the same time, for example.
+
+It also means that the recursor could block if any operation takes too long.
+
+The core interaction with MTasker are the waitEvent() and sendEvent() functions. These pass around PacketID objects. Everything PowerDNS needs to wait for is described by a PacketID event, so the name is a bit misleading. Waiting for a TCP socket to have data available is also passed via a PacketID, for example.
+
+The version of MTasker in PowerDNS is newer than that described at the MTasker site, with a vital difference being that the waitEvent() structure passes along a copy of the exact PacketID sendEvent() transmitted. Furthermore, threads can trawl through the list of events being waited for and modify the respective PacketIDs. This is used for example with **near miss** packets: packets that appear to answer questions we asked, but differ in the DNS id. On seeing such a packet, the recursor trawls through all PacketIDs and if it finds any nearmisses, it updates the PacketID::nearMisses counter. The actual PacketID thus lives inside MTasker while any thread is waiting for it.
+
+# MPlexer
+
+The Recursor uses a separate socket per outgoing query. This has the important benefit of making spoofing 64000 times harder, and additionally means that ICMP errors are reported back to the program. In measurements this appears to happen to one in ten queries, which would otherwise take a two-second timeout before PowerDNS moves on to another nameserver.
+
+However, this means that the program routinely needs to wait on hundreds or even thousands of sockets. Different operating systems offer various ways to monitor the state of sockets or more generally, file descriptors. To abstract out the differing strategies (`select`, `epoll`, `kqueue`, `completion ports`), PowerDNS contains **MPlexer** classes, all of which descend from the FDMultiplexer class.
+
+This class is very simple and offers only five important methods: addReadFD(), addWriteFD(), removeReadFD(), removeWriteFD() and run.
+
+The arguments to the **add** functions consist of an fd, a callback, and a boost::any variable that is passed as a reference to the callback.
+
+This might remind you of the MTasker above, and it is indeed the same trick: state is stored within the MPlexer. As long as a file descriptor remains within either the Read or Write active list, its state will remain stored.
+
+On arrival of a packet (or more generally, when an FD becomes readable or writable, which for example might mean a new TCP connection), the callback is called with the aforementioned reference to its parameter.
+
+The callback is free to call removeReadFD() or removeWriteFD() to remove itself from the active list.
+
+PowerDNS defines such callbacks as newUDPQuestion(), newTCPConnection(), handleRunningTCPConnection().
+
+Finally, the run() method needs to be called whenever the program is ready for new data. This happens in the main loop in pdns\_recursor.cc. This loop is what MTasker refers to as **the kernel**. In this loop, any packets or other MPlexer events get translated either into new MThreads within MTasker, or into calls to sendEvent(), which in turn wakes up other MThreads.
+
+# MOADNSParser
+
+Yes, this does stand for **the Mother of All DNS Parsers**. And even that name does not do it justice! The MOADNSParser is the third attempt I've made at writing DNS packet parser and after two miserable failures, I think I've finally gotten it right.
+
+Writing and parsing DNS packets, and the DNS records it contains, consists of four things:
+
+1. Parsing a DNS record (from packet) into memory
+2. Generating a DNS record from memory (to packet)
+3. Writing out memory to user-readable zone format
+4. Reading said zone format into memory
+
+This gets tedious very quickly, as one needs to implement all four operations for each new record type, and there are dozens of them.
+
+While writing the MOADNSParser, it was discovered there is a remarkable symmetry between these four transitions. DNS Records are nearly always laid out in the same order in memory as in their zone format representation. And reading is nothing but inverse writing.
+
+So, the MOADNSParser is built around the notion of a **Conversion**, and we write all Conversion types once. So we have a Conversion from IP address in memory to an IP address in a DNS packet, and vice versa. And we have a Conversion from an IP address in zone format to memory, and vice versa.
+
+This in turn means that the entire implementation of the ARecordContent is as follows (wait for it!)
+
+```
+conv.xfrIP(d_ip);
+```
+
+Through the use of the magic called `c++ Templates`, this one line does everything needed to perform the four operations mentioned above.
+
+At one point, I got really obsessed with PowerDNS memory use. So, how do we store DNS data in the PowerDNS recursor? I mentioned **memory** above a lot - this means we could just store the DNSRecordContent objects. However, this would be wasteful.
+
+For example, storing the following:
+
+```
+www.example.org 3600 IN CNAME outpost.example.org.
+```
+
+Would duplicate a lot of data. So, what is actually stored is a partial DNS packet. To store the CNAMEDNSRecordContent that corresponds to the above, we generate a DNS packet that has **www.example.org IN CNAME** as its question. Then we add **3600 IN CNAME outpost.example.org**. as its answer. Then we chop off the question part, and store the rest in the **www.example.org IN CNAME** key in our cache.
+
+When we need to retrieve **www.example.org IN CNAME**, the inverse happens. We find the proper partial packet, prefix it with a question for **www.example.org IN CNAME**, and expand the resulting packet into the answer **3600 IN CNAME outpost.example.org.**.
+
+Why do we go through all these motions? Because of DNS compression, which allows us to omit the whole **.example.org.** part, saving us 9 bytes. This is amplified when storing multiple MX records which all look more or less alike. This optimization is not performed yet though.
+
+Even without compression, it makes sense as all records are automatically stored very compactly.
+
+The PowerDNS recursor only parses a number of **well known record types** and passes all other information across verbatim - it doesn't have to know about the content it is serving.
+
+# The C++ Standard Library / Boost
+C++ is a powerful language. Perhaps a bit too powerful at times, you can turn a program into a real freakshow if you so desire.
+
+PowerDNS generally tries not to go overboard in this respect, but we do build upon a very advanced part of the [Boost](http://www.boost.org) C++ library: [boost::multi index container](http://boost.org/libs/multi_index/doc/index.html).
+
+This container provides the equivalent of SQL indexes on multiple keys. It also implements compound keys, which PowerDNS uses as well.
+
+The main DNS cache is implemented as a multi index container object, with a compound key on the name and type of a record. Furthermore, the cache is sequenced, each time a record is accessed it is moved to the end of the list. When cleanup is performed, we start at the beginning. New records also get inserted at the end. For DNS correctness, the sort order of the cache is case insensitive.
+
+The multi index container appears in other parts of PowerDNS, and MTasker as well.
+
+# Actual DNS Algorithm
+The DNS RFCs do define the DNS algorithm, but you can't actually implement it exactly that way, it was written in 1987.
+
+Also, like what happened to HTML, it is expected that even non-standards conforming domains work, and a sizable fraction of them is misconfigured these days.
+
+Everything begins with SyncRes::beginResolve(), which knows nothing about sockets, and needs to be passed a domain name, dns type and dns class which we are interested in. It returns a vector of DNSResourceRecord objects, ready for writing either into an answer packet, or for internal use.
+
+After checking if the query is for any of the hardcoded domains (localhost, version.bind, id.server), the query is passed to SyncRes::doResolve, together with two vital parameters: the `depth` and `beenthere` set. As the word **recursor** implies, we will need to recurse for answers. The **depth** parameter documents how deep we've recursed already.
+
+The `beenthere` set prevents loops. At each step, when a nameserver is queried, it is added to the `beenthere` set. No nameserver in the set will ever be queried again for the same question in the recursion process - we know for a fact it won't help us further. This prevents the process from getting stuck in loops.
+
+SyncRes::doResolve first checks if there is a CNAME in cache, using SyncRes::doCNAMECacheCheck, for the domain name and type queried and if so, changes the query (which is passed by reference) to the domain the CNAME points to. This is the cause of many DNS problems, a CNAME record really means **start over with this query**.
+
+This is followed by a call do SyncRes::doCacheCheck, which consults the cache for a straight answer to the question (as possibly rerouted by a CNAME). This function also consults the so called negative cache, but we won't go into that just yet.
+
+If this function finds the correct answer, and the answer hasn't expired yet, it gets returned and we are (almost) done. This happens in 80 to 90% of all queries. Which is good, as what follows is a lot of work.
+
+To recap:
+
+1. beginResolve() - entry point, does checks for hardcoded domains
+2. doResolve() - start of recursion process, gets passed `depth` of 0 and empty `beenthere` set
+3. doCNAMECacheCheck() - check if there is a CNAME in cache which would reroute the query
+4. doCacheCheck() - see if cache contains straight answer to possibly rerouted query.
+
+If the data we were queried for was in the cache, we are almost done. One final step, which might as well be optional as nobody benefits from it, is SyncRes::addCruft. This function does additional processing, which means that if the query was for the MX record of a domain, we also add the IP address of the mail exchanger.
+
+## The non-cached case
+This is where things get interesting, because we start out with a nearly empty cache and have to go out to the net to get answers to fill it.
+
+The way DNS works, if you don't know the answer to a question, you find somebody who does. Initially you have no other place to go than the root servers. This is embodied in the SyncRes::getBestNSNamesFromCache method, which gets passed the domain we are interested in, as well as the `depth` and `beenthere` parameters mentioned earlier.
+
+From now on, assume our query will be for **`www.powerdns.com.`**. SyncRes::getBestNSNamesFromCache will first check if there are NS records in cache for `www.powerdns.com.`, but there won't be. It then checks `powerdns.com. NS`, and while these records do exist on the internet, the recursor doesn't know about them yet. So, we go on to check the cache for `com. NS`, for which the same holds. Finally we end up checking for `. NS`, and these we do know about: they are the root servers and were loaded into PowerDNS on startup.
+
+So, SyncRes::getBestNSNamesFromCache fills out a set with the **names** of nameservers it knows about for the **`.`** zone.
+
+This set, together with the original query **`www.powerdns.com`** gets passed to SyncRes::doResolveAt. This function can't yet go to work immediately though, it only knows the names of nameservers it can try. This is like asking for directions and instead of hearing **take the third right** you are told **go to 123 Fifth Avenue, and take a right** - the answer doesn't help you further unless you know where 123 Fifth Avenue is.
+
+SyncRes::doResolveAt first shuffles the nameservers both randomly and on performance order. If it knows a nameserver was fast in the past, it will get queried first. More about this later.
+
+Ok, here is the part where things get a bit scary. How does SyncRes::doResolveAt find the IP address of a nameserver? Well, by calling SyncRes::getAs (**get A records**), which in turn calls.. SyncRes::doResolve. Hang on! That's where we came from! Massive potential for loops here. Well, it turns out that for any domain which can be resolved, this loop terminates. We do pass the `beenthere` set again, which makes sure we don't keep on asking the same questions to the same nameservers.
+
+Ok, SyncRes::getAs will give us the IP addresses of the chosen root-server, because these IP addresses were loaded on startup. We then ask these IP addresses (nameservers can have several) for its best answer for **`www.powerdns.com.`**. This is done using the LWRes class and specifically LWRes::asyncresolve, which gets passed domain name, type and IP address. This function interacts with MTasker and MPlexer above in ways which needn't concern us now. When it returns, the LWRes object contains the best answers the queried server had for our domain, which in this case means it tells us about the nameservers of `com.`, and their IP addresses.
+
+All the relevant answers it gives are stored in the cache (or actually, merged), after which SyncRes::doResolveAt (which we are still in) evaluates what to do now.
+
+There are 6 options:
+
+1. The final answer is in, we are done, return to SyncRes::doResolve and SyncRes::beginResolve
+2. The nameserver we queried tells us the domain we asked for authoritatively does not exist. In case of the root-servers, this happens when we query for *`www.powerdns.kom.`* for example, there is no *`kom.`*. Return to SyncRes::beginResolve, we are done.
+3. A lesser form - it tells us it is authoritative for the query we asked about, but there is no record matching our type. This happens when querying for the IPv6 address of a host which only has an IPv4 address. Return to SyncRes::beginResolve, we are done.
+4. The nameserver passed us a CNAME to another domain, and we need to reroute. Go to SyncRes::doResolve for the new domain.
+5. The nameserver did not know about the domain, but does know who does, a *referral*. Stay within doResolveAt and loop to these new nameservers.
+6. The nameserver replied saying *no idea*. This is called a *lame delegation*. Stay within SyncRes::doResolveAt and try the other nameservers we have for this domain.
+
+When not redirected using a CNAME, this function will loop until it has exhausted all nameservers and all their IP addresses. DNS is surprisingly resilient that there is often only a single non-broken nameserver left to answer queries, and we need to be prepared for that.
+
+This is the whole DNS algorithm in PowerDNS, all in less than 700 lines of code. It contains a lot of tricky bits though, related to the cache.
+
+# Some of the things we glossed over
+Whenever a packet is sent to a remote nameserver, the response time is stored in the SyncRes::s\_nsSpeeds map, using an exponentially weighted moving average. This EWMA averages out different response times, and also makes them decrease over time. This means that a nameserver that hasn't been queried recently gradually becomes **faster** in the eyes of PowerDNS, giving it a chance again.
+
+A timeout is accounted as a 1s response time, which should take that server out of the running for a while.
+
+Furthermore, queries are throttled. This means that each query to a nameserver that has failed is accounted in the `s_throttle` object. Before performing a new query, the query and the nameserver are looked up via shouldThrottle. If so, the query is assumed to have failed without even being performed. This saves a lot of network traffic and makes PowerDNS quick to respond to lame servers.
+
+It also offers a modicum of protection against birthday attack powered spoofing attempts, as PowerDNS will not inundate a broken server with queries.
+
+The negative query cache we mentioned earlier caches the cases 2 and 3 in the enumeration above. This data needs to be stored separately, as it represents **non-data**. Each negcache query entry is the name of the SOA record that was presented with the evidence of non-existence. This SOA record is then retrieved from the regular cache, but with the TTL that originally came with the NXDOMAIN (case 2) or NXRRSET (case 3).
+
+# The Recursor Cache
+As mentioned before, the cache stores partial packets. It also stores not the **Time To Live** of records, but in fact the **Time To Die**. If the cache contains data, but it is expired, that data should not be deemed present. This bit of PowerDNS has proven tricky, leading to deadlocks in the past.
+
+There are some other very tricky things to deal with. For example, through a process called **more details**, a domain might have more nameservers than listed in its parent zone. So, there might only be two nameservers for `powerdns.com.` in the **`com.`** zone, but the **`powerdns.com`** zone might list more.
+
+This means that the cache should not, when talking to the **`com.`** servers later on, overwrite these four nameservers with only the two copies the **`com.`** servers pass us.
+
+However, in other cases (like for example for SOA and CNAME records), new data should overwrite old data.
+
+Note that PowerDNS deviates from RFC 2181 (section 5.4.1) in this respect.
+
+# Some small things
+The server-side part of PowerDNS (`pdns_recursor.cc`), which listens to queries by end-users, is fully IPv6 capable using the ComboAddress class. This class is in fact a union of a `struct sockaddr_in` and a `struct sockaddr_in6`. As long as the `sin_family` (or `sin6_family`) and `sin_port` members are in the same place, this works just fine, allowing us to pass a ComboAddress*, cast to a `sockaddr*` to the socket functions. For convenience, the ComboAddress also offers a length() method which can be used to indicate the length - either sizeof(sockaddr\_in) or sizeof(sockaddr\_in6).
+
+Access to the recursor is governed through the NetmaskGroup class, which internally contains Netmask, which in turn contain a ComboAddress.
--- /dev/null
+# PowerDNS Recursor performance
+To get the best out of the PowerDNS recursor, which is important if you are doing thousands of queries per second, please consider the following.
+
+- Limit the size of the caches to a sensible value. Cache hit rate does not improve meaningfully beyond 4 million **max-cache-entries** per thread, reducing the memory footprint reduces CPU cache misses. See below for more information about the various caches.
+- Compile using g++ 4.1 or later. This compiler really does a good job on PowerDNS, much better than 3.4 or 4.0.
+- On AMD/Intel hardware, wherever possible, run a 64-bit binary. This delivers a nearly twofold performance increase. On UltraSPARC, there is no need to run with 64 bits.
+- Consider performing a 'profiled build' as described in the README. This is good for a 20% performance boost in some cases.
+- When running with >3000 queries per second, and running Linux versions prior to 2.6.17 on some motherboards, your computer may spend an inordinate amount of time working around an ACPI bug for each call to gettimeofday. This is solved by rebooting with 'clock=tsc' or upgrading to a 2.6.17 kernel.
+
+ The above is relevant if dmesg shows **Using pmtmr for high-res timesource**
+
+- A busy server may need hundreds of file descriptors on startup, and deals with spikes better if it has that many available later on. Linux by default restricts processes to 1024 file descriptors, which should suffice most of the time, but Solaris has a default limit of 256. This can be raised using the ulimit command. FreeBSD has a default limit that is high enough for even very heavy duty use.
+- When deploying (large scale) IPv6, please be aware some Linux distributions leave IPv6 routing cache tables at very small default values. Please check and if necessary raise 'sysctl net.ipv6.route.max\_size'.
+- For older versions <3.2: If you need it, try **--fork**, this will fork the daemon into two halves, allowing it to benefit from a second CPU. This feature almost doubles performance, but is a bit of a hack.
+- for 3.2 and higher, set 'threads' to your number of CPU cores (but values above 8 rarely improve performance).
+- For best PowerDNS Recursor performance, use a recent version of your operating system, since this generally offers the best event multiplexer implementation available (kqueue, epoll, ports or /dev/poll).
+- A Recursor under high load puts a severe stress on any stateful (connection tracking) firewall, so much so that the firewall may fail.
+
+ Specifically, many Linux distributions run with a connection tracking firewall configured. For high load operation (thousands of queries/second), It is advised to either turn off iptables completely, or use the 'NOTRACK' feature to make sure DNS traffic bypasses the connection tracking.
+
+ Sample Linux command lines would be:
+
+```
+## IPv4
+iptables -t raw -I OUTPUT -p udp --dport 53 -j CT --notrack
+iptables -t raw -I OUTPUT -p udp --sport 53 -j CT --notrack
+iptables -t raw -I PREROUTING -p udp --dport 53 -j CT --notrack
+iptables -t raw -I PREROUTING -p udp --sport 53 -j CT --notrack
+iptables -I INPUT -p udp --dport 53 -j ACCEPT
+iptables -I INPUT -p udp --sport 53 -j ACCEPT
+iptables -I OUTPUT -p udp --dport 53 -j ACCEPT
+iptables -I OUTPUT -p udp --sport 53 -j ACCEPT
+
+## IPv6
+ip6tables -t raw -I OUTPUT -p udp --dport 53 -j CT --notrack
+ip6tables -t raw -I OUTPUT -p udp --sport 53 -j CT --notrack
+ip6tables -t raw -I PREROUTING -p udp --sport 53 -j CT --notrack
+ip6tables -t raw -I PREROUTING -p udp --dport 53 -j CT --notrack
+ip6tables -I INPUT -p udp --dport 53 -j ACCEPT
+ip6tables -I INPUT -p udp --sport 53 -j ACCEPT
+ip6tables -I OUTPUT -p udp --dport 53 -j ACCEPT
+ip6tables -I OUTPUT -p udp --sport 53 -j ACCEPT
+```
+
+
+When using FirewallD (Centos 7+ / RedHat 7+ / Fedora 21+) connection tracking can be disabled via direct rules.
+The settings can be made permanent by using the --permanent flag.
+```
+## IPv4
+firewall-cmd --direct --add-rule ipv4 raw OUTPUT 0 -p udp --dport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv4 raw OUTPUT 0 -p udp --sport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv4 raw PREROUTING 0 -p udp --dport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv4 raw PREROUTING 0 -p udp --sport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p udp --dport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv4 filter INPUT 0 -p udp --sport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -p udp --dport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv4 filter OUTPUT 0 -p udp --sport 53 -j ACCEPT
+
+## IPv6
+firewall-cmd --direct --add-rule ipv6 raw OUTPUT 0 -p udp --dport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv6 raw OUTPUT 0 -p udp --sport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv6 raw PREROUTING 0 -p udp --dport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv6 raw PREROUTING 0 -p udp --sport 53 -j CT --notrack
+firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -p udp --dport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv6 filter INPUT 0 -p udp --sport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv6 filter OUTPUT 0 -p udp --dport 53 -j ACCEPT
+firewall-cmd --direct --add-rule ipv6 filter OUTPUT 0 -p udp --sport 53 -j ACCEPT
+```
+
+
+Following the instructions above, you should be able to attain very high query rates.
+
+## Recursor Caches
+The PowerDNS Recursor contains a number of caches, or information stores:
+
+### Nameserver speeds cache
+The "NSSpeeds" cache contains the average latency to all remote authoritative servers.
+
+### Negative cache
+The "Negcache" contains all domains known not to exist, or record types not to exist for a domain.
+
+### Recursor Cache
+The Recursor Cache contains all DNS knowledge gathered over time.
+
+### Packet Cache
+The Packet Cache contains previous answers sent to clients. If a question comes in that matches a previous answer, this is sent back directly.
+
+The Packet Cache is consulted first, immediately after receiving a packet. This means that a high hitrate for the Packet Cache automatically lowers the cache hitrate of subsequent caches. This explains why releases 3.2 and beyond see dramatically lower DNS cache hitrates, since this is the first version with a Packet Cache.
--- /dev/null
+# Controlling and querying the recursor
+To control and query the PowerDNS recursor, the tool `rec_control` is provided. This program talks to the recursor over the 'controlsocket', often stored in `/var/run`.
+
+As a sample command, try:
+
+```
+# rec_control ping
+pong
+```
+
+When not running as root, `--socket-dir=/tmp` might be appropriate.
+
+## `rec_control` commands
+dump-cache filename
+Dumps the entire cache to the filename mentioned. This file should not exist already, PowerDNS will refuse to overwrite it. While dumping, the recursor will not answer questions.
+
+### `current-queries`
+Show currently outstanding queries.
+
+### `dump-cache <filename>`
+Dump cache contents to the named file `filename`. Note that the file MUST NOT exist beforehand. \\
+Typical PowerDNS Recursors run multiple threads, therefore you'll see duplicate, different entries for the same domains. The negative cache is also dumped to the same file. The per-thread positive and negative cache dumps are separated with an appropiate comment.
+
+### `dump-edns[status] <filename>`
+Dump EDNS Status for remotes to the named file `filename`. Note that the file MUST NOT exist beforehand.
+
+### `dump-nsspeeds <filename>`
+Dump remote nameserver speed statistics to the named file `filename`. Note that the file MUST NOT exist beforehand. Again, statistics are kept per thread, and the dumps end up in the same file.
+
+### `get statistic`
+Retrieve a statistic. For items that can be queried, see below.
+
+### `get-all`
+Retrieve all statistics in one go. Available since version 3.2.
+
+### `get-parameter parameter1 [parameter2 ..]`
+Retrieve a configuration parameter. All parameters from the configuration and command line can be queried. Available since version 3.2.
+
+### `help`
+List all commands understood by your running `pdns_recursor` process.
+
+### `ping`
+Check if server is alive.
+
+### `quit`
+Request shutdown of the recursor.
+
+### `quit-nicely`
+Request a nice shutdown of the recursor.
+
+### `reload-acls`
+Reload access control lists.
+
+### `reload-lua-script [filename]`
+(Re-)Load Lua script. Note that loading a script fully replaces the one currently
+loaded.
+
+### `reload-lua-config [filename]`
+(Re-)Load the Lua configuration file.
+Note that *FILENAME* will be fully executed, any settings changed at runtime that are not modified in this file, will still be active.
+Also note that the process will block (not answering queries) when reloading, this might take a long time when an RPZ has to be transferred.
+
+### `reload-zones`
+Reload data about all authoritative and forward zones. The configuration file is also scanned to see if the **auth-domain**, **forward-domain** and **export-etc-hosts** statements have changed, and if so, these changes are incorporated.
+
+### `set-minimum-ttl value`
+Available since 3.6, this setting artificially raises all TTLs to be at least this long. While this is a gross hack, and violates RFCs, under conditions of DoS, it may enable you to continue serving your customers. Corresponds to the configuration file setting 'minimum-ttl-override'.
+
+### `set-carbon-server server ourname`
+Set a Carbon server for telemetry purposes. The parameter `server` corresponds to the configuration setting **carbon-server**, and `ourname` corresponds to **carbon-ourname**.
+
+### `top-remotes`
+Shows the top-20 most active remote hosts. Statistics are over the last **stats-ringbuffer-entries** queries.
+
+### `trace-regex regex`
+Available since 3.5.
+
+Queries matching this regular expression will generate voluminous tracing output. Be aware that matches from the packet cache will still not generate tracing. To unset the regex, pass `trace-regex` without a new regex.
+
+The regular expression is matched against domain queries terminated with a `.`. So, for example the regex `powerdns\.com$` will not match a query for `www.powerdns.com`, since the attempted match will be with `www.powerdns.com.`.
+
+In addition, since this is a regular expression, to exclusively match queries for `www.powerdns.com`, one should escape the dots: `^www\.powerdns\.com\.$`.
+
+Multiple matches can be chained with the | operator. For example, to match all queries for Dutch (.nl) and German (.de) domain names, use: `\.nl\.$|\.de\.$`.
+
+### `unload-lua-script`
+Unload Lua script, if one is loaded.
+
+### `version`
+Available after 3.6.1, report currently running version.
+
+### `wipe-cache domain1. [domain2. ..]`
+Wipe entries from the cache. This is useful if, for example, an important server has a new IP address, but the TTL has not yet expired. Multiple domain names can be passed. For versions before 3.1, you must terminate a domain with a `.`! So to wipe powerdns.org, issue `rec_control wipe-cache powerdns.org.`. For later versions, the dot is optional.
+
+Note that deletion is exact, wiping `com.` will leave `www.powerdns.com.` untouched!
+
+**Warning**: As of 3.1.7, this command also wipes the negative query cache for the specified domain.
+**Warning**: Don't just wipe "www.somedomain.com", its NS records or CNAME target may still be undesired, so wipe "somedomain.com" as well.
+
+The command `get` can query a large number of statistics, which are detailed in [Performance Monitoring](stats.md).
+
+More details on what "throttled" queries and the like are can be found below in [Security Settings](security.md).
--- /dev/null
+# Scripting The Recursor
+In the PowerDNS recursor, it is possible to modify resolving behaviour using
+simple scripts written in the [Lua](http://www.lua.org) programming language.
+This page documents the Recursor 4.0.0 and beyond version of the scripting API.
+
+**Note**: This describes the Lua scripts as supported by 4.x. They are very
+different than the ones from 3.x, but tend to be faster and more correct.
+
+These scripts can be used to quickly override dangerous domains, fix things
+that are wrong, for load balancing or for legal or commercial purposes. The
+scripts can also protect you or your users from malicious traffic.
+
+Lua is extremely fast and lightweight, easily supporting hundreds of thousands
+of queries per second. The Lua language is explained very well in the excellent
+book [Programming in Lua](http://www.amazon.com/exec/obidos/ASIN/859037985X/lua-pilindex-20).
+If you already have programming experience,
+[Learn Lua in 15 Minutes](http://tylerneylon.com/a/learn-lua/) is a great primer.
+
+For extra performance, a Just In Time compiled version of Lua called
+[LuaJIT](http://luajit.org/) is supported.
+
+Queries can be intercepted in many places:
+
+* before any packet parsing begins (`ipfilter`)
+* before any filtering policy have been applied (`prerpz`)
+* before the resolving logic starts to work (`preresolve`)
+* after the resolving process failed to find a correct answer for a domain (`nodata`, `nxdomain`)
+* after the whole process is done and an answer is ready for the client (`postresolve`)
+* before an outgoing query is made to an authoritative server (`preoutquery`)
+
+## Configuring Lua scripts
+In order to load scripts, the PowerDNS Recursor must have Lua support built
+in. The packages distributed from the PowerDNS website have this language
+enabled, other distributions may differ. By default, the Recursor's configure
+script will attempt to detect if Lua is available.
+
+**note**: Only one script can be loaded at the same time. If you load a different
+script, the current one will be replaced (safely)!
+
+If Lua support is available, a script can be configured either via the
+configuration file, or at runtime via the `rec_control` tool. Scripts can
+be reloaded or unloaded at runtime with no interruption in operations. If a
+new script contains syntax errors, the old script remains in force.
+
+On the command line, or in the configuration file, the setting
+[`lua-dns-script`](settings.md#lua-dns-script) can be used to supply a full path
+to the Lua script.
+
+At runtime, `rec_control reload-lua-script` can be used to either reload the
+script from its current location, or, when passed a new file name, load one
+from a new location. A failure to parse the new script will leave the old
+script in working order.
+
+**Note**: It is also possible to precompile scripts using `luac`, and have
+PowerDNS load the result. This means that switching scripts is faster, and
+also that you'll be informed about syntax errors at compile time.
+
+Finally, `rec_control unload-lua-script` can be used to remove the currently
+installed script, and revert to unmodified behaviour.
+
+# Writing Lua PowerDNS Recursor scripts
+To get a quick start, we have supplied a sample script that showcases all functionality described below. Please
+find it [here](https://github.com/PowerDNS/pdns/blob/master/pdns/powerdns-example-script.lua).
+
+Addresses and DNS Names are not passed as strings but as native objects. This
+allows for easy checking against [netmasks](#netmask-groups) and [domain sets]().
+It also means that to print such names, the `:toString` method must be used
+(or even `:toStringWithPort` for addresses).
+
+Comparing IP addresses and DNSNames is not done with '==' but with the `:equal` method.
+
+Once a script is loaded, PowerDNS looks for several functions, as detailed below.
+All of these functions are optional.
+
+## The DNSQuestion (`dq`) object
+Apart from the `ipfilter`-function, all functions work on a `dq` (DNSQuestion)
+object. This object contains details about the current state of the question.
+This state can be modified from the various hooks. If a function returns 'true',
+it will indicate that it handled a query. If it returns false, the Recursor will
+continue processing unchanged (with one minor exception).
+
+The DNSQuestion object contains at least the following fields:
+
+* qname - DNS native version of the name this query is for
+* qtype - type this query is for, can be compared against pdns.A, pdns.AAAA etc
+* rcode - current DNS Result Code, which can be overridden, including to several magical values
+* isTcp - whether the query have been received over TCP or UDP
+* remoteaddr - address of the requestor
+* localaddr - address this query was received on
+* variable - a boolean which, if set, indicates the recursor should not packet cache this answer. Honored even when returning 'false'! Important when providing answers that vary over time or based on sender details.
+* followupFunction - a string that signals the nameserver to take one of the following additional actions:
+ * followCNAMERecords: When adding a CNAME to the answer, this tells the recursor to follow that CNAME. See [CNAME chain resolution](#cname-chain-resolution)
+ * getFakeAAAARecords: Get a fake AAAA record, see [DNS64](#dns64)
+ * getFakePTRRecords: Get a fake PTR record, see [DNS64](#dns64)
+ * udpQueryResponse: Do a UDP query and call a handler, see [`udpQueryResponse`](#udpqueryresponse)
+* appliedPolicy - The decision that was made by the policy engine, see [Modifying policy decisions](#modifying-policy-decisions). It has the following fields:
+ * policyName: The name of the policy (used in e.g. protobuf logging)
+ * policyAction: The action taken by the engine
+ * policyCustom: The CNAME content for the `pdns.policyactions.Custom` response, a string
+ * policyTTL: The TTL in seconds for the `pdns.policyactions.Custom` response
+* wantsRPZ - A boolean that indicates the use of the Policy Engine, can be set to `false` in `preresolve` to disable RPZ for this query
+
+It also supports the following methods:
+
+* `addAnswer(type, content, [ttl, name])`: add an answer to the record of `type` with `content`. Optionally supply TTL and the name of
+ the answer too, which defaults to the name of the question
+* `addPolicyTag(tag)`: add a policy tag.
+* `discardPolicy(policyname)`: skip the filtering policy (for example RPZ) named `policyname` for this query. This is mostly useful in the `prerpz` hook.
+* `getPolicyTags()`: get the current policy tags as a table of strings.
+* `getRecords()`: get a table of DNS Records in this DNS Question (or answer by now)
+* `setPolicyTags(tags)`: update the policy tags, taking a table of strings.
+* `setRecords(records)`: after your edits, update the answers of this question
+* `getEDNSOption(num)`: get the EDNS Option with number `num`
+* `getEDNSOptions()`: get a map of all EDNS Options
+* `getEDNSSubnet()`: returns the netmask specified in the EDNSSubnet option, or empty if there was none
+
+## `function ipfilter ( remoteip, localip, dh )`
+This hook gets queried immediately after consulting the packet cache, but before
+parsing the DNS packet. If this hook returns something else than false, the packet is dropped.
+However, because this check is after the packet cache, the IP address might still receive answers
+that require no packet parsing.
+
+With this hook, undesired traffic can be dropped rapidly before using precious CPU cycles
+for parsing.
+
+`remoteip` is the IP(v6) address of the requestor, `localip` is the address on which the query arrived.
+`dh` is the DNS Header of the query, and it offers the following methods:
+
+* `getRD()`, `getAA()`, `getAD()`, `getCD()`, `getRD()`, `getRD()`, `getTC()`: query these bits from the DNS Header
+* `getRCODE()`: get the RCODE of the query
+* `getOPCODE()`: get the OPCODE of the query
+* `getID()`: get the ID of the query
+
+As an example, to filter all queries coming from 1.2.3.0/24, or with the AD bit set:
+
+```
+badips = newNMG()
+badips:addMask("1.2.3.0/24")
+
+function ipfilter(rem, loc, dh)
+ return badips:match(rem) or dh:getAD()
+end
+```
+
+This hook does not get the full DNSQuestion object, since filling out the fields
+would require packet parsing, which is what we are trying to prevent with `ipfilter`.
+
+### `function gettag(remote, ednssubnet, local, qname, qtype)`
+The `gettag` function is invoked when the Recursor attempts to discover in which
+packetcache an answer is available.
+This function must return an integer, which is the tag number of the packetcache.
+In addition to this integer, this function can return a table of policy tags.
+
+The resulting tag number can be accessed via `dq.tag` in the `preresolve` hook,
+and the policy tags via `dq:getPolicyTags()` in every hook.
+
+The tagged packetcache can e.g. be used to answer queries from cache that have
+e.g. been filtered for certain IPs (this logic should be implemented in the
+`gettag` function). This ensure that queries are answered quickly compared to
+setting dq.variable to `true`. In the latter case, repeated queries will pass
+through the entire Lua script.
+
+### `function prerpz(dq)`
+
+This hook is called before any filtering policy have been applied, making it
+possible to completely disable filtering by setting `wantsRPZ` to false.
+Using the `discardPolicy()` function, it is also possible to selectively disable
+one or more filtering policy, for example RPZ zones, based on the content of the
+`dq` object.
+
+As an example, to disable the `malware` policy for `example.com` queries:
+
+```
+function prerpz(dq)
+ -- disable the RPZ policy named 'malware' for example.com
+ if dq.qname:equal('example.com') then
+ dq:discardPolicy('malware')
+ end
+end
+```
+
+### `function preresolve(dq)`
+is called before any DNS resolution is attempted, and if this function
+indicates it, it can supply a direct answer to the DNS query, overriding the
+internet. This is useful to combat botnets, or to disable domains
+unacceptable to an organization for whatever reason.
+
+The rcode can be set to pdns.DROP to drop the query. Other statuses are normal DNS
+return codes, like no error, NXDOMDAIN etc.
+
+### `function postresolve(dq)`
+is called right before returning a response to a client (and, unless
+`variable` is set, to the packet cache too). It allows inspection
+and modification of almost any detail in the return packet.
+
+### `function nxdomain(dq)`
+is called after the DNS resolution process has run its course, but ended in
+an 'NXDOMAIN' situation, indicating that the domain or the specific record
+does not exist. Works entirely like postresolve, but saves a trip through Lua for
+answers which are not NXDOMAIN.
+
+### `function nodata(dq)`
+is just like `nxdomain`, except it gets called when a domain exists, but the
+requested type does not. This is where one would implement DNS64.
+
+### `function preoutquery(dq)`
+This hook is not called in response to a client packet, but fires when the Recursor
+wants to talk to an authoritative server. When this hook sets the special result code -3,
+the whole DNS client query causing this outquery gets dropped.
+
+However, this function can also return records like the preresolve query above.
+
+## Semantics
+The functions must return `true` if they have taken over the query and wish that
+the nameserver should not proceed with its regular query-processing. When a
+function returns `false`, the nameserver will process the query normally until
+a new function is called.
+
+If a function has taken over a request, it should set an rcode (usually 0),
+and specify a table with records to be put in the answer section of a
+packet. An interesting rcode is NXDOMAIN (3, or `pdns.NXDOMAIN`), which
+specifies the non-existence of a domain.
+
+The `ipfilter` and `preoutquery` hooks are different, in that `ipfilter` can
+only return a true of false value, and that `preoutquery` can also set rcode -3
+to signify that the whole query should be terminated.
+
+A minimal sample script:
+
+```
+function nxdomain(dq)
+ print("Intercepting NXDOMAIN for: ",dq.qname:toString())
+ if dq.qtype == pdns.A
+ then
+ dq.rcode=0 -- make it a normal answer
+ dq:addAnswer(pdns.A, "192.168.1.1")
+ return true
+ end
+ return false
+end
+```
+
+**Warning**: Please do NOT use the above sample script in production!
+Responsible NXDomain redirection requires more attention to detail.
+
+Useful 'rcodes' include 0 for "no error", `pdns.NXDOMAIN` for
+"NXDOMAIN", `pdns.DROP` to drop the question from further processing (since
+3.6, and such a drop is accounted in the 'policy-drops' metric).
+
+## Helpful functions
+
+### Netmask Groups
+IP addresses are passed to Lua in native format. They can be matched against netmasks objects like this:
+```
+nmg = newNMG()
+nmg:addMask("127.0.0.0/8")
+nmg:addMasks({"213.244.168.0/24", "130.161.0.0/16"})
+nmg:addMasks(dofile("bad.ips")) -- contains return {"ip1","ip2"..}
+
+if nmg:match(dq.remoteaddr) then
+ print("Intercepting query from ", dq.remoteaddr)
+end
+```
+
+### IP Addresses
+We move IP addresses around in native format, called ComboAddress within PowerDNS.
+ComboAddresses can be IPv4 or IPv6, and unless you want to know, you don't need
+to. You can make a ComboAddress with: `newCA("::1")`, and you can compare
+it against a NetmaskGroup as described above.
+
+To compare the address (so not the port) of two ComboAddresses, use `:equal`.
+
+To convert an address to human-friendly representation, use `:toString()` or
+`:toStringWithPort()`. To get only the port number, use `:getPort()`.
+
+Other functions that can be called on a ComboAddress are:
+
+ * `isIPv4` - true if the address is an IPv4 address
+ * `isIPv6` - true if the address is an IPv6 address
+ * `getRaw` - returns the bytestring representing the address
+ * `isMappedIPv4` - true if the address is an IPv4 address mapped into an IPv6 one
+ * `mapToIPv4` - if the address is an IPv4 mapped into an IPv6 one, return the corresponding IPv4
+ * `truncate(bits)` - truncate to the supplied number of bits
+
+### Netmask
+IP addresses can be matched against a Netmask object, which can be created with
+`newNetmask("192.0.2.1/24")` and supports the following methods:
+
+ * `empty` - true if the netmask doesn't contain a valid address
+ * `getBits` - the number of bits in the address
+ * `getNetwork` - return a ComboAddress representing the network (no mask applied)
+ * `getMaskedNetwork` - return a ComboAddress representing the network (truncating according to the mask)
+ * `isIpv4` - true if the address is an IPv4 address
+ * `isIpv6` - true if the address is an IPv6 address
+ * `match(str)` - true if the address passed in str matches
+ * `toString` - human-friendly representation
+
+### DNSName
+DNSNames are passed to various functions, and they sport the following methods:
+
+* `:equal`: use this to compare two DNSNames in DNS native fashion. So 'PoWeRdNs.COM' matches 'powerdns.com'
+* `:isPartOf`: returns true if a is a part of b. So: `newDN("www.powerdns.com"):isPartOf(newDN("CoM."))` returns true
+* `:toString` and `:toStringNoDot`: return a string representation of the name, with or without trailing dot.
+* `:chopOff`: removes the leftmost label from the name, returns true if this succeeded.
+* `:countLabels`: returns the number of labels
+* `:wirelength`: returns the length on the wire
+
+You can compare DNSNames using `:equal` or the `==` operator.
+
+To make your own DNSName, use `newDN("domain.name")`. To copy an existing DNSName (please remember to do this before using `chopOff`), use `newDN(mydn)`.
+
+### DNS Suffix Match groups
+The `newDS` function creates a "Suffix Match group" that allows fast checking if
+a DNSName is part of a group. Add domains to this group with the `:add(domain)`
+function of the object: `myDS:add("example.net")`, or with a list:
+`myDS:add({"example.net", "example.com"}).
+
+To check e.g. the dq.qname against this list, use `:check(dq.qname)`. This will
+be `true` if dq.qname is part of any of the Suffix Match group domains.
+
+This could e.g. be used to answer questions for known malware domains.
+
+To see the set of suffixes matched by a Suffix Match Group, use `:toString()`.
+
+### Metrics
+You can custom metrics which will be shown in the output of 'rec_control get-all'
+and sent to the metrics server over the Carbon protocol, and also appear in the
+JSON HTTP API.
+
+Create a custom metric with: `myMetric= getMetric("name")`. This metric sports
+the following metrics:
+
+* `:inc()`: increase metric by 1
+* `:incBy(amount)`: increase metric by amount
+* `:set(to)`: set metric to value to
+* `:get()`: get value of metric
+
+Metrics are shared across all of PowerDNS and are fully atomic and high
+performance. The myMetric object is effectively a pointer to an atomic value.
+
+Note that metrics live in the same namespace as 'system' metrics. So if you
+generate one that overlaps with a PowerDNS stock metric, you will get double
+output and weird results.
+
+### Logging
+To log messages with the main PowerDNS Recursor process, use `pdnslog(message)`.
+pdnslog can also write out to a syslog loglevel if specified.
+Use `pdnslog(message, pdns.loglevels.LEVEL)` with the correct pdns.loglevels
+entry. Entries are listed in the following table:
+
+* All - `pdns.loglevels.All`
+* Alert - `pdns.loglevels.Alert`
+* Critical - `pdns.loglevels.Critical`
+* Error - `pdns.loglevels.Error`
+* Warning - `pdns.loglevels.Warning`
+* Notice - `pdns.loglevels.Notice`
+* Info - `pdns.loglevels.Info`
+* Debug - `pdns.loglevels.Debug`
+* None - `pdns.loglevels.None`
+
+`pdnslog(message)` will write out to Info by default.
+
+`getregisteredname('www.powerdns.com')` returns `powerdns.com.`, based on Mozilla's
+Public Suffix List. In general it will tell you the 'registered domain' for a given
+name.
+
+## DNS64
+The `getFakeAAAARecords` and `getFakePTRRecords` followupFunctions can be used
+to implement DNS64. See [DNS64 support in the PowerDNS Recursor](dns64.md) for
+more information.
+
+To get fake AAAA records for DNS64 usage, set dq.followupFunction to `getFakeAAAARecords`,
+dq.followupPrefix to e.g. "64:ff9b::" and dq.followupName to the name you want to
+synthesize an IPv6 address for.
+
+For fake reverse (PTR) records, set dq.followupFunction to `getFakePTRRecords`
+and set dq.followupName to the name to look up and dq.followupPrefix to the
+same prefix as used with `getFakeAAAARecords`.
+
+## CNAME chain resolution
+It may be useful to return a CNAME record for Lua, and then have the
+PowerDNS Recursor continue resolving that CNAME. This can be achieved by
+setting dq.followupFunction to `followCNAMERecords` and dq.followupDomain to
+"www.powerdns.com". PowerDNS will do the rest.
+
+## `udpQueryResponse`
+The `udpQueryResponse` dq.followupFunction allows you to query a simple key-value
+store over UDP asynchronously.
+
+Several dq variables can be set:
+
+* `udpQueryDest`: destination IP address to send the UDP packet to
+* `udpQuery`: The content of the UDP payload
+* `udpCallback`: The name of the callback function that is called when an answer is received
+
+The callback function must accept the `dq` object and can find the response to
+the UDP query in `dq.udpAnswer`.
+
+In this callback function, `dq.followupFunction` can be set again to any of the
+available functions for further processing.
+
+This example script queries a simple key/value store over UDP to decide on whether
+or not to filter a query:
+
+```
+!!include=../pdns/kv-example-script.lua
+```
+
+## Example Script
+
+```
+!!include=../pdns/powerdns-example-script.lua
+```
+
+### Dropping all traffic from botnet-infected users
+Frequently, DoS attacks are performed where specific IP addresses are attacked,
+often by queries coming in from open resolvers. These queries then lead to a lot of
+queries to 'authoritative servers' which actually often aren't nameservers at all, but
+just targets of attack.
+
+The following script will add a requestor's IP address to a blocking set if they've
+sent a query that caused PowerDNS to attempt to talk to a certain subnet.
+
+This specific script is, as of January 2015, useful to prevent traffic to ezdns.it related
+traffic from creating CPU load. This script requires PowerDNS Recursor 4.x or later.
+
+```
+lethalgroup=newNMG()
+lethalgroup:addMask("192.121.121.0/24") -- touch these nameservers and you die
+
+function preoutquery(dq)
+ print("pdns wants to ask "..dq.remoteaddr:toString().." about "..dq.qname:toString().." "..dq.qtype.." on behalf of requestor "..dq.localaddr:toString())
+ if(lethalgroup:match(dq.remoteaddr))
+ then
+ print("We matched the group "..lethalgroup:tostring().."!", "killing query dead & adding requestor "..dq.localaddr:toString().." to block list")
+ dq.rcode = -3 -- "kill"
+ return true
+ end
+ return false
+end
+```
+
+## Modifying Policy Decisions
+The PowerDNS Recursor has a [policy engine based on Response Policy Zones (RPZ)](settings.md#response-policy-zone-rpz).
+Starting with version 4.0.1 of the recursor, it is possible to alter this decision inside the Lua hooks.
+If the decision is modified in a Lua hook, `false` should be returned, as the query is not actually handled by Lua so the decision is picked up by the Recursor.
+The result of the policy decision is checked after `preresolve` and `postresolve`.
+
+For example, if a decision is set to `pdns.policykinds.NODATA` by the policy engine and is unchanged in `preresolve`, the query is replied to with a NODATA response immediately after `preresolve`.
+
+### Example script
+```
+-- Dont ever block my own domain and IPs
+myDomain = newDN("example.com")
+
+myNetblock = newNMG()
+myNetblock:addMasks("192.0.2.0/24")
+
+function preresolve(dq)
+ if dq.qname:isPartOf(myDomain) and dq.appliedPolicy.policyKind != pdns.policykinds.NoAction then
+ pdnslog("Not blocking our own domain!")
+ dq.appliedPolicy.policyKind = pdns.policykinds.NoAction
+ end
+end
+
+function postresolve(dq)
+ if dq.appliedPolicy.policyKind != pdns.policykinds.NoAction then
+ local records = dq:getRecords()
+ for k,v in pairs(records) do
+ if v.type == pdns.A then
+ local blockedIP = newCA(v:getContent())
+ if myNetblock:match(blockedIP) then
+ pdnslog("Not blocking our IP space")
+ dq.appliedPolicy.policyKind = pdns.policykinds.NoAction
+ end
+ end
+ end
+ end
+end
+```
+
+The decision is contained in the `dq` object under `dq.appliedPolicy` and features 4 fields:
+
+### `dq.appliedPolicy.policyName`
+A string with the name of the policy (set by `polName=` in the `rpzFile` and `rpzMaster` configuration items).
+It is advised to overwrite this when modifying the `policyKind`
+
+### `dq.appliedPolicy.policyKind`
+The kind of policy response, there are several policy kinds:
+
+ * `pdns.policykinds.Custom` will return a NoError, CNAME answer with the value specified in `dq.appliedPolicy.policyCustom`
+ * `pdns.policykinds.Drop` will simply cause the query to be dropped
+ * `pdns.policykinds.NoAction` will continue normal processing of the query
+ * `pdns.policykinds.NODATA` will return a NoError response with no value in the answer section
+ * `pdns.policykinds.NXDOMAIN` will return a response with a NXDomain rcode
+ * `pdns.policykinds.Truncate` will return a NoError, no answer, truncated response over UDP. Normal processing will continue over TCP
+
+### `dq.appliedPolicy.policyCustom` and `dq.appliedPolicy.policyTTL`
+These fields are only used when `dq.appliedPolicy.policyKind` is set to `pdns.policykinds.Custom`.
+`dq.appliedPolicy.policyCustom` contains the name for the CNAME target as a string.
+And `dq.appliedPolicy.policyTTL` is the TTL field (in seconds) for the CNAME response.
--- /dev/null
+# Security Measures in the Recursor
+
+## Anti-spoofing
+The PowerDNS recursor 3.0 uses a fresh UDP source port for each outgoing query, making spoofing around 64000 times harder. This raises the bar from 'easily doable given some time' to 'very hard'. Under some circumstances, 'some time' has been measured at 2 seconds. This technique was first used by `dnscache` by Dan J. Bernstein.
+
+In addition, PowerDNS detects when it is being sent too many unexpected answers, and mistrusts a proper answer if found within a clutch of unexpected ones.
+
+This behaviour can be tuned using the **spoof-nearmiss-max**.
+
+## Throttling
+PowerDNS implements a very simple but effective nameserver. Care has been taken not to overload remote servers in case of overly active clients.
+
+This is implemented using the 'throttle'. This accounts all recent traffic and prevents queries that have been sent out recently from going out again.
+
+There are three levels of throttling.
+
+- If a remote server indicates that it is lame for a zone, the exact question won't be repeated in the next 60 seconds.
+- After 4 ServFail responses in 60 seconds, the query gets throttled too.
+- 5 timeouts in 20 seconds also lead to query suppression.
--- /dev/null
+# All PowerDNS Recursor Settings
+Each setting can appear on the command line, prefixed by '--', or in the configuration file. The command line overrides the configuration file.
+
+**Note**: Settings marked as 'Boolean' can either be set to an empty value, which
+means on, or to 'no' or 'off' which means off. Anything else means on.
+
+So, as an example:
+
+ * 'serve-rfc1918' on its own means: do serve those zones.
+ * 'serve-rfc1918=off' or 'serve-rfc1918=no' means: do not serve those zones.
+ * Anything else means: do serve those zones.
+
+## `aaaa-additional-processing`
+* Boolean
+* Default: No
+* Available until: 3.6.0
+
+If turned on, the recursor will attempt to add AAAA IPv6 records to questions
+for MX records and NS records. Can be quite slow as absence of these records in
+earlier answers does not guarantee their non-existence. Can double the amount of
+queries needed.
+
+## `allow-from`
+* IP ranges, separated by commas
+* Default: 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16
+
+Netmasks (both IPv4 and IPv6) that are allowed to use the server. The default
+allows access only from RFC 1918 private IP addresses. Due to the aggressive
+nature of the internet these days, it is highly recommended to not open up the
+recursor for the entire internet. Questions from IP addresses not listed here
+are ignored and do not get an answer.
+
+## `allow-from-file`
+* Path
+
+Like [`allow-from`](#allow-from), except reading from file. Overrides the
+[`allow-from`](#allow-from) setting. To use this feature, supply one netmask per
+line, with optional comments preceded by a \#. Available since version 3.1.5.
+
+## `any-to-tcp`
+* Boolean
+* Default: no
+
+Answer questions for the ANY type on UDP with a truncated packet that refers the
+remote server to TCP. Useful for mitigating ANY reflection attacks.
+
+## `api-config-dir`
+* Path
+* Default: unset
+* Available since: 4.0
+
+Directory where the REST API stores its configuration and zones.
+
+## `api-key`
+* String
+* Default: unset
+* Available since: 4.0
+
+Static pre-shared authentication key for access to the REST API.
+
+## `api-readonly`
+* Boolean
+* Default: no
+* Available since: 4.0
+
+Disallow data modification through the REST API when set.
+
+## `api-logfile`
+* Path
+* Default: unset
+* Available since: 4.0
+
+Location of the server logfile (used by the REST API).
+
+## `auth-can-lower-ttl`
+* Boolean
+* Default: no
+* Available until: 3.5
+
+Authoritative zones can transmit a TTL value that is lower than that specified
+in the parent zone. This is called a 'delegation inconsistency'. To follow
+RFC 2181 paragraphs 5.2 and 5.4 to the letter, enable this feature. This will
+mean a slight deterioration of performance, and it will not solve any problems,
+but does make the recursor more standards compliant. Not recommended unless you
+have to tick an 'RFC 2181 compliant' box.
+
+## `auth-zones`
+* Comma separated list of 'zonename=filename' pairs
+* Available since: 3.1
+
+Zones read from these files (in BIND format) are served authoritatively. Example:
+`auth-zones=example.org=/var/zones/example.org, powerdns.com=/var/zones/powerdns.com`.
+
+## `carbon-interval`
+* Integer
+* Default: 30
+* Available since: 3.5.3
+
+If sending carbon updates, this is the interval between them in seconds. See
+["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `carbon-ourname`
+* String
+* Available since: 3.5.3
+
+If sending carbon updates, if set, this will override our hostname. Be
+careful not to include any dots in this setting, unless you know what you
+are doing. See ["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `carbon-server`
+* IP address
+* Available since: 3.5.3
+
+If set to an IP or IPv6 address, will send all available metrics to this server
+via the carbon protocol, which is used by graphite and metronome. You may specify
+an alternate port by appending :port, ex: 127.0.0.1:2004. See
+["PowerDNS Metrics"](../common/logging.md#sending-to-carbongraphitemetronome).
+
+## `chroot`
+* Path to a Directory
+If set, chroot to this directory for more security. See [Security](../common/security.md).
+
+Make sure that `/dev/log` is available from within the chroot. Logging will
+silently fail over time otherwise (on logrotate).
+
+When using `chroot`, all other paths (except for [`config-dir`](#config-dir) set
+in the configuration are relative to the new root.
+
+When using `chroot` and the API ([`webserver`](#webserver)), [`api-readonly`](#api-readonly)
+must be set and [`api-config-dir`](#api-config-dir) unset.
+
+## `client-tcp-timeout`
+* Integer
+* Default: 2
+
+Time to wait for data from TCP clients.
+
+## `config-dir`
+* Path
+
+Location of configuration directory (`recursor.conf`). Usually `/etc/powerdns`, but
+this depends on `SYSCONFDIR` during compile-time.
+
+## `config-name`
+* String
+* Default: unset
+
+When running multiple recursors on the same server, read settings from
+"name-recursor.conf", this will also rename the binary image.
+
+## `daemon`
+* Boolean
+* Default: no (since 4.0.0, 'yes' before 4.0.0)
+
+Operate in the background.
+
+## `delegation-only`
+* Domains, comma separated
+
+Which domains we only accept delegations from (a Verisign special).
+
+## `disable-packetcache`
+* Boolean
+* Default: no
+* Available since: 3.2
+
+Turn off the packet cache. Useful when running with Lua scripts that can not be
+cached.
+
+## `disable-syslog`
+* Boolean
+* Default: no
+
+Do not log to syslog, only to stdout. Use this setting when running inside a
+supervisor that handles logging (like systemd). **Note**: do not use this setting
+in combination with [`daemon`](#daemon) as all logging will disappear.
+
+## `dnssec`
+* One of `off`, `process-no-validate`, `process`, `log-fail`, `validate`, String
+* Default: `process-no-validate` (**note**: was `process` until 4.0.0-alpha2)
+* Available since: 4.0.0
+
+Set the mode for DNSSEC processing:
+
+### `off`
+No DNSSEC processing whatsoever. Ignore DO-bits in queries, don't request any
+DNSSEC information from authoritative servers. This behaviour is similar to
+PowerDNS Recursor pre-4.0.
+
+### `process-no-validate`
+Respond with DNSSEC records to clients that ask for it, set the DO bit on all
+outgoing queries. Don't do any validation.
+
+### `process`
+Respond with DNSSEC records to clients that ask for it, set the DO bit on all
+outgoing queries. Do validation for clients that request it (by means of the AD-
+bit or DO-bit in the query).
+
+### `log-fail`
+Similar behaviour to `process`, but validate RRSIGs on responses and log bogus
+responses.
+
+#### `validate`
+Full blown DNSSEC validation. Send SERVFAIL to clients on bogus responses.
+
+## `dnssec-log-bogus`
+* Boolean
+* Default: no
+* Available since: 4.0.0
+
+Log every DNSSEC validation failure.
+**Note**: This is not logged per-query but every time records are validated as Bogus.
+
+## `dont-query`
+* Netmasks, comma separated
+* Default: 127.0.0.0/8, 10.0.0.0/8, 100.64.0.0/10, 169.254.0.0/16, 192.168.0.0/16,
+ 172.16.0.0/12, ::1/128, fc00::/7, fe80::/10, 0.0.0.0/8, 192.0.0.0/24,
+ 192.0.2.0/24, 198.51.100.0/24, 203.0.113.0/24, 240.0.0.0/4, ::/96,
+ ::ffff:0:0/96, 100::/64, 2001:db8::/32
+* Available since: 3.1.5
+
+The DNS is a public database, but sometimes contains delegations to private IP
+addresses, like for example 127.0.0.1. This can have odd effects, depending on
+your network, and may even be a security risk. Therefore, since version 3.1.5,
+the PowerDNS recursor by default does not query private space IP addresses.
+This setting can be used to expand or reduce the limitations.
+
+## `edns-outgoing-bufsize`
+* Integer
+* Default: 1680
+
+This is the value set for the EDNS0 buffer size in outgoing packets.
+Lower this if you experience timeouts.
+
+## `edns-subnet-whitelist`
+* Comma separated list of domain names and netmasks
+* Default: (none)
+
+List of netmasks and domains that [EDNS Client Subnet](https://tools.ietf.org/html/rfc7871) should be enabled for in outgoing queries.
+For example, an EDNS Client Subnet option containing the address of the initial requestor will be added to an outgoing query sent to server 192.0.2.1 for domain X if 192.0.2.1 matches one of the supplied netmasks, or if X matches one of the supplied domains.
+The initial requestor address will be truncated to 24 bits for IPv4 and to 56 bits for IPv6, as recommended in the privacy section of RFC 7871.
+By default, this option is empty, meaning no EDNS Client Subnet information is sent.
+
+## `entropy-source`
+* Path
+* Default: /dev/urandom
+* Available since: 3.1.5
+
+PowerDNS can read entropy from a (hardware) source. This is used for generating
+random numbers which are very hard to predict. Generally on UNIX platforms,
+this source will be `/dev/urandom`, which will always supply random numbers,
+even if entropy is lacking. Change to `/dev/random` if PowerDNS should block
+waiting for enough entropy to arrive.
+
+## `etc-hosts-file`
+* Path
+* Default: /etc/hosts
+
+The path to the /etc/hosts file, or equivalent. This file can be used to serve
+data authoritatively using [`export-etc-hosts`](#export-etc-hosts).
+
+## `export-etc-hosts`
+* Boolean
+* Default: no
+* Available since: 3.1
+
+If set, this flag will export the host names and IP addresses mentioned in
+`/etc/hosts`.
+
+## `export-etc-hosts-search-suffix`
+* String
+* Available since: 3.4
+
+If set, all hostnames in the [`export-etc-hosts`](#export-etc-hosts) file are
+loaded in canonical form, based on this suffix, unless the name contains a '.',
+in which case the name is unchanged. So an entry called 'pc' with
+`export-etc-hosts-search-suffix='home.com'` will lead to the generation of
+'pc.home.com' within the recursor. An entry called 'server1.home' will be stored
+as 'server1.home', regardless of this setting.
+
+## `fork`
+* Boolean
+* Default: no
+* Available until: 3.2
+
+If running on an SMP system with enough memory, this feature forks PowerDNS so
+it benefits from two processors. Experimental. Renames controlsockets, so care
+is needed to connect to the right one using `rec_control`, using `socket-pid`.
+Available in versions of the Recursor before 3.2, replaced by the
+['threads'](#threads) setting.
+
+## `forward-zones`
+* 'zonename=IP' pairs, comma separated
+* Available since: 3.1
+
+Queries for zones listed here will be forwarded to the IP address listed. i.e.
+`forward-zones=example.org=203.0.113.210, powerdns.com=2001:DB8::BEEF:5`.
+
+Since version 3.1.5, multiple IP addresses can be specified. Additionally, port
+numbers other than 53 can be configured. Sample syntax:
+`forward-zones=example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;198.51.100.10:530;[2001:DB8::1:3]:5300`,
+or on the command line:
+`--forward-zones="example.org=203.0.113.210:5300;127.0.0.1, powerdns.com=127.0.0.1;9.8.7.6:530;[2001:DB8::1:3]:5300"`.
+
+Forwarded queries have the 'recursion desired' bit set to 0, meaning that this
+setting is intended to forward queries to authoritative servers.
+
+## `forward-zones-file`
+* Path
+* Available since: 3.1.5
+
+Same as [`forward-zones`](#forward-zones), parsed from a file. Only 1 zone is
+allowed per line, specified as follows: `example.org=203.0.113.210, 192.0.2.4:5300`.
+
+Since version 3.2, zones prefixed with a '+' are forwarded with the
+recursion-desired bit set to one, for which see ['forward-zones-recurse'](#forward-zones-recurse).
+Default behaviour without '+' is as with [`forward-zones`](#forward-zones).
+
+Comments are allowed since version 4.0.0. Everything behind '#' is ignored.
+
+## `forward-zones-recurse`
+* 'zonename=IP' pairs, comma separated
+* Available since: 3.2
+
+Like regular [`forward-zones`](#forward-zones), but forwarded queries have the
+'recursion desired' bit set to 1, meaning that this setting is intended to
+forward queries to other recursive servers.
+
+## `hint-file`
+* Path
+* Available since: 2.9.19
+
+If set, the root-hints are read from this file. If unset, default root hints are
+used.
+
+## `include-dir`
+* Path
+
+Directory to scan for additional config files. All files that end with .conf are
+loaded in order using `POSIX` as locale.
+
+## `latency-statistic-size`
+* Integer
+* Default: 10000
+* Available since 3.6
+
+Indication of how many queries will be averaged to get the average latency
+reported by the 'qa-latency' metric.
+
+## `local-address`
+* IP addresses, comma separated
+* Default: 127.0.0.1
+
+Local IPv4 or IPv6 addresses to bind to. Addresses can also contain port numbers,
+for IPv4 specify like this: `192.0.2.4:5300`, for IPv6: `[::1]:5300`.
+Port specifications are available since version 3.1.2.
+
+**Warning**: When binding to wildcard addresses, UNIX semantics mean that
+answers may not be sent from the address a query was received on. It is highly
+recommended to bind to explicit addresses.
+
+## `local-port`
+* Integer
+* Default: 53
+
+Local port to bind to.
+
+## `non-local-bind`
+* Boolean
+* Default: no
+* Available since: 4.0.0
+
+Bind to addresses even if one or more of the [`local-address`'s](#local-address)
+do not exist on this server. Setting this option will enable the needed socket
+options to allow binding to non-local addresses.
+This feature is intended to facilitate ip-failover setups, but it may also
+mask configuration issues and for this reason it is disabled by default.
+
+## `loglevel`
+* Integer between 0 and 9
+* Default: 4
+* Available since: 3.6
+
+Amount of logging. Higher is more, more logging may destroy performance.
+It is recommended not to set this below 3.
+
+## `log-common-errors`
+* Boolean
+* Default: no
+
+Some DNS errors occur rather frequently and are no cause for alarm.
+
+## `logging-facility`
+* Integer
+* Available since: 3.1.3
+
+If set to a digit, logging is performed under this LOCAL facility. See
+[Logging](../common/logging.md#logging). Do not pass names like 'local0'!
+
+## `lowercase-outgoing`
+* Boolean
+* Default: no
+* Available since: 4.0.0
+
+Set to true to lowercase the outgoing queries. When set to 'no' (the default) a
+query from a client using mixed case in the DNS labels (such as a user entering
+mixed-case names or [draft-vixie-dnsext-dns0x20-00](http://tools.ietf.org/html/draft-vixie-dnsext-dns0x20-00)),
+PowerDNS preserves the case of the query. Broken authoritative servers might give
+a wrong or broken answer on this encoding. Setting `lowercase-outgoing` to 'yes'
+makes the PowerDNS Recursor lowercase all the labels in the query to the authoritative
+servers, but still return the proper case to the client requesting.
+
+## `lua-config-file`
+* Filename
+* Available since 4.0.0
+
+If set, and Lua support is compiled in, this will load an additional configuration file
+for newer features and more complicated setups.
+
+### `addSortList`
+Sortlist is a complicated feature which allows for the ordering of A and
+AAAA records in answers to be modified, optionally dependently on who is
+asking. Since clients frequently connect to the 'first' IP address they see,
+this can effectively allow you to make sure that user from, say 10.0.0.0/8
+also preferrably connect to servers in 10.0.0.0/8.
+
+The syntax consists of a netmask for which this ordering instruction
+applies, followed by a set of netmask (groups) which describe the desired
+ordering. So an ordering instruction of "1.0.0.0/8", "2.0.0.0/8" will put
+anything within 1/8 first, and anything in 2/8 second. Other IP addresses
+would follow behind the addresses sorted earlier.
+
+If netmasks are grouped, this means these get equal ordering.
+
+`addSortList()` is intended to exactly mirror the semantics of the BIND
+sortlist option, but the syntax is slightly different.
+
+As an example, the following BIND sortlist:
+
+```
+{ 17.50.0.0/16; {17.238.240.0/24; 17.138.149.200;
+{17.218.242.254; 17.218.252.254;}; 17.38.42.80;
+17.208.240.100; }; };
+```
+
+Gets transformed into:
+
+```
+addSortList("17.50.0.0/16", {"17.238.240.0/24", "17.138.149.200",
+{"17.218.242.254", "17.218.252.254"}, "17.38.42.80",
+"17.208.240.100" })
+```
+
+In other words: each IP address is put within quotes, and are separated by
+commas instead of semicolons. For the rest everything is identical.
+
+### Response Policy Zone (RPZ)
+Response Policy Zone is an open standard developed by ISC, the authors of the BIND nameserver, to modify
+DNS responses based on a policy loaded via a zonefile.
+
+Frequently, Response Policy Zones get to be very large and change quickly,
+so it is customary to update them over IXFR.
+It allows the use of third-party feeds, and near real-time policy updates.
+
+An RPZ can be loaded from file or slaved from a master. To load from file, use for example:
+
+```
+rpzFile("dblfilename", {defpol=Policy.Custom, defcontent="badserver.example.com"})
+```
+
+To slave from a master and start IXFR to get updates, use for example:
+
+```
+rpzMaster("192.0.2.4", "policy.rpz", {defpol=Policy.Drop})
+```
+
+In this example, 'policy.rpz' denotes the name of the zone to query for.
+
+Settings for `rpzFile` and `rpzMaster` can contain:
+
+* defpol = Policy.Custom, Policy.Drop, Policy.NXDOMAIN, Policy.NODATA, Policy.Truncate, Policy.NoAction
+* defcontent = CNAME field to return in case of defpol=Policy.Custom
+* defttl = the TTL of the CNAME field to be synthesized. The default is to use the zone's TTL
+* policyName = the name logged as 'appliedPolicy' in protobuf messages when this policy is applied
+
+In addition to those, `rpzMaster` accepts:
+
+* tsigname = the name of the TSIG key to authenticate to the server (also set tsigalgo, tsigsecret)
+* tsigalgo = the name of the TSIG algorithm (like 'hmac-md5') used
+* tsigsecret = base64 encoded TSIG secret
+* refresh = an integer describing the interval between checks for updates. By default, the RPZ zone's default is used
+* maxReceivedMBytes = the maximum size in megabytes of an AXFR/IXFR update, to prevent resource exhaustion.
+The default value of 0 means no restriction.
+* localAddress = The source IP address to use when transferring the RPZ. When unset, [`query-local-address(6)`](#query-local-address) is used.
+
+If no settings are included, the RPZ is taken literally with no overrides applied.
+
+The policy action are:
+
+* Policy.Custom will return a NoError, CNAME answer with the value specified with `defcontent`
+* Policy.Drop will simply cause the query to be dropped
+* Policy.NoAction will continue normal processing of the query
+* Policy.NODATA will return a NoError response with no value in the answer section
+* Policy.NXDOMAIN will return a response with a NXDomain rcode
+* Policy.Truncate will return a NoError, no answer, truncated response over UDP. Normal processing will continue over TCP
+
+### Protocol Buffers (protobuf)
+PowerDNS Recursor has the ability to emit a stream of protocol buffers messages over TCP,
+containing information about queries, answers and policy decisions.
+
+Messages contain the IP address of the client initiating the query,
+the one on which the message was received, whether it was received over UDP or TCP,
+a timestamp and the qname, qtype and qclass of the question.
+In addition, messages related to responses contain the name, type, class
+and rdata of A, AAAA and CNAME records present in the response, as well as the response
+code.
+
+Finally, if a RPZ or custom Lua policy has been applied, response messages
+also contain the applied policy name and some tags. This is particularly useful
+to detect and act on infected hosts.
+
+Protobuf export to a server is enabled using the `protobufServer()` directive:
+
+```
+protobufServer("192.0.2.1:4242" [[[[[[, timeout], maxQueuedEntries], reconnectWaitTime], maskV4], maskV6], asynConnect])
+```
+
+The optional parameters are:
+
+* timeout = time in seconds to wait when sending a message, default to 2
+* maxQueuedEntries = how many entries will be kept in memory if the server becomes unreachable, default to 100
+* reconnectWaitTime = how long to wait, in seconds, between two reconnection attempts, default to 1
+* maskV4 = network mask to apply to the client IPv4 addresses, for anonymization purpose. The default of 32 means no anonymization
+* maskV6 = same as maskV4, but for IPv6. Default to 128
+* asyncConnect = if set to false (default) the first connection to the server during startup will block up to `timeout` seconds,
+otherwise the connection is done in a separate thread.
+
+The protocol buffers message types can be found in the [`dnsmessage.proto`](https://github.com/PowerDNS/pdns/blob/master/pdns/dnsmessage.proto) file.
+
+## `lua-dns-script`
+* Path
+* Default: unset
+
+Path to a lua file to manipulate the recursor's answers. See [Scripting the
+recursor](scripting.md).
+
+## `max-cache-entries`
+* Integer
+* Default: 1000000
+
+Maximum number of DNS cache entries. 1 million per thread will generally suffice
+for most installations.
+
+## `max-cache-ttl`
+* Integer
+* Default: 86400
+* Available since: 3.2
+
+Maximum number of seconds to cache an item in the DNS cache, no matter what the
+original TTL specified.
+
+## `max-mthreads`
+* Integer
+* Default: 2048
+
+Maximum number of simultaneous MTasker threads.
+
+## `max-packetcache-entries`
+* Integer
+* Default: 500000
+* Available since: 3.2
+
+Maximum number of Packet Cache entries. 1 million per thread will generally
+suffice for most installations.
+
+## `max-qperq`
+* Integer
+* Default: 50
+
+The maximum number of outgoing queries that will be sent out during the resolution
+of a single client query. This is used to limit endlessy chasing CNAME redirections.
+
+## `max-negative-ttl`
+* Integer
+* Default: 3600
+
+A query for which there is authoritatively no answer is cached to quickly deny a
+record's existence later on, without putting a heavy load on the remote server.
+In practice, caches can become saturated with hundreds of thousands of hosts
+which are tried only once. This setting, which defaults to 3600 seconds, puts a
+maximum on the amount of time negative entries are cached.
+
+## `max-tcp-clients`
+* Integer
+* Default: 128
+
+Maximum number of simultaneous incoming TCP connections allowed.
+
+## `max-tcp-per-client`
+* Integer
+* Default: 0 (unlimited)
+
+Maximum number of simultaneous incoming TCP connections allowed per client
+(remote IP address).
+
+## `max-total-msec`
+* Integer
+* Default: 7000
+
+Total maximum number of miliseconds of wallclock time the servermay use to answer
+a single query.
+
+## `minimum-ttl-override`
+* Integer
+* Default: 0 (disabled)
+
+This setting artificially raises all TTLs to be at least this long. While this
+is a gross hack, and violates RFCs, under conditions of DoS, it may enable you
+to continue serving your customers. Can be set at runtime using
+`rec_control set-minimum-ttl 3600`.
+
+## `network-timeout`
+* Integer
+* Default: 1500
+* Available since: 3.2
+
+Number of milliseconds to wait for a remote authoritative server to respond.
+
+## `packetcache-ttl`
+* Integer
+* Default: 3600
+* Available since: 3.2
+
+Maximum number of seconds to cache an item in the packet cache, no matter what
+the original TTL specified.
+
+## `packetcache-servfail-ttl`
+* Integer
+* Default: 60
+* Available since: 3.2
+
+Maximum number of seconds to cache a 'server failure' answer in the packet cache.
+From 4.0.0 onward, this settings maximum is capped to [`packetcache-ttl`](#packetcache-ttl).
+i.e. setting `packetcache-ttl=15` and keeping `packetcache-servfail-ttl` at the
+default will lower `packetcache-servfail-ttl` to `15`.
+
+## `pdns-distributes-queries`
+* Boolean
+* Default: yes (since 3.7.0), no (before 3.7.0)
+* Available since: 3.6
+
+If set, PowerDNS will have only 1 thread listening on client sockets, and
+distribute work by itself over threads. Improves performance on Linux. Do not
+use on Recursor versions before 3.6 as the feature was experimental back then,
+and not that stable.
+
+## `query-local-address`
+* IPv4 Address, comma separated
+* Default: 0.0.0.0
+* Available since: 3.2
+
+Send out local queries from this address, or addresses, by adding multiple
+addresses, increased spoofing resilience is achieved.
+
+## `query-local-address6`
+* IPv6 addresses, comma separated
+* Default: unset
+* Available since: 3.2
+
+Send out local IPv6 queries from this address or addresses. Disabled by default,
+which also disables outgoing IPv6 support.
+
+## `quiet`
+* Boolean
+* Default: yes
+
+Don't log queries.
+
+## `root-nx-trust`
+* Boolean
+* Default: no (<= 4.0.0), yes
+
+If set, an NXDOMAIN from the root-servers will serve as a blanket NXDOMAIN for the entire TLD
+the query belonged to. The effect of this is far fewer queries to the root-servers.
+
+## `security-poll-suffix`
+* String
+* Default: secpoll.powerdns.com.
+
+Domain name from which to query security update notifications. Setting this to
+an empty string disables secpoll.
+
+## `serve-rfc1918`
+* Boolean
+* Default: yes
+
+This makes the server authoritatively aware of: `10.in-addr.arpa`,
+`168.192.in-addr.arpa`, `16-31.172.in-addr.arpa`, which saves load on the AS112
+servers. Individual parts of these zones can still be loaded or forwarded.
+
+## `server-down-max-fails`
+* Integer
+* Default: 64
+* Available since: 3.6
+
+If a server has not responded in any way this many times in a row, no longer
+send it any queries for [`server-down-throttle-time`](#server-down-throttle-time)
+seconds. Afterwards, we will try a new packet, and if that also gets no response
+at all, we again throttle for [`server-down-throttle-time-seconds`](#server-down-throttle-time).
+Even a single response packet will drop the block.
+
+## `server-down-throttle-time`
+* Integer
+* Default: 60
+* Available since: 3.6
+
+Throttle a server that has failed to respond [`server-down-max-fails`](#server-down-max-fails)
+times for this many seconds.
+
+## `server-id`
+* String
+* Default: The hostname of the server
+
+The PowerDNS recursor by replies to a query for 'id.server' with its hostname,
+useful for in clusters. Use this setting to override the answer it gives.
+
+Query example (where 192.0.2.14 is your server):
+```
+dig @192.0.2.14 CHAOS TXT id.server.
+```
+
+## `setgid`, `setuid`
+* String
+* Default: unset
+
+PowerDNS can change its user and group id after binding to its socket. Can be
+used for better [security](security.md).
+
+## `single-socket`
+* Boolean
+* Default: no
+
+Use only a single socket for outgoing queries.
+
+## `socket-dir`
+* Path
+
+Where to store the control socket and pidfile. The default depends on
+`LOCALSTATEDIR` during compile-time (usually `/var/run` or `/run`).
+
+When using [`chroot`](#chroot) the default becomes to `/`.
+
+## `socket-owner`, `socket-group`, `socket-mode`
+Owner, group and mode of the controlsocket. Owner and group can be specified by
+name, mode is in octal.
+
+## `spoof-nearmiss-max`
+* Integer
+* Default: 20
+
+If set to non-zero, PowerDNS will assume it is being spoofed after seeing this
+many answers with the wrong id.
+
+## `stack-size`
+* Integer
+* Default: 200000
+
+Size of the stack per thread.
+
+## `stats-ringbuffer-entries`
+* Integer
+* Default: 10000
+
+Number of entries in the remotes ringbuffer, which keeps statistics on who is
+querying your server. Can be read out using `rec_control top-remotes`.
+
+## `threads`
+* Integer
+* Default: 2
+
+Spawn this number of threads on startup.
+
+## `trace`
+* Boolean
+* Default: no
+
+If turned on, output impressive heaps of logging. May destroy performance under
+load.
+
+## `udp-truncation-threshold`
+* Integer
+* Default: 1680
+
+EDNS0 allows for large UDP response datagrams, which can potentially raise
+performance. Large responses however also have downsides in terms of reflection
+attacks. This setting limits the accepted size. Maximum value is 65535, but
+values above 4096 should probably not be attempted.
+
+## `version`
+Print version of this binary. Useful for checking which version of the PowerDNS
+recursor is installed on a system. Available since version 3.1.5.
+
+## `version-string`
+* String
+* Default: PowerDNS Recursor version number
+
+By default, PowerDNS replies to the 'version.bind' query with its version number.
+Security conscious users may wish to override the reply PowerDNS issues.
+
+## `webserver`
+* Boolean
+* Default: no
+
+Start the webserver (for REST API).
+
+## `webserver-address`
+* IP Addresses, separated by spaces
+* Default: 127.0.0.1
+
+IP address for the webserver to listen on.
+
+## `webserver-allow-from`
+* IP addresses, comma separated
+* Default: 0.0.0.0, ::/0
+
+These subnets are allowed to access the webserver.
+
+## `webserver-password`
+* String
+* Default: unset
+
+Password required to access the webserver.
+
+## `webserver-port`
+* Integer
+* Default: 8082
+
+TCP port where the webserver should listen on.
+
+## `write-pid`
+* Boolean
+* Default: yes
+
+If a PID file should be written. Available since 4.0.
--- /dev/null
+# Recursor Statistics
+The `rec_control get` command can be used to query the following statistics, either single keys or multiple statistics at once:
+
+* `all-outqueries`: counts the number of outgoing UDP queries since starting
+* `answers-slow`: counts the number of queries answered after 1 second
+* `answers0-1`: counts the number of queries answered within 1 millisecond
+* `answers1-10`: counts the number of queries answered within 10 milliseconds
+* `answers10-100`: counts the number of queries answered within 100 milliseconds
+* `answers100-1000`: counts the number of queries answered within 1 second
+* `auth4-answers-slow`: counts the number of queries answered by auth4s after 1 second (4.0)
+* `auth4-answers0-1`: counts the number of queries answered by auth4s within 1 millisecond (4.0)
+* `auth4-answers1-10`: counts the number of queries answered by auth4s within 10 milliseconds (4.0)
+* `auth4-answers10-100`: counts the number of queries answered by auth4s within 100 milliseconds (4.0)
+* `auth4-answers100-1000`: counts the number of queries answered by auth4s within 1 second (4.0)
+* `auth6-answers-slow`: counts the number of queries answered by auth6s after 1 second (4.0)
+* `auth6-answers0-1`: counts the number of queries answered by auth6s within 1 millisecond (4.0)
+* `auth6-answers1-10`: counts the number of queries answered by auth6s within 10 milliseconds (4.0)
+* `auth6-answers10-100`: counts the number of queries answered by auth6s within 100 milliseconds (4.0)
+* `auth6-answers100-1000`: counts the number of queries answered by auth6s within 1 second (4.0)
+* `cache-bytes`: size of the cache in bytes (since 3.3.1)
+* `cache-entries`: shows the number of entries in the cache
+* `cache-hits`: counts the number of cache hits since starting, this does **not** include hits that got answered from the packet-cache
+* `cache-misses`: counts the number of cache misses since starting
+* `case-mismatches`: counts the number of mismatches in character case since starting
+* `chain-resends`: number of queries chained to existing outstanding query
+* `client-parse-errors`: counts number of client packets that could not be parsed
+* `concurrent-queries`: shows the number of MThreads currently running
+* `dlg-only-drops`: number of records dropped because of delegation only setting
+* `dnssec-queries`: number of queries received with the DO bit set
+* `dnssec-result-bogus`: number of DNSSEC validations that had the Bogus state
+* `dnssec-result-indeterminate`: number of DNSSEC validations that had the Indeterminate state
+* `dnssec-result-insecure`: number of DNSSEC validations that had the Insecure state
+* `dnssec-result-nta`: number of DNSSEC validations that had the NTA (negative trust anchor) state
+* `dnssec-result-secure`: number of DNSSEC validations that had the Secure state
+* `dnssec-validations`: number of DNSSEC validations performed
+* `dont-outqueries`: number of outgoing queries dropped because of 'dont-query' setting (since 3.3)
+* `edns-ping-matches`: number of servers that sent a valid EDNS PING response
+* `edns-ping-mismatches`: number of servers that sent an invalid EDNS PING response
+* `failed-host-entries`: number of servers that failed to resolve
+* `ignored-packets`: counts the number of non-query packets received on server sockets that should only get query packets
+* `ipv6-outqueries`: number of outgoing queries over IPv6
+* `ipv6-questions`: counts all end-user initiated queries with the RD bit set, received over IPv6 UDP
+* `malloc-bytes`: returns the number of bytes allocated by the process (broken, always returns 0)
+* `max-mthread-stack`: maximum amount of thread stack ever used
+* `negcache-entries`: shows the number of entries in the negative answer cache
+* `no-packet-error`: number of errorneous received packets
+* `noedns-outqueries`: number of queries sent out without EDNS
+* `noerror-answers`: counts the number of times it answered NOERROR since starting
+* `noping-outqueries`: number of queries sent out without ENDS PING
+* `nsset-invalidations`: number of times an nsset was dropped because it no longer worked
+* `nsspeeds-entries`: shows the number of entries in the NS speeds map
+* `nxdomain-answers`: counts the number of times it answered NXDOMAIN since starting
+* `outgoing-timeouts`: counts the number of timeouts on outgoing UDP queries since starting
+* `outgoing4-timeouts`: counts the number of timeouts on outgoing UDP IPv4 queries since starting (since 4.0)
+* `outgoing6-timeouts`: counts the number of timeouts on outgoing UDP IPv6 queries since starting (since 4.0)
+* `over-capacity-drops`: questions dropped because over maximum concurrent query limit (since 3.2)
+* `packetcache-bytes`: size of the packet cache in bytes (since 3.3.1)
+* `packetcache-entries`: size of packet cache (since 3.2)
+* `packetcache-hits`: packet cache hits (since 3.2)
+* `packetcache-misses`: packet cache misses (since 3.2)
+* `policy-drops`: packets dropped because of (Lua) policy decision
+* `policy-result-noaction`: packets that were not actioned upon by the RPZ/filter engine
+* `policy-result-drop`: packets that were dropped by the RPZ/filter engine
+* `policy-result-nxdomain`: packets that were replied to with NXDOMAIN by the RPZ/filter engine
+* `policy-result-nodata`: packets that were replied to with no data by the RPZ/filter engine
+* `policy-result-truncate`: packets that were forced to TCP by the RPZ/filter engine
+* `policy-result-custom`: packets that were sent a custom answer by the RPZ/filter engine
+* `qa-latency`: shows the current latency average, in microseconds, exponentially weighted over past 'latency-statistic-size' packets
+* `questions`: counts all end-user initiated queries with the RD bit set
+* `resource-limits`: counts number of queries that could not be performed because of resource limits
+* `security-status`: security status based on [security polling](../common/security.md#implementation)
+* `server-parse-errors`: counts number of server replied packets that could not be parsed
+* `servfail-answers`: counts the number of times it answered SERVFAIL since starting
+* `spoof-prevents`: number of times PowerDNS considered itself spoofed, and dropped the data
+* `sys-msec`: number of CPU milliseconds spent in 'system' mode
+* `tcp-client-overflow`: number of times an IP address was denied TCP access because it already had too many connections
+* `tcp-clients`: counts the number of currently active TCP/IP clients
+* `tcp-outqueries`: counts the number of outgoing TCP queries since starting
+* `tcp-questions`: counts all incoming TCP queries (since starting)
+* `throttle-entries`: shows the number of entries in the throttle map
+* `throttled-out`: counts the number of throttled outgoing UDP queries since starting
+* `throttled-outqueries`: idem to throttled-out
+* `too-old-drops`: questions dropped that were too old
+* `unauthorized-tcp`: number of TCP questions denied because of allow-from restrictions
+* `unauthorized-udp`: number of UDP questions denied because of allow-from restrictions
+* `unexpected-packets`: number of answers from remote servers that were unexpected (might point to spoofing)
+* `unreachables`: number of times nameservers were unreachable since starting
+* `uptime`: number of seconds process has been running (since 3.1.5)
+* `user-msec`: number of CPU milliseconds spent in 'user' mode
+
+In the `pdns/tools/rrd/` subdirectory a number of rrdtool scripts is provided to
+make nice graphs of all these numbers. Use `rec_control get-all` to get all
+statistics in one go.
+
+It should be noted that answers0-1 + answers1-10 + answers10-100 + answers100-1000 +
+answers-slow + packetcache-hits + over-capacity-drops + policy-drops = questions.
+
+Also note that unauthorized-tcp and unauthorized-udp packets do not end up in
+the 'questions' count.
+
+Every half hour or so, the recursor outputs a line with statistics. More
+infrastructure is planned so as to allow for Cricket or MRTG graphs. To force
+the output of statistics, send the process a SIGUSR1. A line of statistics looks
+like this:
+
+```
+Feb 10 14:16:03 stats: 125784 questions, 13971 cache entries, 309 negative entries, 84% cache hits, outpacket/query ratio 37%, 12% throttled
+```
+
+This means that there are 13791 different names cached, which each may have
+multiple records attached to them. There are 309 items in the negative cache,
+items of which it is known that don't exist and won't do so for the near future.
+84% of incoming questions could be answered without any additional queries going
+out to the net.
+
+The outpacket/query ratio means that on average, 0.37 packets were needed to
+answer a question. Initially this ratio may be well over 100% as additional
+queries may be needed to actually recurse the DNS and figure out the addresses
+of nameservers.
+
+Finally, 12% of queries were not performed because identical queries had gone out
+previously, saving load on servers worldwide.
--- /dev/null
+Before upgrading, it is advised to read the [changelog](../changelog.md).
+When upgrading several versions, please read **all** notes applying to the upgrade.
+
+# 4.0.0 to 4.0.1
+Two settings have changed defaults, these new defaults decrease CPU usage:
+
+ - [`root-nx-trust`](settings.md#root-nx-trust) changed from `no` to `yes`
+ - [`log-common-errors`](settings.md#log-common-errors) changed from `yes` to `no`
--- /dev/null
+# Security Policy
+
+If you have a security problem to report, please email us at both <a href="mailto:security@netherlabs.nl">security@netherlabs.nl</a> and <a href="mailto:ahu@ds9a.nl">ahu@ds9a.nl</a>. Please do not mail security issues to public lists, nor file a ticket, unless we do not get back to you in a timely manner. We fully credit reporters of security issues, and respond quickly, but please allow us a reasonable timeframe to coordinate a response.
+
+We remind PowerDNS users that under the terms of the GNU General Public License, PowerDNS comes with ABSOLUTELY NO WARRANTY. This license is included in this documentation.
+
+As of the 2nd of September 2015, no actual security problems with PowerDNS Authoritative Server 3.4.6, Recursor 3.6.3, Recursor 3.7.2, or later are known about. This page will be updated with all bugs which are deemed to be security problems, or could conceivably lead to those. Any such notifications will also be sent to all PowerDNS mailing lists.
+
+PowerDNS Authoritative Server 3.4.0 through 3.4.5 can have their threads crashed with a malformed packet, see [PowerDNS Security Advisory 2015-02](powerdns-advisory-2015-02.md) for more information.
+
+All recent Recursor versions up to and including 3.6.2 and 3.7.1, and all recent Authoritative servers up to and including version 3.4.3, can in specific situations be crashed with a malformed packet. For more detail, see [PowerDNS Security Advisory 2015-01](powerdns-advisory-2015-01.md)
+
+All Recursor versions up to and including 3.6.1 can be made to provide degraded service. For more detail, see [PowerDNS Security Advisory 2014-02](powerdns-advisory-2014-02.md)
+
+Version 3.6.0 of the Recursor (but not 3.5.x) can be crashed remotely with a specific packet sequence. For more detail, see [PowerDNS Security Advisory 2014-01](powerdns-advisory-2014-01.md)
+
+Versions 2.9.22 and lower and 3.0 of the PowerDNS Authoritative Server were vulnerable to a temporary denial of service attack. For more detail, see [PowerDNS Security Advisory 2012-01](powerdns-advisory-2012-01.md).
+
+Version 3.1.7.1 and earlier of the PowerDNS Recursor were vulnerable to a probably exploitable buffer overflow and a spoofing attack. For more detail, see [PowerDNS Security Advisory 2010-01](powerdns-advisory-2010-01.md "PowerDNS Security Advisory 2010-01: PowerDNS Recursor up to and including 3.1.7.1 can be brought down and probably exploited") and [PowerDNS Security Advisory 2010-02](powerdns-advisory-2010-02.md "PowerDNS Recursor up to and including 3.1.7.1 can be spoofed into accepting bogus data").
+
+Version 3.1.4 and earlier of the PowerDNS recursor were vulnerable to a spoofing attack. For more detail, see [PowerDNS Security Advisory 2008-01](powerdns-advisory-2008-01.md "System random generator can be predicted, leading to the potential to 'spoof' PowerDNS Recursor").
+
+Version 3.1.3 and earlier of the PowerDNS recursor contain two security issues, both of which can lead to a denial of service, both of which can be triggered by remote users. One of the issues might be exploited and ead to a system compromise. For more detail, see [PowerDNS Security Advisory 2006-01](powerdns-advisory-2006-01.md "Malformed TCP queries can lead to a buffer overflow which might be exploitable") and [PowerDNS Security Advisory 2006-02](powerdns-advisory-2006-02.md "Zero second CNAME TTLs can make PowerDNS exhaust allocated stack space, and crash").
+
+Version 3.0 of the PowerDNS recursor contains a denial of service bug which can be exploited remotely. This bug, which we believe to only lead to a crash, has been fixed in 3.0.1. There are no guarantees however, so an upgrade from 3.0 is highly recommended.
+
+All versions of PowerDNS before 2.9.21.1 do not respond to certain queries. This in itself is not a problem, but since the discovery by Dan Kaminsky of a new spoofing technique, this silence for queries PowerDNS considers invalid, within a valid domain, allows attackers more chances to feed *other* resolvers bad data.
+
+All versions of PowerDNS before 2.9.18 contain the following two bugs, which only apply to installations running with the LDAP backend, or installations providing recursion to a limited range of IP addresses. If any of these apply to you, an upgrade is highly advised:
+
+ * The LDAP backend did not properly escape all queries, allowing it to fail and not answer questions. We have not investigated further risks involved, but we advise LDAP users to update as quickly as possible (Norbert Sendetzky, Jan de Groot)
+
+ * Questions from clients denied recursion could blank out answers to clients who are allowed recursion services, temporarily. Reported by Wilco Baan. This would've made it possible for outsiders to blank out a domain temporarily to your users. Luckily PowerDNS would send out SERVFAIL or Refused, and not a denial of a domain's existence.
+
+All versions of PowerDNS before 2.9.17 are known to suffer from remote denial of service problems which can disrupt operation. Please upgrade to 2.9.17 as this page will only contain detailed security information from 2.9.17 onwards.
--- /dev/null
+## PowerDNS Security Advisory 2006-01: Malformed TCP queries can lead to a buffer overflow which might be exploitable
+
+
+ * CVE: CVE-2006-4251
+ * Date: 13th of November 2006
+ * Affects: PowerDNS Recursor versions 3.1.3 and earlier, on all operating systems.
+ * Not affected: No versions of the PowerDNS Authoritative Server ('pdns\_server') are affected.
+ * Severity: Critical
+ * Impact: Potential remote system compromise.
+ * Exploit: As far as we know, no exploit is available as of 11th of November 2006.
+ * Solution: Upgrade to PowerDNS Recursor 3.1.4, or apply the patches referred below and recompile
+ * Workaround: Disable TCP access to the Recursor. This will have slight operational impact, but it is likely that this will not lead to meaningful degradation of service. Disabling access is best performed at packet level, either by configuring a firewall, or instructing the host operating system to drop TCP connections to port 53. Additionally, exposure can be limited by configuring the `allow-from` setting so only trusted users can query your nameserver.
+
+PowerDNS Recursor 3.1.3 and previous miscalculate the length of incoming TCP DNS queries, and will attempt to read up to 4 gigabytes of query into a 65535 byte buffer.
+
+We have not verified if this problem might actually lead to a system compromise, but are acting on the assumption that it might.
+
+For distributors, a minimal patch is available on [the PowerDNS wiki](http://wiki.powerdns.com/cgi-bin/trac.fcgi/changeset/915). Additionally, those shipping very old versions of the PowerDNS Recursor might benefit from this [patch](http://ds9a.nl/tmp/cve-2006-4251.patch).
+
+The impact of these and other security problems can be lessened by considering the advice in FIXME: security-settings.
--- /dev/null
+## PowerDNS Security Advisory 2006-02: Zero second CNAME TTLs can make PowerDNS exhaust allocated stack space, and crash
+
+ * CVE: CVE-2006-4252
+ * Date: 13th of November 2006
+ * Affects: PowerDNS Recursor versions 3.1.3 and earlier, on all operating systems.
+ * Not affected: No versions of the PowerDNS Authoritative Server ('pdns\_server') are affected.
+ * Severity: Moderate
+ * Impact: Denial of service
+ * Exploit: This problem can be triggered by sending queries for specifically configured domains
+ * Solution: Upgrade to PowerDNS Recursor 3.1.4, or apply [commit 919](http://wiki.powerdns.com/projects/trac/changeset/919).
+ * Workaround: None known. Exposure can be limited by configuring the **allow-from** setting so only trusted users can query your nameserver.
+
+PowerDNS would recurse endlessly on encountering a CNAME loop consisting entirely of zero second CNAME records, eventually exceeding resources and crashing.
--- /dev/null
+## PowerDNS Security Advisory 2008-01: System random generator can be predicted, leading to the potential to 'spoof' PowerDNS Recursor
+
+ * CVE: Not yet assigned
+ * Date: 31st of March 2008
+ * Affects: PowerDNS Recursor versions 3.1.4 and earlier, on most operating systems
+ * Not affected: No versions of the PowerDNS Authoritative Server ('pdns\_server') are affected.
+ * Severity:Moderate
+ * Impact: Data manipulation; client redirection
+ * Exploit: This problem can be triggered by sending queries for specifically configured domains, sending spoofed answer packets immediately afterwards.
+ * Solution: Upgrade to PowerDNS Recursor 3.1.5, or apply changesets [1159](http://wiki.powerdns.com/projects/trac/changeset/1159), [1160](http://wiki.powerdns.com/projects/trac/changeset/1160) and [1164](http://wiki.powerdns.com/projects/trac/changeset/1164).
+ * Workaround: None known. Exposure can be limited by configuring the **allow-from** setting so only trusted users can query your nameserver.
+
+We would like to thank Amit Klein of Trusteer for bringing a serious vulnerability to our attention which would enable a smart attacker to 'spoof' previous versions of the PowerDNS Recursor into accepting possibly malicious data.
+
+Details can be found on [this Trusteer page](http://www.trusteer.com/docs/powerdnsrecursor.html).
+
+This security problem was announced in [this email message](http://mailman.powerdns.com/pipermail/pdns-users/2008-March/005279.html).
+
+It is recommended that all users of the PowerDNS Recursor upgrade to 3.1.5 as soon as practicable, while we simultaneously note that busy servers are less susceptible to the attack, but not immune.
+
+The vulnerability is present on all operating systems where the behaviour of the libc random() function can be predicted based on its past output. This includes at least all known versions of Linux, as well as Microsoft Windows, and probably FreeBSD and Solaris.
+
+The magnitude of this vulnerability depends on internal details of the system random() generator. For Linux, the mathematics of the random generator are complex, but well understood and Amit Klein has written and published a proof of concept that can successfully predict its output after uninterrupted observation of 40-50 DNS queries.
+
+Because the observation needs to be uninterrupted, busy PowerDNS Recursor instances are harder to subvert - other data is highly likely to be interleaved with traffic generated by an attacker.
+
+Nevertheless, operators are urged to update at their earliest convenience.
--- /dev/null
+## PowerDNS Security Advisory 2008-02: By not responding to certain queries, domains become easier to spoof
+
+ * CVE: CVE-2008-3337
+ * Date: 6th of August 2008
+ * Affects: PowerDNS Authoritative Server 2.9.21 and earlier
+ * Not affected: No versions of the PowerDNS Recursor ('pdns\_recursor') are affected.
+ * Severity: Moderate
+ * Impact: Data manipulation; client redirection
+ * Exploit: Domains with servers that drop certain queries can be spoofed using simpler measures than would usually be required
+ * Solution: Upgrade to PowerDNS Authoritative Server 2.9.21.1, or apply [commit 1239](http://wiki.powerdns.com/projects/trac/changeset/1239).
+ * Workaround: None known.
+
+Brian J. Dowling of Simplicity Communications has discovered a security implication of the previous PowerDNS behaviour to drop queries it considers malformed. We are grateful that Brian notified us quickly about this problem.
+
+The implication is that while the PowerDNS Authoritative server itself does not face a security risk because of dropping these malformed queries, other resolving nameservers run a higher risk of accepting spoofed answers for domains being hosted by PowerDNS Authoritative Servers before 2.9.21.1.
+
+While the dropping of queries does not aid sophisticated spoofing attempts, it does facilitate simpler attacks.
--- /dev/null
+## PowerDNS Security Advisory 2008-03: Some PowerDNS Configurations can be forced to restart remotely
+
+ * CVE: Not yet assigned
+ * Date: 18th of November 2008
+ * Affects: PowerDNS Authoritative Server 2.9.21.1 and earlier
+ * Not affected: No versions of the PowerDNS Recursor (`pdns_recursor`) are affected. Versions not running in single threaded mode (`distributor-threads=1`) are probably not affected.
+ * Severity: Moderate
+ * Impact: Denial of Service
+ * Exploit: Send PowerDNS an CH HINFO query.
+ * Solution: Upgrade to PowerDNS Authoritative Server 2.9.21.2, or wait for 2.9.22.
+ * Workaround: Remove `distributor-threads=1` if this is set.
+
+Daniel Drown discovered that his PowerDNS 2.9.21.1 installation crashed on receiving a HINFO CH query. In his enthusiasm, he shared his discovery with the world, forcing a rapid over the weekend release cycle.
+
+While we thank Daniel for his discovery, please study our security policy as outlined in ["Security"](#security) before making vulnerabilities public.
+
+It is believed that this issue only impacts PowerDNS Authoritative Servers operating with `distributor-threads=1`, but even on other configurations a database reconnect occurs on receiving a CH HINFO query.
--- /dev/null
+## PowerDNS Security Advisory 2010-01: PowerDNS Recursor up to and including 3.1.7.1 can be brought down and probably exploited
+
+ * CVE: CVE-2009-4009
+ * Date: 6th of January 2010
+ * Affects: PowerDNS Recursor 3.1.7.1 and earlier
+ * Not affected: No versions of the PowerDNS Authoritative ('pdns\_server') are affected.
+ * Severity: Critical
+ * Impact: Denial of Service, possible full system compromise
+ * Exploit: Withheld
+ * Solution: Upgrade to PowerDNS Recursor 3.1.7.2 or higher
+ * Workaround: None. The risk of exploitation or denial of service can be decreased slightly by using the `allow-from` setting to only provide service to known users. The risk of a full system compromise can be reduced by running with a suitable reduced privilege user and group settings, and possibly chroot environment.
+
+Using specially crafted packets, it is possible to force a buffer overflow in the PowerDNS Recursor, leading to a crash.
+
+This vulnerability was discovered by a third party that (for now) prefers not to be named. PowerDNS is very grateful however for their help in improving PowerDNS security.
--- /dev/null
+## PowerDNS Security Advisory 2010-02: PowerDNS Recursor up to and including 3.1.7.1 can be spoofed into accepting bogus data
+
+ * CVE: CVE-2009-4010
+ * Date: 6th of January 2010
+ * Affects: PowerDNS Recursor 3.1.7.1 and earlier
+ * Not affected: No versions of the PowerDNS Authoritative ('pdns\_server') are affected.
+ * Severity: High
+ * Impact: Using smart techniques, it is possible to fool the PowerDNS Recursor into accepting unauthorized data
+ * Exploit: Withheld
+ * Solution: Upgrade to PowerDNS Recursor 3.1.7.2 or higher
+ * Workaround: None.
+
+Using specially crafted zones, it is possible to fool the PowerDNS Recursor into accepting bogus data. This data might be harmful to your users. An attacker would be able to divert data from, say, bigbank.com to an IP address of his choosing.
+
+This vulnerability was discovered by a third party that (for now) prefers not to be named. PowerDNS is very grateful however for their help in improving PowerDNS security.
--- /dev/null
+## PowerDNS Security Advisory 2012-01: PowerDNS Authoritative Server can be caused to generate a traffic loop
+
+
+ * CVE: CVE-2012-0206
+ * Date: 10th of January 2012
+ * Credit: Ray Morris of [BetterCGI.com](http://BetterCGI.com/).
+ * Affects: Most PowerDNS Authoritative Server versions < 3.0.1 (with the exception of 2.9.22.5 and 2.9.22.6)
+ * Not affected: No versions of the PowerDNS Recursor ('pdns\_recursor') are affected.
+ * Severity: High
+ * Impact: Using well crafted UDP packets, one or more PowerDNS servers could be made to enter a tight packet loop, causing temporary denial of service
+ * Exploit: Proof of concept
+ * Risk of system compromise: No
+ * Solution: Upgrade to PowerDNS Authoritative Server 2.9.22.5 or 3.0.1
+ * Workaround: Several, the easiest is setting: `cache-ttl=0`, which does have a performance impact. Please see below.
+
+Affected versions of the PowerDNS Authoritative Server can be made to respond to DNS responses, thus enabling an attacker to setup a packet loop between two PowerDNS servers, perpetually answering each other's answers. In some scenarios, a server could also be made to talk to itself, achieving the same effect.
+
+If enough bouncing traffic is generated, this will overwhelm the server or network and disrupt service.
+
+As a workaround, if upgrading to a non-affected version is not possible, several options are available. The issue is caused by the packet-cache, which can be disabled by setting 'cache-ttl=0', although this does incur a performance penalty. This can be partially addressed by raising the query-cache-ttl to a (far) higher value.
+
+Alternatively, on Linux systems with a working iptables setup, 'responses' sent to the PowerDNS Authoritative Server 'question' address can be blocked by issuing:
+
+```
+ iptables -I INPUT -p udp --dst $AUTHIP --dport 53 \! -f -m u32 --u32 "0>>22&0x3C@8>>15&0x01=1" -j DROP
+
+```
+
+If this command is used on a router or firewall, substitute FORWARD for INPUT.
+
+To solve this issue, we recommend upgrading to the latest packages available for your system. Tarballs and new static builds (32/64bit, RPM/DEB) of 2.9.22.5 and 3.0.1 have been uploaded to [our download site](http://www.powerdns.com/content/downloads.html). Kees Monshouwer has provided updated CentOS/RHEL packages in [his repository](http://www.monshouwer.eu/download/3th_party/). Debian, Fedora and SuSE should have packages available shortly after this announcement.
+
+For those running custom PowerDNS versions, just applying this patch may be easier:
+
+```
+--- pdns/common_startup.cc (revision 2326)
++++ pdns/common_startup.cc (working copy)
+@@ -253,7 +253,9 @@
+ numreceived4++;
+ else
+ numreceived6++;
+-
++ if(P->d.qr)
++ continue;
++
+ S.ringAccount("queries", P->qdomain+"/"+P->qtype.getName());
+ S.ringAccount("remotes",P->getRemote());
+ if(logDNSQueries) {
+```
+
+It should apply cleanly to 3.0 and with little trouble to several older releases, including 2.9.22 and 2.9.21.
+
+This bug resurfaced because over time, the check for 'not responding to responses' moved to the wrong place, allowing certain responses to be processed anyhow.
+
+We would like to thank Ray Morris of [BetterCGI.com](http://BetterCGI.com/) for bringing this issue to our attention and Aki Tuomi for helping us reproduce the problem.
--- /dev/null
+## PowerDNS Security Advisory 2014-01: PowerDNS Recursor 3.6.0 can be crashed remotely
+
+* CVE: CVE-2014-3614
+* Date: 10th of September 2014
+* Credit: Dedicated PowerDNS users willing to study a crash that happens once every few months (thanks)
+* Affects: Only PowerDNS Recursor version 3.6.0.
+* Not affected: No other versions of PowerDNS Recursor, no versions of PowerDNS Authoritative Server
+* Severity: High
+* Impact: Crash
+* Exploit: The sequence of packets required is known
+* Risk of system compromise: No
+* Solution: Upgrade to PowerDNS Recursor 3.6.1
+* Workaround: Restrict service using [`allow-from`](../recursor/settings.md#allow-from), install script that restarts PowerDNS
+
+Recently, we've discovered that PowerDNS Recursor 3.6.0 (but NOT earlier) can crash when exposed to a specific sequence of malformed packets. This sequence happened spontaneously with one of our largest deployments, and the packets did not appear to have a malicious origin.
+
+Yet, this crash can be triggered remotely, leading to a denial of service attack. There appears to be no way to use this crash for system compromise or stack overflow.
+
+Upgrading to 3.6.1 solves the issue.
+
+In addition, if you want to apply a minimal fix to your own tree, it can be found [here](https://xs.powerdns.com/tmp/minipatch-3.6.1)
+
+As for workarounds, only clients in allow-from are able to trigger the crash, so this should be limited to your userbase. Secondly, [this](https://github.com/PowerDNS/pdns/blob/master/contrib/upstart-recursor.conf) and [this](https://github.com/PowerDNS/pdns/blob/master/contrib/systemd-pdns-recursor.service) can be used to enable Upstart and Systemd to restart the PowerDNS Recursor automatically.
--- /dev/null
+## PowerDNS Security Advisory 2014-02: PowerDNS Recursor 3.6.1 and earlier can be made to provide bad service
+
+* CVE: CVE-2014-8601
+* Date: 8th of December 2014
+* Credit: Florian Maury ([ANSSI](http://www.ssi.gouv.fr/en/))
+* Affects: PowerDNS Recursor versions 3.6.1 and earlier
+* Not affected: PowerDNS Recursor 3.6.2; no versions of PowerDNS Authoritative Server
+* Severity: High
+* Impact: Degraded service
+* Exploit: This problem can be triggered by sending queries for specifically configured domains
+* Risk of system compromise: No
+* Solution: Upgrade to PowerDNS Recursor 3.6.2
+* Workaround: None known. Exposure can be limited by configuring the **allow-from** setting so only trusted users can query your nameserver.
+
+Recently we released PowerDNS Recursor 3.6.2 with a new feature that
+strictly limits the amount of work we'll perform to resolve a single query.
+This feature was inspired by performance degradations noted when resolving
+domains hosted by 'ezdns.it', which can require thousands of queries to
+resolve.
+
+During the 3.6.2 release process, we were contacted by a government security
+agency with news that they had found that all major caching nameservers,
+including PowerDNS, could be negatively impacted by specially configured,
+hard to resolve domain names. With their permission, we continued the 3.6.2
+release process with the fix for the issue already in there.
+
+We recommend that all users upgrade to 3.6.2 if at all possible. Alternatively,
+if you want to apply a minimal fix to your own tree, it can be found
+[here](https://downloads.powerdns.com/patches/2014-02/), including patches for older versions.
+
+As for workarounds, only clients in allow-from are able to trigger the
+degraded service, so this should be limited to your userbase.
--- /dev/null
+## PowerDNS Security Advisory 2015-01: Label decompression bug can cause crashes or CPU spikes
+
+* CVE: CVE-2015-1868 (original), CVE-2015-5470 (update)
+* Date: 23rd of April 2015, updated 7th of July 2015
+* Credit: Aki Tuomi, Toshifumi Sakaguchi
+* Affects: PowerDNS Recursor versions 3.5 and up; Authoritative Server 3.2 and up
+* Not affected: Recursor 3.6.4; Recursor 3.7.3; Auth 3.3.3; Auth 3.4.5
+* Severity: High
+* Impact: Degraded service
+* Exploit: This problem can be triggered by sending queries for specifically configured domains, or by sending specially crafted query packets
+* Risk of system compromise: No
+* Solution: Upgrade to any of the non-affected versions
+* Workaround: Run your Recursor under a supervisor. Exposure can be limited by
+ configuring the [`allow-from`](../recursor/settings.md#allow-from) setting so
+ only trusted users can query your nameserver. There is no workaround for the
+ Authoritative server.
+
+A bug was discovered in our label decompression code, making it possible for
+names to refer to themselves, thus causing a loop during decompression. On
+some platforms, this bug can be abused to cause crashes. On all platforms,
+this bug can be abused to cause service-affecting CPU spikes.
+
+We recommend that all users upgrade to a corrected version if at all possible.
+Alternatively, if you want to apply a minimal fix to your own tree, please
+[find patches here](https://downloads.powerdns.com/patches/2015-01/).
+
+As for workarounds, for the Recursor: only clients in allow-from are able to
+trigger the degraded service, so this should be limited to your userbase;
+further, we recommend running your critical services under supervision such
+as systemd, supervisord, daemontools, etc.
+
+There is no workaround for the Authoritative Server.
+
+We want to thank Aki Tuomi for noticing this in production, and then digging
+until he got to the absolute bottom of what at the time appeared to be a
+random and spurious failure.
+
+We want to thank Toshifumi Sakaguchi for further investigation into the issue
+after the initial announcement, and for demonstrating to us quite clearly the
+CPU spike issues.
+
+Update 7th of July 2015: Toshifumi Sakaguchi discovered that the original fix
+was insufficient in some cases. Updated versions of the Authoritative Server and
+Recursor [were released](../changelog.md#powerdns-recursor-364) on the 9th of June.
+Minimal patches are [available](http://downloads.powerdns.com/patches/2015-01/).
+The insufficient fix was assigned CVE-2015-5470.
--- /dev/null
+## PowerDNS Security Advisory 2015-02: Packet parsing bug can cause thread or process abortion
+
+* CVE: CVE-2015-5230
+* Date: 2nd of September 2015
+* Credit: Pyry Hakulinen and Ashish Shukla at Automattic
+* Affects: PowerDNS Authoritative Server 3.4.0 through 3.4.5
+* Not affected: PowerDNS Authoritative Server 3.4.6
+* Severity: High
+* Impact: Degraded service or Denial of service
+* Exploit: This problem can be triggered by sending specially crafted query packets
+* Risk of system compromise: No
+* Solution: Upgrade to a non-affected version
+* Workaround: Run the Authoritative Server inside a supervisor when
+ `distributor-threads` is set to `1` to prevent Denial of Service.
+ No workaround for the degraded service exists
+
+A bug was found in our DNS packet parsing/generation code, which, when exploited,
+can cause individual threads (disabling service) or whole processes (allowing a
+supervisor to restart them) to crash with just one or a few query packets.
+
+PowerDNS Authoritative Server 3.4.0-3.4.5 are affected. No other versions are
+affected. The PowerDNS Recursor is not affected.
+
+[PowerDNS Authoritative Server 3.4.6](../changelog.md#powerdns-authoritative-server-346)
+contains a fix to this issue. A minimal patch is [available here](https://downloads.powerdns.com/patches/2015-02/).
+
+This issue is entirely unrelated to [Security Advisory 2015-01](powerdns-advisory-2015-01.md)/CVE-2015-1868.
+
+We'd like to thank Pyry Hakulinen and Ashish Shukla at Automattic for finding and
+subsequently reporting this bug.
--- /dev/null
+## PowerDNS Security Advisory 2015-03: Packet parsing bug can lead to crashes
+
+* CVE: CVE-2015-5311
+* Date: November 9th 2015
+* Credit: Christian Hofstaedtler of Deduktiva GmbH
+* Affects: PowerDNS Authoritative Server 3.4.4 through 3.4.6
+* Not affected: PowerDNS Authoritative Server 3.3.x and 3.4.7 and up
+* Severity: High
+* Impact: Degraded service or Denial of service
+* Exploit: This problem can be triggered by sending specially crafted query packets
+* Risk of system compromise: No
+* Solution: Upgrade to a non-affected version
+* Workaround: run the process inside the guardian or inside a supervisor
+
+A bug was found using `afl-fuzz` in our packet parsing code. This bug, when
+exploited, causes an assertion error and consequent termination of the the
+`pdns_server` process, causing a Denial of Service.
+
+When the PowerDNS Authoritative Server is run inside the guardian (`--guardian`),
+or inside a supervisor like supervisord or systemd, it will be automatically
+restarted, limiting the impact to a somewhat degraded service.
+
+PowerDNS Authoritative Server 3.4.4 - 3.4.6 are affected. No other versions are
+affected. The PowerDNS Recursor is not affected.
+
+[PowerDNS Authoritative Server 3.4.7](../changelog.md#powerdns-authoritative-server-347)
+contains a fix to this issue. A minimal patch is [available here](https://downloads.powerdns.com/patches/2015-03/).
+
+This issue is unrelated to the issues in our previous two Security Announcements
+([2015-01](powerdns-advisory-2015-01.md) and [2015-02](powerdns-advisory-2015-02.md)).
+
+We'd like to thank Christian Hofstaedtler of Deduktiva GmbH for finding and reporting this issue.
--- /dev/null
+# Tools to analyse DNS traffic
+DNS is highly mission critical, it is therefore necessary to be able to
+study and compare DNS traffic. Since version 2.9.18, PowerDNS comes with
+various tools to aid in analysis.
+
+The following tools are available:
+
+ * [dnsbulktest](../manpages/dnsbulktest.1.md) - A resolver stress-tester
+ * [dnsgram](../manpages/dnsgram.1.md) - Show per 5-second statistics to study intermittent resolver issues
+ * [dnsreplay](../manpages/dnsreplay.1.md) - Replay a pcap with DNS queries
+ * [dnsscan](../manpages/dnsscan.1.md) - Prints the query-type amounts in a pcap
+ * [dnsscope](../manpages/dnsscope.1.md) - Calculates statistics without replaying traffic
+ * [dnstcpbench](../manpages/dnstcpbench.1.md) - Perform TCP benchmarking of DNS servers
+ * [dnswasher](../manpages/dnswasher.1.md) - Clean a pcap of identifying IP information
+ * [nsec3dig](../manpages/nsec3dig.1.md) - Calculate the correctness of NSEC3 proofs
+ * [saxfr](../manpages/saxfr.1.md) - AXFR zones and show extra information
+
+# Downloading the tools
+The PowerDNS tools do not (yet) follow an independent release process.
+However, we keep them working, and they are shipped with PowerDNS
+Authoritative Server tarballs.
+
+In addition, our build infrastructure creates fresh Linux packages for every
+commit, and these can be found on:
+
+ * <https://autotest.powerdns.com/job/auth-git-semistatic-deb-amd64/>
+ * <https://autotest.powerdns.com/job/auth-git-semistatic-deb-i386/>
+ * <https://autotest.powerdns.com/job/auth-git-semistatic-rpm-amd64/>
+ * <https://autotest.powerdns.com/job/auth-git-semistatic-rpm-i386/>
--- /dev/null
+# Supported Record Types
+This chapter lists all record types PowerDNS supports, and how they are stored in
+backends. The list is mostly alphabetical but some types are grouped.
+
+**Warning**: Host names and the MNAME of a SOA records are NEVER terminated with
+a '.' in PowerDNS storage! If a trailing '.' is present it will inevitably cause
+problems, problems that may be hard to debug. Use [`pdnsutil check-zone`](authoritative/dnssec.md#pdnsutil)
+to validate your zone data.
+
+**Note**: Whenever the storage format is mentioned, this relates only to the way
+the record should be stored in one of the [generic SQL](authoritative/backend-generic-sql.md)
+backends. The other backends should use their *native* format.
+
+The PowerDNS Recursor can serve and store all record types, regardless of whether
+these are explicitly supported.
+
+## A
+The A record contains an IP address. It is stored as a decimal dotted quad
+string, for example: '203.0.113.210'.
+
+## AAAA
+The AAAA record contains an IPv6 address. An example: '2001:DB8:2000:bf0::1'.
+
+## AFSDB
+A specialised record type for the 'Andrew Filesystem'. Stored as: '\#subtype hostname',
+where subtype is a number.
+
+## ALIAS
+Since 4.0.0, the ALIAS pseudo-record type is supported to provide CNAME-like
+mechanisms on a zone's apex. See the [howto](authoritative/howtos.md#using-alias-records)
+for information on how to configure PowerDNS to serve records synthesized from
+ALIAS records.
+
+## CAA
+Since 4.0.0. The "Certification Authority Authorization" record, specified in
+[RFC 6844](https://tools.ietf.org/html/rfc6844), is used to specify Certificate
+Authorities that may issue certificates for a domain.
+
+## CERT
+Specialised record type for storing certificates, defined in
+[RFC 2538](http://tools.ietf.org/html/rfc2538).
+
+## CDNSKEY
+Since 4.0.0. The CDNSKEY ([Child DNSKEY](https://tools.ietf.org/html/rfc7344#section-3.2))
+type is supported.
+
+## CDS
+Since 4.0.0. The CDS ([Child DS](https://tools.ietf.org/html/rfc7344#section-3.1))
+type is supported.
+
+## CNAME
+The CNAME record specifies the canonical name of a record. It is stored plainly.
+Like all other records, it is not terminated by a dot. A sample might be
+'webserver-01.yourcompany.com'.
+
+## DNSKEY
+The DNSKEY DNSSEC record type is fully supported, as described in [RFC 4034](https://tools.ietf.org/html/rfc4034).
+Enabeling DNSSEC for domains can be done with [`pdnsutil`](authoritative/dnssec.md#pdnsutil "'pdnsutil' for PowerDNS command & control").
+
+## DNAME
+The DNAME record, as specified in [RFC 6672](http://tools.ietf.org/html/rfc6672)
+is supported. However, [`dname-processing`](authoritative/settings.md#dname-processing) has
+to be set to `yes` for PowerDNS to process these records.
+
+## DS
+The DS DNSSEC record type is fully supported, as described in [RFC 4034](https://tools.ietf.org/html/rfc4034).
+Enabeling DNSSEC for domains can be done with [`pdnsutil`](authoritative/dnssec.md#pdnsutil "'pdnsutil' for PowerDNS command & control").
+
+## HINFO
+Hardware Info record, used to specify CPU and operating system. Stored with a
+single space separating these two, example: 'i386 Linux'.
+
+## KEY
+The KEY record is fully supported. For its syntax, see [RFC 2535](http://tools.ietf.org/html/rfc2535).
+
+## LOC
+The LOC record is fully supported. For its syntax, see [RFC 1876](http://tools.ietf.org/html/rfc1876).
+A sample content would be: `51 56 0.123 N 5 54 0.000 E 4.00m 1.00m 10000.00m 10.00m`
+
+## MX
+The MX record specifies a mail exchanger host for a domain. Each mail exchanger
+also has a priority or preference. For example `10 mx.example.net`. In the generic
+SQL backends, the `10` should go in the 'priority field'.
+
+## NAPTR
+Naming Authority Pointer, [RFC 2915](http://tools.ietf.org/html/rfc2915). Stored as follows:
+
+```
+'100 50 "s" "z3950+I2L+I2C" "" _z3950._tcp.gatech.edu'.
+```
+
+The fields are: order, preference, flags, service, regex, replacement.
+Note that the replacement is not enclosed in quotes, and should not be. The
+replacement may be omitted, in which case it is empty. See also [RFC 2916](http://tools.ietf.org/html/rfc2916)
+for how to use NAPTR for ENUM (E.164) purposes.
+
+## NS
+Nameserver record. Specifies nameservers for a domain. Stored plainly:
+`ns1.powerdns.com`, as always without a terminating dot.
+
+## NSEC, NSEC3, NSEC3PARAM
+The NSEC, NSEC3 and NSEC3PARAM DNSSEC record type are fully supported, as described
+in [RFC 4034](http://tools.ietf.org/html/rfc4034). To enable DNSSEC, use
+[`pdnsutil`](authoritative/dnssec.md#pdnsutil "'pdnsutil' for PowerDNS command & control").
+
+## OPENPGPKEY
+Since 3.4.7. The OPENPGPKEY records, specified in [RFC TBD](https://tools.ietf.org/html/draft-ietf-dane-openpgpkey-06),
+are used to bind OpenPGP certificates to email addresses.
+
+## PTR
+Reverse pointer, used to specify the host name belonging to an IP or IPv6 address.
+Name is stored plainly: `www.powerdns.com`. As always, no terminating dot.
+
+## RP
+Responsible Person record, as described in [RFC 1183](http://tools.ietf.org/html/rfc1183).
+Stored with a single space between the mailbox name and the more-information pointer.
+Example: `peter.powerdns.com peter.people.powerdns.com`, to indicate that
+`peter@powerdns.com` is responsible and that more information about peter is
+available by querying the TXT record of peter.people.powerdns.com.
+
+## RRSIG
+The RRSIG DNSSEC record type is fully supported, as described in [RFC 4034](http://tools.ietf.org/html/rfc4034).
+To enable DNSSEC prcessing, use [pdnsutil](authoritative/dnssec.md#pdnsutil).
+
+## SOA
+The Start of Authority record is one of the most complex available. It specifies
+a lot about a domain: the name of the master nameserver ('the primary'), the
+hostmaster and a set of numbers indicating how the data in this domain expires
+and how often it needs to be checked. Further more, it contains a serial number
+which should rise on each change of the domain.
+
+The stored format is:
+
+```
+ primary hostmaster serial refresh retry expire default_ttl
+```
+
+Besides the primary and the hostmaster, all fields are numerical. PowerDNS has a set of default values:
+
+ * primary: [`default-soa-name`](authoritative/settings.md#default-soa-name) configuration option
+ * hostmaster: `hostmaster@domain-name`
+ * serial: 0
+ * refresh: 10800 (3 hours)
+ * retry: 3600 (1 hour)
+ * expire: 604800 (1 week)
+ * default\_ttl: 3600 (1 hour)
+
+The fields have complicated and sometimes controversial meanings. The 'serial'
+field is special. If left at 0, the default, PowerDNS will perform an internal list
+of the domain to determine highest change\_date field of all records within the
+zone, and use that as the zone serial number. This means that the serial number
+is always raised when changes are made to the zone, as long as the change\_date
+field is being set. Make sure to check whether your backend of choice supports
+Autoserial.
+
+## SPF
+SPF records can be used to store Sender Policy Framework details
+([RFC 4408](http://tools.ietf.org/html/rfc4408)).
+
+## SSHFP
+The SSHFP record type, used for storing Secure Shell (SSH) fingerprints, is
+fully supported. A sample from [RFC 4255](http://tools.ietf.org/html/rfc4255) is:
+`2 1 123456789abcdef67890123456789abcdef67890`.
+
+## SRV
+SRV records can be used to encode the location and port of services on a domain
+name. When encoding, the priority field is used to encode the priority. For example,
+`_ldap._tcp.dc._msdcs.conaxis.ch SRV 0 100 389 mars.conaxis.ch` would be encoded
+with `0` in the priority field and `100 389 mars.conaxis.ch` in the content field.
+
+## TKEY, TSIG
+The TKEY ([RFC 2930](http://tools.ietf.org/html/rfc2930)) and TSIG records
+([RFC 2845](http://tools.ietf.org/html/rfc2845), used for key-exchange and
+authenticated AXFRs, are supported. See the
+[Modes of operation](authoritative/modes-of-operation.md#tsig-shared-secret-authorization-and-authentication)
+and [DNS update](authoritative/dnsupdate.md) documentation for more information.
+
+## TLSA
+Since 3.0. The TLSA records, specified in [RFC 6698](http://tools.ietf.org/html/rfc6698),
+are used to bind SSL/TLS certificate to named hosts and ports.
+
+## TXT
+The TXT field can be used to attach textual data to a domain. Text is stored
+plainly, PowerDNS understands content not enclosed in quotes. However, all quotes
+characters (`"`) in the TXT content must be preceded with a backslash (`\`).:
+
+```
+"This \"is\" valid"
+```
+
+For a literal backslash in the TXT record, escape it:
+
+```
+"This is also \\ valid"
+```
+
+Unicode characters can be added in two ways, either by adding the character itself
+or the escaped variant to the content field. e.g. `"ç"` is equal to `"\195\167"`.
+
+When a TXT record is longer than 255 characters/bytes (excluding possible enclosing
+quotes), PowerDNS will cut up the content into 255 character/byte chunks for
+transmission to the client.
+
+## URI
+The URI record, specified in [RFC 7553](http://tools.ietf.org/html/rfc7553), is
+used to publish mappings from hostnames to URIs.
+
+## Other types
+The following, rarely used or obsolete record types, are also supported:
+
+* A6 ([RFC 2874](http://tools.ietf.org/html/rfc2874), obsolete)
+* DHCID ([RFC 4701](http://tools.ietf.org/html/rfc4701))
+* DLV ([RFC 4431](http://tools.ietf.org/html/rfc4431))
+* EUI48/EUI64 ([RFC 7043](http://tools.ietf.org/html/rfc7043))
+* IPSECKEY ([RFC 4025](http://tools.ietf.org/html/rfc4024))
+* KEY ([RFC 2535](http://tools.ietf.org/html/rfc2535), obsolete)
+* KX ([RFC 2230](http://tools.ietf.org/html/rfc2230))
+* MAILA ([RFC 1035](http://tools.ietf.org/html/rfc1035))
+* MAILB ([RFC 1035](http://tools.ietf.org/html/rfc1035))
+* MINFO ([RFC 1035](http://tools.ietf.org/html/rfc1035))
+* MR ([RFC 1035](http://tools.ietf.org/html/rfc1035))
+* RKEY ([draft-reid-dnsext-rkey-00.txt](https://tools.ietf.org/html/draft-reid-dnsext-rkey-00))
+* SIG ([RFC 2535](http://tools.ietf.org/html/rfc2535), obsolete)
+* WKS ([RFC 1035](http://tools.ietf.org/html/rfc1035))
--- /dev/null
+.TH "NPROXY" "1" "April 2016" "" ""
+.SH NAME
+.PP
+\f[B]nproxy\f[] \- DNS notification proxy
+.SH SYNOPSIS
+.PP
+nproxy \-\-powerdns\-address \f[I]ADDRESS\f[] [\f[I]OPTION\f[]]...
+\f[I]ADDRESS\f[]...
+.SH DESCRIPTION
+.PP
+\f[B]nproxy\f[] is a simple daemon that reads DNS NOTIFY queries on one
+address and forwards them to an \[aq]inner\[aq] nameserver that will
+process the notification.
+.PP
+Its usecase is e.g.
+a private authoritative server inside a NAT or firewalled LAN where
+\f[B]nproxy\f[] is deployed in the DMZ.
+.PP
+The PowerDNS Authoritative Server has the trusted\-notification\-proxy
+option that should be set to the address set with
+\f[I]\-\-origin\-address\f[] to accept these proxied notifications.
+.PP
+\f[B]nproxy\f[] also has a health\-check option built in.
+A query for \[aq]pdns.nproxy.\[aq] with QType \[aq]TXT\[aq] will be
+responded to with an answer of "OK" (inside the TXT record.
+When the query is for an A\-record, \[aq]1.2.3.4.\[aq] is returned.
+.SH OPTIONS
+.TP
+.B \-\-powerdns\-address \f[I]ADDRESS\f[]
+IP address of the PowerDNS server to forward the notifications to.
+.RS
+.RE
+.TP
+.B \-\-chroot \f[I]PATH\f[]
+chroot to \f[I]PATH\f[] for additional security.
+.RS
+.RE
+.TP
+.B \-\-setuid \f[I]UID\f[]
+setuid to this numerical \f[I]UID\f[].
+.RS
+.RE
+.TP
+.B \-\-setgid \f[I]GID\f[]
+setgid to this numerical \f[I]GID\f[].
+.RS
+.RE
+.TP
+.B \-\-origin\-address \f[I]ADDRESS\f[]
+Set the source of the notifications sent to PowerDNS to
+\f[I]ADDRESS\f[].
+By default, the best matching address (kernel\[aq]s choice) is used.
+.RS
+.RE
+.TP
+.B \-\-listen\-address \f[I]ADDRESS\f[]
+IP addresses to listen on.
+.RS
+.RE
+.TP
+.B \-\-listen\-port \f[I]PORT\f[]
+Source port to listen on, 53 by default.
+.RS
+.RE
+.TP
+.B \-d,\-\-daemon \f[I]ARG\f[]
+Set \f[I]ARG\f[] to 0 to disable running in the background.
+.RS
+.RE
+.TP
+.B \-v,\-\-verbose
+Be verbose
+.RS
+.RE
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "NSEC3DIG" "1" "April 2015" "" ""
+.SH NAME
+.PP
+\f[B]nsec3dig\f[] \- Show and validate NSEC3 proofs
+.SH SYNOPSIS
+.PP
+\f[B]nsec3dig\f[] \f[I]IPADDRESS\f[] \f[I]PORT\f[] \f[I]QNAME\f[]
+\f[I]QTYPE\f[] [recurse]
+.SH DESCRIPTION
+.PP
+\f[B]nsec3dig\f[] sends a query for \f[I]QNAME\f[] and \f[I]QTYPE\f[] to
+the nameserver at \f[I]IPADDRESS\f[] on port \f[I]PORT\f[] and prints
+whether and why the NSEC3 proofs are correct.
+Using the \[aq]recurse\[aq] option sets the Recursion Desired (RD) bit
+in the query.
+.SH EXAMPLE
+.PP
+\f[C]nsec3dig\ 8.8.8.8\ 53\ doesntexist.isoc.nl\ TXT\ recurse\f[]
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "PDNS_CONTROL" "1" "December 2002" "" ""
+.SH NAME
+.PP
+\f[B]pdns_control\f[] \- Control the PowerDNS nameserver
+.SH SYNOPSIS
+.PP
+\f[B]pdns_control\f[] [\f[I]OPTION\f[]]...
+\f[I]COMMAND\f[]
+.SH DESCRIPTION
+.PP
+\f[B]pdns_control\f[] is used to send commands to a running PowerDNS
+nameserver.
+.SH OPTIONS
+.TP
+.B \-\-help
+Show summary of options.
+.RS
+.RE
+.TP
+.B \-\-chroot=\f[I]DIR\f[]
+Directory where PowerDNS is chrooted.
+.RS
+.RE
+.TP
+.B \-\-config\-dir=\f[I]DIR\f[]
+Location of configuration directory (pdns.conf).
+.RS
+.RE
+.TP
+.B \-\-config\-name=\f[I]NAME\f[]
+Name of this virtual configuration \- will rename the binary image.
+.RS
+.RE
+.TP
+.B \-\-remote\-address=\f[I]ADDRESS\f[]
+Remote address to query.
+.RS
+.RE
+.TP
+.B \-\-remote\-port=\f[I]PORT\f[]
+Remote port to query.
+.RS
+.RE
+.TP
+.B \-\-secret=\f[I]SECRET\f[]
+Secret needed to connect to remote PowerDNS.
+.RS
+.RE
+.TP
+.B \-\-socket\-dir=\f[I]DIR\f[]
+Where the controlsocket lives.
+.RS
+.RE
+.SH COMMANDS
+.TP
+.B bind\-add\-zone \f[I]DOMAIN\f[] \f[I]FILENAME\f[]
+When using the bindbackend, add a zone.
+This zone is added in\-memory and served immediately.
+Note that this does not add the zone to the bind\-config file.
+\f[I]FILENAME\f[] must be an absolute path.
+.RS
+.RE
+.TP
+.B bind\-domain\-status [\f[I]DOMAIN\f[]...]
+When using the bindbackend, list status of all domains.
+Optionally, append \f[I]DOMAIN\f[]s to get the status of specific zones.
+.RS
+.RE
+.TP
+.B bind\-list\-rejects
+When using the bindbackend, get a list of all rejected domains.
+.RS
+.RE
+.TP
+.B bind\-reload\-now \f[I]DOMAIN\f[] [\f[I]DOMAIN\f[]...]
+When using the bindbackend, immediately reload \f[I]DOMAIN\f[] from
+disk.
+.RS
+.RE
+.TP
+.B ccounts
+Show the content of the cache.
+.RS
+.RE
+.TP
+.B current\-config
+Show the currently running configuration.
+The output has the same format as \f[C]pdns_server\ \-\-config\f[].
+You\[aq]ll notice that all the are uncommented.
+This is because PowerDNS simply has values, and the default isn\[aq]t
+known at runtime.
+.RS
+.RE
+.TP
+.B cycle
+Restart the nameserver so it reloads its configuration.
+Only works when the server is running in guardian mode.
+.RS
+.RE
+.TP
+.B list
+Dump all variables and their values in a comma separated list,
+equivalent to \f[B]show *\f[].
+.RS
+.RE
+.TP
+.B list\-zones [master,slave,native]
+Show a list of zones, optionally filter on the type of zones to show.
+.RS
+.RE
+.TP
+.B notify \f[I]DOMAIN\f[]
+Adds \f[I]DOMAIN\f[] to the notification list, causing PowerDNS to send
+out notifications to the nameservers of a domain.
+Can be used if a slave missed previous notifications or is generally
+hard of hearing.
+.RS
+.RE
+.TP
+.B notify\-host \f[I]DOMAIN\f[] \f[I]ADDRESS\f[]
+Same as above but with operator specified IP \f[I]ADDRESS\f[] as
+destination, to be used if you know better than PowerDNS.
+.RS
+.RE
+.TP
+.B ping, rping
+Check if the server is still alive.
+Will return \[aq]PONG\[aq] when it is.
+\f[B]ping\f[] works when running inside a guardian, whereas
+\f[B]rping\f[] works when running without a guardian.
+.RS
+.RE
+.TP
+.B purge [\f[I]RECORD\f[]]
+Purge entries from the cache.
+If \f[I]RECORD\f[] ends with a dollar ($) all entries that end with that
+name are removed.
+If no record is specified the entire cache is purged.
+.RS
+.RE
+.TP
+.B qtypes
+Get a count of queries per qtype on standard out.
+.RS
+.RE
+.TP
+.B quit
+Tell a running pdns_server to quit.
+.RS
+.RE
+.TP
+.B rediscover
+Instructs backends that new domains may have appeared in the database,
+or, in the case of the Bind backend, in named.conf.
+.RS
+.RE
+.TP
+.B reload
+Instruct the server to reload all its zones, this will not add new
+zones.
+.RS
+.RE
+.TP
+.B remotes
+Get the top number of remote addresses (clients).
+.RS
+.RE
+.TP
+.B respsizes
+Get a histogram of the response sizes.
+.RS
+.RE
+.TP
+.B retrieve \f[I]DOMAIN\f[]
+Retrieve slave \f[I]DOMAIN\f[] from its master.
+Done nearly immediately.
+.RS
+.RE
+.TP
+.B set \f[I]VARIABLE\f[] \f[I]VALUE\f[]
+Set the configuration parameter \f[I]VARIABLE\f[] to \f[I]VALUE\f[].
+Currently only the query\-logging can be set.
+.RS
+.RE
+.TP
+.B show \f[I]VARIABLE\f[]
+Show a single statistic, as present in the output of the list command.
+.RS
+.RE
+.TP
+.B status
+Show usage statistics.
+This only works if the server is running in guardian mode.
+.RS
+.RE
+.TP
+.B token\-login \f[I]MODULE\f[] \f[I]SLOT\f[] \f[I]PIN\f[]
+Log on to a PKCS#11 slot.
+You only need to login once per slot, even if you have multiple keys on
+single slot.
+Only available if PowerDNS was compiled with PKCS#11 support.
+.RS
+.RE
+.TP
+.B uptime
+Show the uptime of the running server.
+.RS
+.RE
+.TP
+.B version
+Print the version of the running pdns daemon.
+.RS
+.RE
+.SH SEE ALSO
+.PP
+pdns_server(1)
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "PDNS_NOTIFY" "1" "April 2016" "" ""
+.SH NAME
+.PP
+\f[B]pdns_notify\f[] \- A simple DNS NOTIFY sender
+.SH SYNOPSIS
+.PP
+\f[B]pdns_notify\f[] \f[I]IP_ADDRESS\f[][:\f[I]PORT\f[]] \f[I]DOMAIN\f[]
+.SH DESCRIPTION
+.PP
+\f[B]pdns_notify\f[] sends a DNS NOTIFY message to \f[I]IP_ADDRESS\f[],
+by default on port 53, for \f[I]DOMAIN\f[] and prints the remote
+nameserver\[aq]s response.
+.SH OPTIONS
+.PP
+None
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "PDNS_SERVER" "1" "December 2012" "" ""
+.SH NAME
+.PP
+\f[B]pdns_server\f[] \- The PowerDNS Authoritative Namserver
+.SH SYNOPSIS
+.PP
+\f[B]pdns_server\f[] [\f[I]OPTION\f[]]
+.SH DESCRIPTION
+.PP
+The PowerDNS Authoritative Server is a versatile nameserver which
+supports a large number of backends.
+These backends can either be plain zone files or be more dynamic in
+nature.
+Please see the online documentation for more information.
+.SH OPTIONS
+.PP
+See the online documentation for all options
+.TP
+.B \-\-daemon={\f[B]yes\f[],\f[B]no\f[]}
+Indicate if the server should run in the background as a real daemon, or
+in the foreground.
+.RS
+.RE
+.TP
+.B \-\-guardian={\f[B]yes\f[],\f[B]no\f[]}
+Run \f[B]pdns_server\f[] inside a guardian.
+This guardian monitors the performance of the inner \f[B]pdns_server\f[]
+instance.
+It is also this guardian that \f[B]pdns_control\f[](8) talks to.
+.RS
+.RE
+.TP
+.B \-\-control\-console
+Run the server in a special monitor mode.
+This enables detailed logging and exposes the raw control socket.
+.RS
+.RE
+.TP
+.B \-\-loglevel=\f[I]LEVEL\f[]
+Set the logging level.
+.RS
+.RE
+.PP
+\-\-help To view more options that are available use this program.
+.SH SEE ALSO
+.PP
+pdns_control(1), pdnsutil(1), http://doc.powerdns.com/md/authoritative/
+.SH AUTHORS
+PowerDNS.COM BV.
--- /dev/null
+.TH "PDNSUTIL" "1" "November 2011" "PowerDNS DNSSEC command and control" ""
+.SH NAME
+.PP
+pdnsutil \- PowerDNS dnssec command and control
+.SH SYNOPSIS
+.PP
+pdnsutil [OPTION]...
+\f[I]COMMAND\f[]
+.SH DESCRIPTION
+.PP
+\f[B]pdnsutil\f[] (formerly pdnssec) is a powerful command that is the
+operator\-friendly gateway into DNSSEC and zone management for PowerDNS.
+Behind the scenes, \f[B]pdnsutil\f[] manipulates a PowerDNS backend
+database, which also means that for many databases, \f[B]pdnsutil\f[]
+can be run remotely, and can configure key material on different
+servers.
+.SH OPTIONS
+.TP
+.B \-h | \-help
+Show summary of options
+.RS
+.RE
+.TP
+.B \-v | \-\-verbose
+Be more verbose.
+.RS
+.RE
+.TP
+.B \-\-force
+force an action
+.RS
+.RE
+.TP
+.B \-\-config\-name \f[I]NAME\f[]
+Virtual configuration name
+.RS
+.RE
+.TP
+.B \-\-config\-dir \f[I]DIR\f[]
+Location of pdns.conf.
+Default is /etc/powerdns.
+.RS
+.RE
+.SH COMMANDS
+.PP
+There are many available commands, this section splits them up into
+their respective uses
+.SS DNSSEC RELATED COMMANDS
+.PP
+Several commands manipulate the DNSSEC keys and options for zones.
+Some of these commands require an \f[I]ALGORITHM\f[] to be set.
+The following algorithms are supported:
+.IP \[bu] 2
+rsasha1
+.IP \[bu] 2
+rsasha256
+.IP \[bu] 2
+rsasha512
+.IP \[bu] 2
+gost
+.IP \[bu] 2
+ecdsa256
+.IP \[bu] 2
+ecdsa384
+.TP
+.B activate\-zone\-key \f[I]ZONE\f[] \f[I]KEY\-ID\f[]
+Activate a key with id \f[I]KEY\-ID\f[] within a zone called
+\f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B add\-zone\-key \f[I]ZONE\f[] {\f[B]KSK\f[],\f[B]ZSK\f[]} [\f[B]active\f[],\f[B]inactive\f[]] \f[I]KEYBITS\f[] \f[I]ALGORITHM\f[]
+Create a new key for zone \f[I]ZONE\f[], and make it a KSK or a ZSK,
+with the specified algorithm.
+The key is inactive by default, set it to \f[B]active\f[] to immediately
+use it to sign \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B create\-bind\-db \f[I]FILE\f[]
+Create DNSSEC database (sqlite3) at \f[I]FILE\f[] for the BIND backend.
+Remember to set \f[C]bind\-dnssec\-db=*FILE*\f[] in your
+\f[C]pdns.conf\f[].
+.RS
+.RE
+.TP
+.B deactivate\-zone\-key \f[I]ZONE\f[] \f[I]KEY\-ID\f[]
+Deactivate a key with id KEY\-ID within a zone called \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B disable\-dnssec \f[I]ZONE\f[]
+Deactivate all keys and unset PRESIGNED in \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B export\-zone\-dnskey \f[I]ZONE\f[] \f[I]KEY\-ID\f[]
+Export to standard output DNSKEY and DS of key with key id
+\f[I]KEY\-ID\f[] within zone called \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B export\-zone\-key \f[I]ZONE\f[] \f[I]KEY\-ID\f[]
+Export to standard output full (private) key with key id
+\f[I]KEY\-ID\f[] within zone called \f[I]ZONE\f[].
+The format used is compatible with BIND and NSD/LDNS.
+.RS
+.RE
+.TP
+.B generate\-zone\-key {\f[B]KSK\f[],\f[B]ZSK\f[]} [\f[I]ALGORITHM\f[]] [\f[I]KEYBITS\f[]]
+Generate a ZSK or KSK to stdout with specified algorithm and bits and
+print it on STDOUT.
+If \f[I]ALGORITHM\f[] is not set, RSASHA512 is used.
+If \f[I]KEYBITS\f[] is not set, an appropriate keysize is selected for
+\f[I]ALGORITHM\f[].
+.RS
+.RE
+.TP
+.B import\-zone\-key \f[I]ZONE\f[] \f[I]FILE\f[] {\f[B]KSK\f[],\f[B]ZSK\f[]}
+Import from \f[I]FILE\f[] a full (private) key for zone called
+\f[I]ZONE\f[].
+The format used is compatible with BIND and NSD/LDNS.
+\f[B]KSK\f[] or \f[B]ZSK\f[] specifies the flags this key should have on
+import.
+.RS
+.RE
+.TP
+.B remove\-zone\-key \f[I]ZONE\f[] \f[I]KEY\-ID\f[]
+Remove a key with id \f[I]KEY\-ID\f[] from a zone called \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B set\-nsec3 \f[I]ZONE\f[] \[aq]\f[I]HASH\-ALGORITHM\f[] \f[I]FLAGS\f[] \f[I]ITERATIONS\f[] \f[I]SALT\f[]\[aq] [\f[B]narrow\f[]]
+Sets NSEC3 parameters for this zone.
+The quoted parameters are 4 values that are used for the the NSEC3PARAM
+record and decide how NSEC3 records are created.
+The NSEC3 parameters must be quoted on the command line.
+\f[I]HASH\-ALGORITHM\f[] must be 1 (SHA\-1). Setting \f[I]FLAGS\f[] to 1
+enables NSEC3 opt\-out operation.
+Only do this if you know you need it. For \f[I]ITERATIONS\f[], please
+consult RFC 5155, section 10.3.
+And be aware that a high number might overload validating resolvers. The
+\f[I]SALT\f[] is a hexadecimal string encoding the bits for the salt.
+Setting \f[B]narrow\f[] will make PowerDNS send out "white lies" about
+the next secure record.
+Instead of looking it up in the database, it will send out the hash + 1
+as the next secure record.
+ A sample commandline is: "pdnsutil set\-nsec3 powerdnssec.org \[aq]1 1
+1 ab\[aq] narrow". \f[B]WARNING\f[]: If running in RSASHA1 mode
+(algorithm 5 or 7), switching from NSEC to NSEC3 will require a DS
+update in the parent zone.
+.RS
+.RE
+.TP
+.B unset\-nsec3 \f[I]ZONE\f[]
+Converts \f[I]ZONE\f[] to NSEC operations.
+\f[B]WARNING\f[]: If running in RSASHA1 mode (algorithm 5 or 7),
+switching from NSEC to NSEC3 will require a DS update at the parent
+zone!
+.RS
+.RE
+.TP
+.B set\-publish\-cds \f[I]ZONE\f[] [\f[I]DIGESTALGOS\f[]]
+Set \f[I]ZONE\f[] to respond to queries for its CDS records.
+the optional argument \f[I]DIGESTALGOS\f[] should be a comma\-separated
+list of DS algorithms to use.
+By default, this is 1,2 (SHA1 and SHA2\-256).
+.RS
+.RE
+.TP
+.B set\-publish\-cdnskey \f[I]ZONE\f[]
+Set \f[I]ZONE\f[] to publish CDNSKEY records.
+.RS
+.RE
+.TP
+.B unset\-publish\-cds \f[I]ZONE\f[]
+Set \f[I]ZONE\f[] to stop responding to queries for its CDS records.
+.RS
+.RE
+.TP
+.B unset\-publish\-cdnskey \f[I]ZONE\f[]
+Set \f[I]ZONE\f[] to stop publishing CDNSKEY records.
+.RS
+.RE
+.SS TSIG RELATED COMMANDS
+.PP
+These commands manipulate TSIG key information in the database.
+Some commands require an \f[I]ALGORITHM\f[], the following are
+available:
+.IP \[bu] 2
+hmac\-md5
+.IP \[bu] 2
+hmac\-sha1
+.IP \[bu] 2
+hmac\-sha224
+.IP \[bu] 2
+hmac\-sha256
+.IP \[bu] 2
+hmac\-sha384
+.IP \[bu] 2
+hmac\-sha512
+.TP
+.B activate\-tsig\-key \f[I]ZONE\f[] \f[I]NAME\f[] {\f[B]master\f[],\f[B]slave\f[]}
+Enable TSIG authenticated AXFR using the key \f[I]NAME\f[] for zone
+\f[I]ZONE\f[].
+This sets the \f[C]TSIG\-ALLOW\-AXFR\f[] (master) or
+\f[C]AXFR\-MASTER\-TSIG\f[] (slave) zone metadata.
+.RS
+.RE
+.TP
+.B deactivate\-tsig\-key \f[I]ZONE\f[] \f[I]NAME\f[] {\f[B]master\f[],\f[B]slave\f[]}
+Disable TSIG authenticated AXFR using the key \f[I]NAME\f[] for zone
+\f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B delete\-tsig\-key \f[I]NAME\f[]
+Delete the TSIG key \f[I]NAME\f[].
+Warning, this does not deactivate said key.
+.RS
+.RE
+.TP
+.B generate\-tsig\-key \f[I]NAME\f[] \f[I]ALGORITHM\f[]
+Generate new TSIG key with name \f[I]NAME\f[] and the specified
+algorithm.
+.RS
+.RE
+.SS ZONE MANIPULATION COMMANDS
+.TP
+.B create\-zone \f[I]ZONE\f[]
+Create an empty zone named \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B check\-all\-zones
+Check all zones for correctness.
+.RS
+.RE
+.TP
+.B check\-zone \f[I]ZONE\f[]
+Check zone \f[I]ZONE\f[] for correctness.
+.RS
+.RE
+.TP
+.B clear\-zone \f[I]ZONE\f[]
+Clear the records in zone \f[I]ZONE\f[], but leave actual domain and
+settings unchanged
+.RS
+.RE
+.TP
+.B delete\-zone \f[I]ZONE\f[]:
+Delete the zone named \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B edit\-zone \f[I]ZONE\f[]
+Opens \f[I]ZONE\f[] in zonefile format (regardless of backend it was
+loaded from) in the editor set in the environment variable
+\f[B]EDITOR\f[].
+if \f[B]EDITOR\f[] is empty, \f[I]pdnsutil\f[] falls back to using
+\f[I]editor\f[].
+.RS
+.RE
+.TP
+.B get\-meta \f[I]ZONE\f[] [\f[I]ATTRIBUTE\f[]]...
+Get zone metadata.
+If no \f[I]ATTRIBUTE\f[] given, lists all known.
+.RS
+.RE
+.TP
+.B hash\-zone\-record \f[I]ZONE\f[] \f[I]RNAME\f[]
+This convenience command hashes the name \f[I]RNAME\f[] according to the
+NSEC3 settings of \f[I]ZONE\f[].
+Refuses to hash for zones with no NSEC3 settings.
+.RS
+.RE
+.TP
+.B list\-keys [\f[I]ZONE\f[]]
+List DNSSEC information for all keys or for \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B list\-all\-zones:
+List all zone names.
+.RS
+.RE
+.TP
+.B list\-zone \f[I]ZONE\f[]
+Show all records for \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B load\-zone \f[I]ZONE\f[] \f[I]FILE\f[]
+Load records for \f[I]ZONE\f[] from \f[I]FILE\f[].
+If \f[I]ZONE\f[] already exists, all records are overwritten, this
+operation is atomic.
+If \f[I]ZONE\f[] doesn\[aq]t exist, it is created.
+.RS
+.RE
+.TP
+.B rectify\-zone \f[I]ZONE\f[]
+Calculates the \[aq]ordername\[aq] and \[aq]auth\[aq] fields for a zone
+called \f[I]ZONE\f[] so they comply with DNSSEC settings.
+Can be used to fix up migrated data.
+Can always safely be run, it does no harm.
+.RS
+.RE
+.TP
+.B secure\-zone \f[I]ZONE\f[]
+Configures a zone called \f[I]ZONE\f[] with reasonable DNSSEC settings.
+You should manually run \[aq]pdnsutil rectify\-zone\[aq] afterwards.
+.RS
+.RE
+.TP
+.B set\-meta \f[I]ZONE\f[] \f[I]ATTRIBUTE\f[] [\f[I]VALUE\f[]]
+Set domainmetadata \f[I]ATTRIBUTE\f[] for \f[I]ZONE\f[] to
+\f[I]VALUE\f[].
+An empty value clears it.
+.RS
+.RE
+.TP
+.B set\-presigned \f[I]ZONE\f[]
+Switches \f[I]ZONE\f[] to presigned operation, utilizing in\-zone
+RRSIGs.
+.RS
+.RE
+.TP
+.B show\-zone \f[I]ZONE\f[]
+Shows all DNSSEC related settings of a zone called \f[I]ZONE\f[].
+.RS
+.RE
+.TP
+.B test\-schema \f[I]ZONE\f[]
+Test database schema, this creates the zone \f[I]ZONE\f[]
+.RS
+.RE
+.TP
+.B unset\-presigned \f[I]ZONE\f[]
+Disables presigned operation for \f[I]ZONE\f[].
+.RS
+.RE
+.SS DEBUGGING TOOLS
+.TP
+.B backend\-cmd \f[I]BACKEND\f[] \f[I]CMD\f[] [\f[I]CMD..\f[]]
+Send a text command to a backend for execution.
+GSQL backends will take SQL commands, other backends may take different
+things.
+Be careful!
+.RS
+.RE
+.SH SEE ALSO
+.PP
+pdns_server (1), pdns_control (1)
+.SH AUTHORS
+Matthijs Möhlmann <matthijs@cacholong.nl>.
--- /dev/null
+.TH "SAXFR" "1" "April 2015" "" ""
+.SH NAME
+.PP
+\f[B]saxfr\f[] \- Perform AXFRs and show information about it
+.SH SYNOPSIS
+.PP
+\f[B]saxfr\f[] \f[I]IPADDRESS\f[] \f[I]PORT\f[] \f[I]ZONE\f[]
+[\f[I]OPTIONS\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]saxfr\f[] does a zone\-transfer (AXFR) of \f[I]ZONE\f[] from the
+nameserver at \f[I]IPADDRESS\f[] on port \f[I]PORT\f[] and displays the
+transferred zone with NSEC3 information truncated.
+See below how to show this information.
+.SH OPTIONS
+.TP
+.B showdetails
+Show all the data in the NSEC3 and DNSKEY RDATA.
+.RS
+.RE
+.TP
+.B showflags
+Show the NSEC3 flags in the RDATA.
+.RS
+.RE
+.TP
+.B unhash
+Unhash the NSEC3 names to the normal names.
+.RS
+.RE
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "SDIG" "1" "September 2015" "" ""
+.SH NAME
+.PP
+\f[B]sdig\f[] \- Perform a DNS query and show the results
+.SH SYNOPSIS
+.PP
+\f[B]sdig\f[] \f[I]IPADDRESS\f[] \f[I]PORT\f[] \f[I]QNAME\f[]
+\f[I]QTYPE\f[] [\f[I]OPTIONS\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]sdig\f[] sends a DNS query to \f[I]IPADDRESS\f[] on port
+\f[I]PORT\f[] and displays the answer in a formatted way.
+.SH OPTIONS
+.PP
+These options can be added to the commandline in any order.
+dnssec : Set the DO bit to request DNSSEC information.
+.TP
+.B hidesoadetails
+Don\[aq]t show the SOA serial in the response.
+.RS
+.RE
+.TP
+.B recurse
+Set the RD bit in the question.
+.RS
+.RE
+.TP
+.B showflags
+Show the NSEC3 flags in the response.
+.RS
+.RE
+.TP
+.B tcp
+Use TCP instead of UDP to send the query.
+.RS
+.RE
+.TP
+.B ednssubnet \f[I]SUBNET\f[]
+Send \f[I]SUBNET\f[] in the edns\-client\-subnet option.
+If this option is not set, no edns\-client\-subnet option is set in the
+query.
+.RS
+.RE
+.SH AUTHORS
+PowerDNS.com BV.
--- /dev/null
+.TH "ZONE2JSON" "1" "January 2016" "" ""
+.SH NAME
+.PP
+\f[B]zone2json\f[] \- convert BIND zones to JSON
+.SH SYNOPSIS
+.PP
+\f[B]zone2json\f[]
+{\f[B]\-\-named\-conf=\f[]\f[I]PATH\f[],\f[B]\-\-zone\-file=\f[]\f[I]PATH\f[]
+[\f[B]\-\-zone\-name=\f[]\f[I]NAME\f[]]} [\f[I]OPTIONS\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]zone2json\f[] parses Bind named.conf files and zonefiles and
+outputs JSON on standard out, which can then be fed to the PowerDNS API.
+.PP
+\f[B]zone2json\f[] understands the Bind master file extension
+\f[C]$GENERATE\f[] and will also honour \f[C]$ORIGIN\f[] and
+\f[C]$TTL\f[].
+.SH OPTIONS
+.SS INPUT OPTIONS
+.TP
+.B \-\-named\-conf=\f[I]PATH\f[]
+Read \f[I]PATH\f[] to get the bind configuration
+.RS
+.RE
+.TP
+.B \-\-zone=\f[I]PATH\f[]
+Parse only the zone file at \f[I]PATH\f[] Conflicts with
+\f[B]\-\-named\-conf\f[] parameter.
+.RS
+.RE
+.TP
+.B \-\-zone\-name=\f[I]NAME\f[]
+When parsing a single zone without $ORIGIN statement, set \f[I]ZONE\f[]
+as the zone name.
+.RS
+.RE
+.SS OTHER OPTIONS
+.TP
+.B \-\-help
+List all options
+.RS
+.RE
+.TP
+.B \-\-on\-error\-resume\-next
+Ignore missing zone files during parsing.
+Dangerous.
+.RS
+.RE
+.TP
+.B \-\-verbose
+Be verbose during conversion.
+.RS
+.RE
+.SH SEE ALSO
+.PP
+pdns_server(1)
+.SH AUTHORS
+PowerDNS.
--- /dev/null
+.TH "ZONE2LDAP" "1" "November 2004" "" ""
+.SH NAME
+.PP
+\f[B]zone2ldap\f[] \- convert zonefiles to ldif
+.SH SYNOPSIS
+.PP
+\f[B]zone2ldap\f[]
+{\f[B]\-\-named\-conf=\f[]\f[I]PATH\f[],\f[B]\-\-zone\-file=\f[]\f[I]PATH\f[]
+\f[B]\-\-zone\-name=\f[]\f[I]NAME\f[]} [\f[I]OPTION\f[]]...
+.SH DESCRIPTION
+.PP
+\f[B]zone2ldap\f[] is a program that converts bind zonefiles to ldif
+format which can inserted to an LDAP server.
+.SH OPTIONS
+.TP
+.B \-\-help
+Show summary of options.
+.RS
+.RE
+.TP
+.B \-\-basedn=\f[I]DN\f[]
+Base DN to store objects below
+.RS
+.RE
+.TP
+.B \-\-dnsttl
+Add dnsttl attribute to every entry
+.RS
+.RE
+.TP
+.B \-\-layout={\f[B]simple,tree\f[]}
+How to arrange entries in the directory (simple or as tree)
+.RS
+.RE
+.TP
+.B \-\-named\-conf=\f[I]PATH\f[]
+Path to a Bind 8 named.conf to parse
+.RS
+.RE
+.TP
+.B \-\-resume
+Continue after errors
+.RS
+.RE
+.TP
+.B \-\-verbose
+verbose comments on operation
+.RS
+.RE
+.TP
+.B \-\-zone\-file=\f[I]PATH\f[]
+Zone file to parse
+.RS
+.RE
+.TP
+.B \-\-zone\-name=\f[I]NAME\f[]
+Specify a zone name if zone is set
+.RS
+.RE
+.SH SEE ALSO
+.PP
+pdns_server(1)
+.SH AUTHORS
+Matthijs Möhlmann <matthijs@cacholong.nl>.
--- /dev/null
+.TH "ZONE2SQL" "1" "December 2002" "" ""
+.SH NAME
+.PP
+\f[B]zone2sql\f[] \- convert BIND zones to SQL
+.SH SYNOPSIS
+.PP
+\f[B]zone2sql\f[]
+{\f[B]\-\-named\-conf=\f[]\f[I]PATH\f[],\f[B]\-\-zone\-file=\f[]\f[I]PATH\f[]
+[\f[B]\-\-zone\-name=\f[]\f[I]NAME\f[]]} [\f[I]OPTIONS\f[]]
+.SH DESCRIPTION
+.PP
+\f[B]zone2sql\f[] parses Bind named.conf files and zonefiles and outputs
+SQL on standard out, which can then be fed to your database.
+.PP
+\f[B]zone2sql\f[] understands the Bind master file extension
+\f[C]$GENERATE\f[] and will also honour \f[C]$ORIGIN\f[] and
+\f[C]$TTL\f[].
+.PP
+For backends supporting slave operation there is also an option to keep
+slave zones as slaves, and not convert them to native operation.
+.PP
+\f[B]zone2sql\f[] can generate SQL for the Generic MySQL, Generic
+PostgreSQL, Generic SQLite3 and Generic Oracle backends.
+.SH OPTIONS
+.SS INPUT OPTIONS
+.TP
+.B \-\-named\-conf=\f[I]PATH\f[]
+Read \f[I]PATH\f[] to get the bind configuration
+.RS
+.RE
+.TP
+.B \-\-zone=\f[I]PATH\f[]
+Parse only the zone file at \f[I]PATH\f[] Conflicts with
+\f[B]\-\-named\-conf\f[] parameter.
+.RS
+.RE
+.TP
+.B \-\-zone\-name=\f[I]NAME\f[]
+When parsing a single zone without $ORIGIN statement, set \f[I]ZONE\f[]
+as the zone name.
+.RS
+.RE
+.SS BACKENDS
+.TP
+.B \-\-gmysql
+Output in format suitable for the default configuration of the Generic
+MySQL backend.
+.RS
+.RE
+.TP
+.B \-\-gpgsql
+Output in format suitable for the default configuration of the Generic
+PostgreSQL backend.
+.RS
+.RE
+.TP
+.B \-\-gsqlite
+Output in format suitable for the default configuration of the Generic
+SQLite3 backend.
+.RS
+.RE
+.TP
+.B \-\-goracle
+Output in format suitable for the default configuration of the Generic
+Oracle backend.
+.RS
+.RE
+.TP
+.B \-\-mydns
+Output in a format suitable for the MyDNS backend.
+.RS
+.RE
+.TP
+.B \-\-oracle
+Output in format suitable for the default configuration of the Oracle
+backend.
+.RS
+.RE
+.SS OUTPUT OPTIONS
+.TP
+.B \-\-json\-comments
+Parse JSON in zonefile comments to set the \[aq]disabled\[aq] and
+\[aq]comment\[aq] fields in the database.
+See \f[I]JSON COMMENTS\f[] for more information.
+.RS
+.RE
+.TP
+.B \-\-transactions
+If the target SQL backend supports transactions, wrap every domain into
+a transaction for integrity and possibly higher speed.
+.RS
+.RE
+.SS OTHER OPTIONS
+.TP
+.B \-\-filter\-duplicate\-soa
+If there\[aq]s more than one SOA record in the zone (possibly because it
+was AXFR\[aq]d), ignore it.
+If this option is not set, all SOA records in the zone are emitted.
+.RS
+.RE
+.TP
+.B \-\-help
+List all options
+.RS
+.RE
+.TP
+.B \-\-on\-error\-resume\-next
+Ignore missing zone files during parsing.
+Dangerous.
+.RS
+.RE
+.TP
+.B \-\-slave
+Maintain slave status of zones listed in named.conf as being slaves.
+The default behaviour is to convert all zones to native operation.
+.RS
+.RE
+.TP
+.B \-\-verbose
+Be verbose during conversion.
+.RS
+.RE
+.SH JSON COMMENTS
+.PP
+The Generic SQL backends have the \[aq]comment\[aq] and
+\[aq]disabled\[aq] fields in the \[aq]records\[aq] table.
+The \[aq]comment\[aq] field contains a comment for this record (if any)
+and the \[aq]disabled\[aq] field tells PowerDNS if the record can be
+served to clients.
+.PP
+When a zonefile contains a comment like
+\f[C];\ json={"comment":\ "Something",\ "disabled":\ true}\f[] and
+\f[B]\-\-json\-comments\f[] is provided, the \[aq]comment\[aq] field
+will contain "Something" and the \[aq]disabled\[aq] field will be set to
+the database\[aq]s native true value.
+.PP
+WARNING: Using JSON comments to disable records means that the zone in
+PowerDNS is different from the one served by BIND, as BIND does not
+handle the disabled status in the comment.
+.SH SEE ALSO
+.PP
+pdns_server(1)
+.SH AUTHORS
+PowerDNS.
--- /dev/null
+SUBDIRS = \
+ yahttp \
+ json11
+
+DIST_SUBDIRS = \
+ yahttp \
+ json11
+
+EXTRA_DIST = \
+ luawrapper/include/LuaContext.hpp
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = \
+ yahttp \
+ json11
+
+DIST_SUBDIRS = \
+ yahttp \
+ json11
+
+EXTRA_DIST = \
+ luawrapper/include/LuaContext.hpp
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ext/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+noinst_LTLIBRARIES = libjson11.la
+libjson11_la_SOURCES = json11.cpp json11.hpp
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/json11
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libjson11_la_LIBADD =
+am_libjson11_la_OBJECTS = json11.lo
+libjson11_la_OBJECTS = $(am_libjson11_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libjson11_la_SOURCES)
+DIST_SOURCES = $(libjson11_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libjson11.la
+libjson11_la_SOURCES = json11.cpp json11.hpp
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/json11/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ext/json11/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libjson11.la: $(libjson11_la_OBJECTS) $(libjson11_la_DEPENDENCIES) $(EXTRA_libjson11_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(CXXLINK) $(libjson11_la_OBJECTS) $(libjson11_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json11.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/* Copyright (c) 2013 Dropbox, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "json11.hpp"
+#include <cassert>
+#include <cstdlib>
+#include <cstdio>
+#include <limits>
+#include <string.h>
+
+namespace json11 {
+
+static const int max_depth = 200;
+
+using std::string;
+using std::vector;
+using std::map;
+using std::make_shared;
+using std::initializer_list;
+using std::move;
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Serialization
+ */
+
+static void dump(std::nullptr_t, string &out) {
+ out += "null";
+}
+
+static void dump(double value, string &out) {
+ char buf[32];
+ snprintf(buf, sizeof buf, "%.17g", value);
+ out += buf;
+}
+
+static void dump(int value, string &out) {
+ char buf[32];
+ snprintf(buf, sizeof buf, "%d", value);
+ out += buf;
+}
+
+static void dump(bool value, string &out) {
+ out += value ? "true" : "false";
+}
+
+static void dump(const string &value, string &out) {
+ out += '"';
+ for (size_t i = 0; i < value.length(); i++) {
+ const char ch = value[i];
+ if (ch == '\\') {
+ out += "\\\\";
+ } else if (ch == '"') {
+ out += "\\\"";
+ } else if (ch == '\b') {
+ out += "\\b";
+ } else if (ch == '\f') {
+ out += "\\f";
+ } else if (ch == '\n') {
+ out += "\\n";
+ } else if (ch == '\r') {
+ out += "\\r";
+ } else if (ch == '\t') {
+ out += "\\t";
+ } else if (static_cast<uint8_t>(ch) <= 0x1f) {
+ char buf[8];
+ snprintf(buf, sizeof buf, "\\u%04x", ch);
+ out += buf;
+ } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
+ && static_cast<uint8_t>(value[i+2]) == 0xa8) {
+ out += "\\u2028";
+ i += 2;
+ } else if (static_cast<uint8_t>(ch) == 0xe2 && static_cast<uint8_t>(value[i+1]) == 0x80
+ && static_cast<uint8_t>(value[i+2]) == 0xa9) {
+ out += "\\u2029";
+ i += 2;
+ } else {
+ out += ch;
+ }
+ }
+ out += '"';
+}
+
+static void dump(const Json::array &values, string &out) {
+ bool first = true;
+ out += "[";
+ for (const auto &value : values) {
+ if (!first)
+ out += ", ";
+ value.dump(out);
+ first = false;
+ }
+ out += "]";
+}
+
+static void dump(const Json::object &values, string &out) {
+ bool first = true;
+ out += "{";
+ for (const auto &kv : values) {
+ if (!first)
+ out += ", ";
+ dump(kv.first, out);
+ out += ": ";
+ kv.second.dump(out);
+ first = false;
+ }
+ out += "}";
+}
+
+void Json::dump(string &out) const {
+ m_ptr->dump(out);
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Value wrappers
+ */
+
+template <Json::Type tag, typename T>
+class Value : public JsonValue {
+protected:
+
+ // Constructors
+ explicit Value(const T &value) : m_value(value) {}
+ explicit Value(T &&value) : m_value(move(value)) {}
+
+ // Get type tag
+ Json::Type type() const override {
+ return tag;
+ }
+
+ // Comparisons
+ bool equals(const JsonValue * other) const override {
+ return m_value == static_cast<const Value<tag, T> *>(other)->m_value;
+ }
+ bool less(const JsonValue * other) const override {
+ return m_value < static_cast<const Value<tag, T> *>(other)->m_value;
+ }
+
+ const T m_value;
+ void dump(string &out) const override { json11::dump(m_value, out); }
+};
+
+class JsonDouble final : public Value<Json::NUMBER, double> {
+ double number_value() const override { return m_value; }
+ int int_value() const override { return static_cast<int>(m_value); }
+ bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
+ bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
+public:
+ explicit JsonDouble(double value) : Value(value) {}
+};
+
+class JsonInt final : public Value<Json::NUMBER, int> {
+ double number_value() const override { return m_value; }
+ int int_value() const override { return m_value; }
+ bool equals(const JsonValue * other) const override { return m_value == other->number_value(); }
+ bool less(const JsonValue * other) const override { return m_value < other->number_value(); }
+public:
+ explicit JsonInt(int value) : Value(value) {}
+};
+
+class JsonBoolean final : public Value<Json::BOOL, bool> {
+ bool bool_value() const override { return m_value; }
+public:
+ explicit JsonBoolean(bool value) : Value(value) {}
+};
+
+class JsonString final : public Value<Json::STRING, string> {
+ const string &string_value() const override { return m_value; }
+public:
+ explicit JsonString(const string &value) : Value(value) {}
+ explicit JsonString(string &&value) : Value(move(value)) {}
+};
+
+class JsonArray final : public Value<Json::ARRAY, Json::array> {
+ const Json::array &array_items() const override { return m_value; }
+ const Json & operator[](size_t i) const override;
+public:
+ explicit JsonArray(const Json::array &value) : Value(value) {}
+ explicit JsonArray(Json::array &&value) : Value(move(value)) {}
+};
+
+class JsonObject final : public Value<Json::OBJECT, Json::object> {
+ const Json::object &object_items() const override { return m_value; }
+ const Json & operator[](const string &key) const override;
+public:
+ explicit JsonObject(const Json::object &value) : Value(value) {}
+ explicit JsonObject(Json::object &&value) : Value(move(value)) {}
+};
+
+class JsonNull final : public Value<Json::NUL, std::nullptr_t> {
+public:
+ JsonNull() : Value(nullptr) {}
+};
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Static globals - static-init-safe
+ */
+struct Statics {
+ const std::shared_ptr<JsonValue> null = make_shared<JsonNull>();
+ const std::shared_ptr<JsonValue> t = make_shared<JsonBoolean>(true);
+ const std::shared_ptr<JsonValue> f = make_shared<JsonBoolean>(false);
+ const string empty_string;
+ const vector<Json> empty_vector;
+ const map<string, Json> empty_map;
+ Statics() {}
+};
+
+const Statics & statics() {
+ static const Statics s {};
+ return s;
+}
+
+const Json & static_null() {
+ // This has to be separate, not in Statics, because Json() accesses statics().null.
+ static const Json json_null;
+ return json_null;
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Constructors
+ */
+
+Json::Json() noexcept : m_ptr(statics().null) {}
+Json::Json(std::nullptr_t) noexcept : m_ptr(statics().null) {}
+Json::Json(double value) : m_ptr(make_shared<JsonDouble>(value)) {}
+Json::Json(int value) : m_ptr(make_shared<JsonInt>(value)) {}
+Json::Json(bool value) : m_ptr(value ? statics().t : statics().f) {}
+Json::Json(const string &value) : m_ptr(make_shared<JsonString>(value)) {}
+Json::Json(string &&value) : m_ptr(make_shared<JsonString>(move(value))) {}
+Json::Json(const char * value) : m_ptr(make_shared<JsonString>(value)) {}
+Json::Json(const Json::array &values) : m_ptr(make_shared<JsonArray>(values)) {}
+Json::Json(Json::array &&values) : m_ptr(make_shared<JsonArray>(move(values))) {}
+Json::Json(const Json::object &values) : m_ptr(make_shared<JsonObject>(values)) {}
+Json::Json(Json::object &&values) : m_ptr(make_shared<JsonObject>(move(values))) {}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Accessors
+ */
+
+Json::Type Json::type() const { return m_ptr->type(); }
+double Json::number_value() const { return m_ptr->number_value(); }
+int Json::int_value() const { return m_ptr->int_value(); }
+bool Json::bool_value() const { return m_ptr->bool_value(); }
+const string & Json::string_value() const { return m_ptr->string_value(); }
+const vector<Json> & Json::array_items() const { return m_ptr->array_items(); }
+const map<string, Json> & Json::object_items() const { return m_ptr->object_items(); }
+const Json & Json::operator[] (size_t i) const { return (*m_ptr)[i]; }
+const Json & Json::operator[] (const string &key) const { return (*m_ptr)[key]; }
+
+double JsonValue::number_value() const { return 0; }
+int JsonValue::int_value() const { return 0; }
+bool JsonValue::bool_value() const { return false; }
+const string & JsonValue::string_value() const { return statics().empty_string; }
+const vector<Json> & JsonValue::array_items() const { return statics().empty_vector; }
+const map<string, Json> & JsonValue::object_items() const { return statics().empty_map; }
+const Json & JsonValue::operator[] (size_t) const { return static_null(); }
+const Json & JsonValue::operator[] (const string &) const { return static_null(); }
+
+const Json & JsonObject::operator[] (const string &key) const {
+ auto iter = m_value.find(key);
+ return (iter == m_value.end()) ? static_null() : iter->second;
+}
+const Json & JsonArray::operator[] (size_t i) const {
+ if (i >= m_value.size()) return static_null();
+ else return m_value[i];
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Comparison
+ */
+
+bool Json::operator== (const Json &other) const {
+ if (m_ptr->type() != other.m_ptr->type())
+ return false;
+
+ return m_ptr->equals(other.m_ptr.get());
+}
+
+bool Json::operator< (const Json &other) const {
+ if (m_ptr->type() != other.m_ptr->type())
+ return m_ptr->type() < other.m_ptr->type();
+
+ return m_ptr->less(other.m_ptr.get());
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Parsing
+ */
+
+/* esc(c)
+ *
+ * Format char c suitable for printing in an error message.
+ */
+static inline string esc(char c) {
+ char buf[12];
+ if (static_cast<uint8_t>(c) >= 0x20 && static_cast<uint8_t>(c) <= 0x7f) {
+ snprintf(buf, sizeof buf, "'%c' (%d)", c, c);
+ } else {
+ snprintf(buf, sizeof buf, "(%d)", c);
+ }
+ return string(buf);
+}
+
+static inline bool in_range(long x, long lower, long upper) {
+ return (x >= lower && x <= upper);
+}
+
+/* JsonParser
+ *
+ * Object that tracks all state of an in-progress parse.
+ */
+struct JsonParser {
+
+ /* State
+ */
+ const string &str;
+ size_t i;
+ string &err;
+ bool failed;
+
+ /* fail(msg, err_ret = Json())
+ *
+ * Mark this parse as failed.
+ */
+ Json fail(string &&msg) {
+ return fail(move(msg), Json());
+ }
+
+ template <typename T>
+ T fail(string &&msg, const T err_ret) {
+ if (!failed)
+ err = std::move(msg);
+ failed = true;
+ return err_ret;
+ }
+
+ /* consume_whitespace()
+ *
+ * Advance until the current character is non-whitespace.
+ */
+ void consume_whitespace() {
+ while (str[i] == ' ' || str[i] == '\r' || str[i] == '\n' || str[i] == '\t')
+ i++;
+ }
+
+ /* get_next_token()
+ *
+ * Return the next non-whitespace character. If the end of the input is reached,
+ * flag an error and return 0.
+ */
+ char get_next_token() {
+ consume_whitespace();
+ if (i == str.size())
+ return fail("unexpected end of input", 0);
+
+ return str[i++];
+ }
+
+ /* encode_utf8(pt, out)
+ *
+ * Encode pt as UTF-8 and add it to out.
+ */
+ void encode_utf8(long pt, string & out) {
+ if (pt < 0)
+ return;
+
+ if (pt < 0x80) {
+ out += pt;
+ } else if (pt < 0x800) {
+ out += (pt >> 6) | 0xC0;
+ out += (pt & 0x3F) | 0x80;
+ } else if (pt < 0x10000) {
+ out += (pt >> 12) | 0xE0;
+ out += ((pt >> 6) & 0x3F) | 0x80;
+ out += (pt & 0x3F) | 0x80;
+ } else {
+ out += (pt >> 18) | 0xF0;
+ out += ((pt >> 12) & 0x3F) | 0x80;
+ out += ((pt >> 6) & 0x3F) | 0x80;
+ out += (pt & 0x3F) | 0x80;
+ }
+ }
+
+ /* parse_string()
+ *
+ * Parse a string, starting at the current position.
+ */
+ string parse_string() {
+ string out;
+ long last_escaped_codepoint = -1;
+ while (true) {
+ if (i == str.size())
+ return fail("unexpected end of input in string", "");
+
+ char ch = str[i++];
+
+ if (ch == '"') {
+ encode_utf8(last_escaped_codepoint, out);
+ return out;
+ }
+
+ if (in_range(ch, 0, 0x1f))
+ return fail("unescaped " + esc(ch) + " in string", "");
+
+ // The usual case: non-escaped characters
+ if (ch != '\\') {
+ encode_utf8(last_escaped_codepoint, out);
+ last_escaped_codepoint = -1;
+ out += ch;
+ continue;
+ }
+
+ // Handle escapes
+ if (i == str.size())
+ return fail("unexpected end of input in string", "");
+
+ ch = str[i++];
+
+ if (ch == 'u') {
+ // Extract 4-byte escape sequence
+ string esc = str.substr(i, 4);
+ for (int j = 0; j < 4; j++) {
+ if (!in_range(esc[j], 'a', 'f') && !in_range(esc[j], 'A', 'F')
+ && !in_range(esc[j], '0', '9'))
+ return fail("bad \\u escape: " + esc, "");
+ }
+
+ long codepoint = strtol(esc.data(), nullptr, 16);
+
+ // JSON specifies that characters outside the BMP shall be encoded as a pair
+ // of 4-hex-digit \u escapes encoding their surrogate pair components. Check
+ // whether we're in the middle of such a beast: the previous codepoint was an
+ // escaped lead (high) surrogate, and this is a trail (low) surrogate.
+ if (in_range(last_escaped_codepoint, 0xD800, 0xDBFF)
+ && in_range(codepoint, 0xDC00, 0xDFFF)) {
+ // Reassemble the two surrogate pairs into one astral-plane character, per
+ // the UTF-16 algorithm.
+ encode_utf8((((last_escaped_codepoint - 0xD800) << 10)
+ | (codepoint - 0xDC00)) + 0x10000, out);
+ last_escaped_codepoint = -1;
+ } else {
+ encode_utf8(last_escaped_codepoint, out);
+ last_escaped_codepoint = codepoint;
+ }
+
+ i += 4;
+ continue;
+ }
+
+ encode_utf8(last_escaped_codepoint, out);
+ last_escaped_codepoint = -1;
+
+ if (ch == 'b') {
+ out += '\b';
+ } else if (ch == 'f') {
+ out += '\f';
+ } else if (ch == 'n') {
+ out += '\n';
+ } else if (ch == 'r') {
+ out += '\r';
+ } else if (ch == 't') {
+ out += '\t';
+ } else if (ch == '"' || ch == '\\' || ch == '/') {
+ out += ch;
+ } else {
+ return fail("invalid escape character " + esc(ch), "");
+ }
+ }
+ }
+
+ /* parse_number()
+ *
+ * Parse a double.
+ */
+ Json parse_number() {
+ size_t start_pos = i;
+
+ if (str[i] == '-')
+ i++;
+
+ // Integer part
+ if (str[i] == '0') {
+ i++;
+ if (in_range(str[i], '0', '9'))
+ return fail("leading 0s not permitted in numbers");
+ } else if (in_range(str[i], '1', '9')) {
+ i++;
+ while (in_range(str[i], '0', '9'))
+ i++;
+ } else {
+ return fail("invalid " + esc(str[i]) + " in number");
+ }
+
+ if (str[i] != '.' && str[i] != 'e' && str[i] != 'E'
+ && (i - start_pos) <= static_cast<size_t>(std::numeric_limits<int>::digits10)) {
+ return std::atoi(str.c_str() + start_pos);
+ }
+
+ // Decimal part
+ if (str[i] == '.') {
+ i++;
+ if (!in_range(str[i], '0', '9'))
+ return fail("at least one digit required in fractional part");
+
+ while (in_range(str[i], '0', '9'))
+ i++;
+ }
+
+ // Exponent part
+ if (str[i] == 'e' || str[i] == 'E') {
+ i++;
+
+ if (str[i] == '+' || str[i] == '-')
+ i++;
+
+ if (!in_range(str[i], '0', '9'))
+ return fail("at least one digit required in exponent");
+
+ while (in_range(str[i], '0', '9'))
+ i++;
+ }
+
+ return std::atof(str.c_str() + start_pos);
+ }
+
+ /* expect(str, res)
+ *
+ * Expect that 'str' starts at the character that was just read. If it does, advance
+ * the input and return res. If not, flag an error.
+ */
+ Json expect(const string &expected, Json res) {
+ assert(i != 0);
+ i--;
+ if (str.compare(i, expected.length(), expected) == 0) {
+ i += expected.length();
+ return res;
+ } else {
+ return fail("parse error: expected " + expected + ", got " + str.substr(i, expected.length()));
+ }
+ }
+
+ /* parse_json()
+ *
+ * Parse a JSON object.
+ */
+ Json parse_json(int depth) {
+ if (depth > max_depth) {
+ return fail("exceeded maximum nesting depth");
+ }
+
+ char ch = get_next_token();
+ if (failed)
+ return Json();
+
+ if (ch == '-' || (ch >= '0' && ch <= '9')) {
+ i--;
+ return parse_number();
+ }
+
+ if (ch == 't')
+ return expect("true", true);
+
+ if (ch == 'f')
+ return expect("false", false);
+
+ if (ch == 'n')
+ return expect("null", Json());
+
+ if (ch == '"')
+ return parse_string();
+
+ if (ch == '{') {
+ map<string, Json> data;
+ ch = get_next_token();
+ if (ch == '}')
+ return data;
+
+ while (1) {
+ if (ch != '"')
+ return fail("expected '\"' in object, got " + esc(ch));
+
+ string key = parse_string();
+ if (failed)
+ return Json();
+
+ ch = get_next_token();
+ if (ch != ':')
+ return fail("expected ':' in object, got " + esc(ch));
+
+ data[std::move(key)] = parse_json(depth + 1);
+ if (failed)
+ return Json();
+
+ ch = get_next_token();
+ if (ch == '}')
+ break;
+ if (ch != ',')
+ return fail("expected ',' in object, got " + esc(ch));
+
+ ch = get_next_token();
+ }
+ return data;
+ }
+
+ if (ch == '[') {
+ vector<Json> data;
+ ch = get_next_token();
+ if (ch == ']')
+ return data;
+
+ while (1) {
+ i--;
+ data.push_back(parse_json(depth + 1));
+ if (failed)
+ return Json();
+
+ ch = get_next_token();
+ if (ch == ']')
+ break;
+ if (ch != ',')
+ return fail("expected ',' in list, got " + esc(ch));
+
+ ch = get_next_token();
+ (void)ch;
+ }
+ return data;
+ }
+
+ return fail("expected value, got " + esc(ch));
+ }
+};
+
+Json Json::parse(const string &in, string &err) {
+ JsonParser parser { in, 0, err, false };
+ Json result = parser.parse_json(0);
+
+ // Check for any trailing garbage
+ parser.consume_whitespace();
+ if (parser.i != in.size())
+ return parser.fail("unexpected trailing " + esc(in[parser.i]));
+
+ return result;
+}
+
+// Documented in json11.hpp
+vector<Json> Json::parse_multi(const string &in, string &err) {
+ JsonParser parser { in, 0, err, false };
+
+ vector<Json> json_vec;
+ while (parser.i != in.size() && !parser.failed) {
+ json_vec.push_back(parser.parse_json(0));
+ // Check for another object
+ parser.consume_whitespace();
+ }
+ return json_vec;
+}
+
+/* * * * * * * * * * * * * * * * * * * *
+ * Shape-checking
+ */
+
+bool Json::has_shape(const shape & types, string & err) const {
+ if (!is_object()) {
+ err = "expected JSON object, got " + dump();
+ return false;
+ }
+
+ for (auto & item : types) {
+ if ((*this)[item.first].type() != item.second) {
+ err = "bad type for " + item.first + " in " + dump();
+ return false;
+ }
+ }
+
+ return true;
+}
+
+} // namespace json11
--- /dev/null
+/* json11
+ *
+ * json11 is a tiny JSON library for C++11, providing JSON parsing and serialization.
+ *
+ * The core object provided by the library is json11::Json. A Json object represents any JSON
+ * value: null, bool, number (int or double), string (std::string), array (std::vector), or
+ * object (std::map).
+ *
+ * Json objects act like values: they can be assigned, copied, moved, compared for equality or
+ * order, etc. There are also helper methods Json::dump, to serialize a Json to a string, and
+ * Json::parse (static) to parse a std::string as a Json object.
+ *
+ * Internally, the various types of Json object are represented by the JsonValue class
+ * hierarchy.
+ *
+ * A note on numbers - JSON specifies the syntax of number formatting but not its semantics,
+ * so some JSON implementations distinguish between integers and floating-point numbers, while
+ * some don't. In json11, we choose the latter. Because some JSON implementations (namely
+ * Javascript itself) treat all numbers as the same type, distinguishing the two leads
+ * to JSON that will be *silently* changed by a round-trip through those implementations.
+ * Dangerous! To avoid that risk, json11 stores all numbers as double internally, but also
+ * provides integer helpers.
+ *
+ * Fortunately, double-precision IEEE754 ('double') can precisely store any integer in the
+ * range +/-2^53, which includes every 'int' on most systems. (Timestamps often use int64
+ * or long long to avoid the Y2038K problem; a double storing microseconds since some epoch
+ * will be exact for +/- 275 years.)
+ */
+
+/* Copyright (c) 2013 Dropbox, Inc.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#pragma once
+
+#include <string>
+#include <vector>
+#include <map>
+#include <memory>
+#include <initializer_list>
+
+namespace json11 {
+
+class JsonValue;
+
+class Json final {
+public:
+ // Types
+ enum Type {
+ NUL, NUMBER, BOOL, STRING, ARRAY, OBJECT
+ };
+
+ // Array and object typedefs
+ typedef std::vector<Json> array;
+ typedef std::map<std::string, Json> object;
+
+ // Constructors for the various types of JSON value.
+ Json() noexcept; // NUL
+ Json(std::nullptr_t) noexcept; // NUL
+ Json(double value); // NUMBER
+ Json(int value); // NUMBER
+ Json(bool value); // BOOL
+ Json(const std::string &value); // STRING
+ Json(std::string &&value); // STRING
+ Json(const char * value); // STRING
+ Json(const array &values); // ARRAY
+ Json(array &&values); // ARRAY
+ Json(const object &values); // OBJECT
+ Json(object &&values); // OBJECT
+
+ // Implicit constructor: anything with a to_json() function.
+ template <class T, class = decltype(&T::to_json)>
+ Json(const T & t) : Json(t.to_json()) {}
+
+ // Implicit constructor: map-like objects (std::map, std::unordered_map, etc)
+ template <class M, typename std::enable_if<
+ std::is_constructible<std::string, typename M::key_type>::value
+ && std::is_constructible<Json, typename M::mapped_type>::value,
+ int>::type = 0>
+ Json(const M & m) : Json(object(m.begin(), m.end())) {}
+
+ // Implicit constructor: vector-like objects (std::list, std::vector, std::set, etc)
+ template <class V, typename std::enable_if<
+ std::is_constructible<Json, typename V::value_type>::value,
+ int>::type = 0>
+ Json(const V & v) : Json(array(v.begin(), v.end())) {}
+
+ // This prevents Json(some_pointer) from accidentally producing a bool. Use
+ // Json(bool(some_pointer)) if that behavior is desired.
+ Json(void *) = delete;
+
+ // Accessors
+ Type type() const;
+
+ bool is_null() const { return type() == NUL; }
+ bool is_number() const { return type() == NUMBER; }
+ bool is_bool() const { return type() == BOOL; }
+ bool is_string() const { return type() == STRING; }
+ bool is_array() const { return type() == ARRAY; }
+ bool is_object() const { return type() == OBJECT; }
+
+ // Return the enclosed value if this is a number, 0 otherwise. Note that json11 does not
+ // distinguish between integer and non-integer numbers - number_value() and int_value()
+ // can both be applied to a NUMBER-typed object.
+ double number_value() const;
+ int int_value() const;
+
+ // Return the enclosed value if this is a boolean, false otherwise.
+ bool bool_value() const;
+ // Return the enclosed string if this is a string, "" otherwise.
+ const std::string &string_value() const;
+ // Return the enclosed std::vector if this is an array, or an empty vector otherwise.
+ const array &array_items() const;
+ // Return the enclosed std::map if this is an object, or an empty map otherwise.
+ const object &object_items() const;
+
+ // Return a reference to arr[i] if this is an array, Json() otherwise.
+ const Json & operator[](size_t i) const;
+ // Return a reference to obj[key] if this is an object, Json() otherwise.
+ const Json & operator[](const std::string &key) const;
+
+ // Serialize.
+ void dump(std::string &out) const;
+ std::string dump() const {
+ std::string out;
+ dump(out);
+ return out;
+ }
+
+ // Parse. If parse fails, return Json() and assign an error message to err.
+ static Json parse(const std::string & in, std::string & err);
+ static Json parse(const char * in, std::string & err) {
+ if (in) {
+ return parse(std::string(in), err);
+ } else {
+ err = "null input";
+ return nullptr;
+ }
+ }
+ // Parse multiple objects, concatenated or separated by whitespace
+ static std::vector<Json> parse_multi(const std::string & in, std::string & err);
+
+ bool operator== (const Json &rhs) const;
+ bool operator< (const Json &rhs) const;
+ bool operator!= (const Json &rhs) const { return !(*this == rhs); }
+ bool operator<= (const Json &rhs) const { return !(rhs < *this); }
+ bool operator> (const Json &rhs) const { return (rhs < *this); }
+ bool operator>= (const Json &rhs) const { return !(*this < rhs); }
+
+ /* has_shape(types, err)
+ *
+ * Return true if this is a JSON object and, for each item in types, has a field of
+ * the given type. If not, return false and set err to a descriptive message.
+ */
+ typedef std::initializer_list<std::pair<std::string, Type>> shape;
+ bool has_shape(const shape & types, std::string & err) const;
+
+private:
+ std::shared_ptr<JsonValue> m_ptr;
+};
+
+// Internal class hierarchy - JsonValue objects are not exposed to users of this API.
+class JsonValue {
+protected:
+ friend class Json;
+ friend class JsonInt;
+ friend class JsonDouble;
+ virtual Json::Type type() const = 0;
+ virtual bool equals(const JsonValue * other) const = 0;
+ virtual bool less(const JsonValue * other) const = 0;
+ virtual void dump(std::string &out) const = 0;
+ virtual double number_value() const;
+ virtual int int_value() const;
+ virtual bool bool_value() const;
+ virtual const std::string &string_value() const;
+ virtual const Json::array &array_items() const;
+ virtual const Json &operator[](size_t i) const;
+ virtual const Json::object &object_items() const;
+ virtual const Json &operator[](const std::string &key) const;
+ virtual ~JsonValue() {}
+};
+
+} // namespace json11
--- /dev/null
+/*
+Copyright (c) 2013, Pierre KRIEGER
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+ * Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+ * Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+ * Neither the name of the <organization> nor the
+ names of its contributors may be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL <COPYRIGHT HOLDER> BE LIABLE FOR ANY
+DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+
+#ifndef INCLUDE_LUACONTEXT_HPP
+#define INCLUDE_LUACONTEXT_HPP
+
+#include <algorithm>
+#include <array>
+#include <cassert>
+#include <cmath>
+#include <cstring>
+#include <functional>
+#include <limits>
+#include <list>
+#include <map>
+#include <memory>
+#include <random>
+#include <set>
+#include <stdexcept>
+#include <string>
+#include <sstream>
+#include <tuple>
+#include <type_traits>
+#include <unordered_map>
+#include <boost/any.hpp>
+#include <boost/mpl/distance.hpp>
+#include <boost/mpl/transform.hpp>
+#include <boost/optional.hpp>
+#include <boost/variant.hpp>
+#include <boost/type_traits.hpp>
+#include <lua.hpp>
+
+#ifdef _MSC_VER
+# include "misc/exception.hpp"
+#endif
+
+#ifdef __GNUC__
+# define ATTR_UNUSED __attribute__((unused))
+#else
+# define ATTR_UNUSED
+#endif
+
+/**
+ * Defines a Lua context
+ * A Lua context is used to interpret Lua code. Since everything in Lua is a variable (including functions),
+ * we only provide few functions like readVariable and writeVariable.
+ *
+ * You can also write variables with C++ functions so that they are callable by Lua. Note however that you HAVE TO convert
+ * your function to std::function (not directly std::bind or a lambda function) so the class can detect which argument types
+ * it wants. These arguments may only be of basic types (int, float, etc.) or std::string.
+ */
+class LuaContext {
+ struct ValueInRegistry;
+ template<typename TFunctionObject, typename TFirstParamType> struct Binder;
+ template<typename T> struct IsOptional;
+ enum Globals_t { Globals }; // tag for "global variables"
+public:
+ /**
+ * @param openDefaultLibs True if luaL_openlibs should be called
+ */
+ explicit LuaContext(bool openDefaultLibs = true)
+ {
+ // luaL_newstate can return null if allocation failed
+ mState = luaL_newstate();
+ if (mState == nullptr)
+ throw std::bad_alloc();
+
+ // setting the panic function
+ lua_atpanic(mState, [](lua_State* state) -> int {
+ const std::string str = lua_tostring(state, -1);
+ lua_pop(state, 1);
+ assert(false && "lua_atpanic triggered");
+ exit(0);
+ });
+
+ // opening default library if required to do so
+ if (openDefaultLibs)
+ luaL_openlibs(mState);
+ }
+
+ /**
+ * Move constructor
+ */
+ LuaContext(LuaContext&& s) :
+ mState(s.mState)
+ {
+ s.mState = luaL_newstate();
+ }
+
+ /**
+ * Move operator
+ */
+ LuaContext& operator=(LuaContext&& s) noexcept
+ {
+ std::swap(mState, s.mState);
+ return *this;
+ }
+
+ /**
+ * Copy is forbidden
+ */
+ LuaContext(const LuaContext&) = delete;
+
+ /**
+ * Copy is forbidden
+ */
+ LuaContext& operator=(const LuaContext&) = delete;
+
+ /**
+ * Destructor
+ */
+ ~LuaContext() noexcept
+ {
+ assert(mState);
+ lua_close(mState);
+ }
+
+ /**
+ * Thrown when an error happens during execution of lua code (like not enough parameters for a function)
+ */
+ class ExecutionErrorException : public std::runtime_error
+ {
+ public:
+ ExecutionErrorException(const std::string& msg) :
+ std::runtime_error(msg)
+ {
+ }
+ };
+
+ /**
+ * Thrown when a syntax error happens in a lua script
+ */
+ class SyntaxErrorException : public std::runtime_error
+ {
+ public:
+ SyntaxErrorException(const std::string& msg) :
+ std::runtime_error(msg)
+ {
+ }
+ };
+
+ /**
+ * Thrown when trying to cast a Lua variable to an unvalid type, eg. trying to read a number when the variable is a string
+ */
+ class WrongTypeException : public std::runtime_error
+ {
+ public:
+ WrongTypeException(std::string luaType, const std::type_info& destination) :
+ std::runtime_error("Trying to cast a lua variable from \"" + luaType + "\" to \"" + destination.name() + "\""),
+ luaType(luaType),
+ destination(destination)
+ {
+ }
+
+ std::string luaType;
+ const std::type_info& destination;
+ };
+
+ /**
+ * Function object that can call a function stored by Lua
+ * This type is copiable and movable, but not constructible. It can only be created through readVariable.
+ * @tparam TFunctionType Function type (eg. "int (int, bool)")
+ */
+ template<typename TFunctionType>
+ class LuaFunctionCaller;
+
+ /**
+ * Opaque type that identifies a Lua thread
+ */
+ struct ThreadID {
+ ThreadID() = default;
+ ThreadID(ThreadID&& o) : state(o.state), threadInRegistry(std::move(o.threadInRegistry)) { }
+ ThreadID& operator=(ThreadID&& o) { std::swap(state, o.state); std::swap(threadInRegistry, o.threadInRegistry); return *this; }
+ public:
+ friend LuaContext;
+ lua_State* state;
+ std::unique_ptr<ValueInRegistry> threadInRegistry;
+ };
+
+ /**
+ * Type that is considered as an empty array
+ */
+ enum EmptyArray_t { EmptyArray };
+
+ /**
+ * Type for a metatable
+ */
+ enum Metatable_t { Metatable };
+
+ /**
+ * Executes lua code from the stream
+ * @param code A stream that Lua will read its code from
+ */
+ void executeCode(std::istream& code)
+ {
+ auto toCall = load(mState, code);
+ call<std::tuple<>>(mState, std::move(toCall));
+ }
+
+ /**
+ * Executes lua code from the stream and returns a value
+ * @param code A stream that Lua will read its code from
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(std::istream& code)
+ -> TType
+ {
+ auto toCall = load(mState, code);
+ return call<TType>(mState, std::move(toCall));
+ }
+
+ /**
+ * Executes lua code given as parameter
+ * @param code A string containing code that will be executed by Lua
+ */
+ void executeCode(const std::string& code)
+ {
+ executeCode(code.c_str());
+ }
+
+ /*
+ * Executes Lua code from the stream and returns a value
+ * @param code A string containing code that will be executed by Lua
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(const std::string& code)
+ -> TType
+ {
+ return executeCode<TType>(code.c_str());
+ }
+
+ /**
+ * Executes Lua code
+ * @param code A string containing code that will be executed by Lua
+ */
+ void executeCode(const char* code)
+ {
+ auto toCall = load(mState, code);
+ call<std::tuple<>>(mState, std::move(toCall));
+ }
+
+ /*
+ * Executes Lua code from the stream and returns a value
+ * @param code A string containing code that will be executed by Lua
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(const char* code)
+ -> TType
+ {
+ auto toCall = load(mState, code);
+ return call<TType>(mState, std::move(toCall));
+ }
+
+ /**
+ * Executes lua code from the stream
+ * @param code A stream that Lua will read its code from
+ */
+ void executeCode(const ThreadID& thread, std::istream& code)
+ {
+ auto toCall = load(thread.state, code);
+ call<std::tuple<>>(thread.state, std::move(toCall));
+ }
+
+ /**
+ * Executes lua code from the stream and returns a value
+ * @param code A stream that Lua will read its code from
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(const ThreadID& thread, std::istream& code)
+ -> TType
+ {
+ auto toCall = load(thread.state, code);
+ return call<TType>(thread.state, std::move(toCall));
+ }
+
+ /**
+ * Executes lua code given as parameter
+ * @param code A string containing code that will be executed by Lua
+ */
+ void executeCode(const ThreadID& thread, const std::string& code)
+ {
+ executeCode(thread, code.c_str());
+ }
+
+ /*
+ * Executes Lua code from the stream and returns a value
+ * @param code A string containing code that will be executed by Lua
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(const ThreadID& thread, const std::string& code)
+ -> TType
+ {
+ return executeCode<TType>(thread, code.c_str());
+ }
+
+ /**
+ * Executes Lua code
+ * @param code A string containing code that will be executed by Lua
+ */
+ void executeCode(const ThreadID& thread, const char* code)
+ {
+ auto toCall = load(thread.state, code);
+ call<std::tuple<>>(thread.state, std::move(toCall));
+ }
+
+ /*
+ * Executes Lua code from the stream and returns a value
+ * @param code A string containing code that will be executed by Lua
+ * @tparam TType The type that the executing code should return
+ */
+ template<typename TType>
+ auto executeCode(const ThreadID& thread, const char* code)
+ -> TType
+ {
+ auto toCall = load(thread.state, code);
+ return call<TType>(thread.state, std::move(toCall));
+ }
+
+ /**
+ * Tells that Lua will be allowed to access an object's function
+ * This is the version "registerFunction(name, &Foo::function)"
+ */
+ template<typename TPointerToMemberFunction>
+ auto registerFunction(const std::string& name, TPointerToMemberFunction pointer)
+ -> typename std::enable_if<std::is_member_function_pointer<TPointerToMemberFunction>::value>::type
+ {
+ registerFunctionImpl(name, std::mem_fn(pointer), tag<TPointerToMemberFunction>{});
+ }
+
+ /**
+ * Tells that Lua will be allowed to access an object's function
+ * This is the version with an explicit template parameter: "registerFunction<void (Foo::*)()>(name, [](Foo&) { })"
+ * @param fn Function object which takes as first parameter a reference to the object
+ * @tparam TFunctionType Pointer-to-member function type
+ */
+ template<typename TFunctionType, typename TType>
+ void registerFunction(const std::string& functionName, TType fn)
+ {
+ static_assert(std::is_member_function_pointer<TFunctionType>::value, "registerFunction must take a member function pointer type as template parameter");
+ registerFunctionImpl(functionName, std::move(fn), tag<TFunctionType>{});
+ }
+
+ /**
+ * Tells that Lua will be allowed to access an object's function
+ * This is the alternative version with an explicit template parameter: "registerFunction<Foo, void (*)()>(name, [](Foo&) { })"
+ * @param fn Function object which takes as first parameter a reference to the object
+ * @tparam TObject Object to register this function to
+ * @tparam TFunctionType Function type
+ */
+ template<typename TObject, typename TFunctionType, typename TType>
+ void registerFunction(const std::string& functionName, TType fn)
+ {
+ static_assert(std::is_function<TFunctionType>::value, "registerFunction must take a function type as template parameter");
+ registerFunctionImpl(functionName, std::move(fn), tag<TObject>{}, tag<TFunctionType>{});
+ }
+
+ /**
+ * Inverse operation of registerFunction
+ * @tparam TType Type whose function belongs to
+ */
+ template<typename TType>
+ void unregisterFunction(const std::string& functionName)
+ {
+ lua_pushlightuserdata(mState, const_cast<std::type_info*>(&typeid(TType)));
+ lua_pushnil(mState);
+ lua_settable(mState, LUA_REGISTRYINDEX);
+ checkTypeRegistration(mState, &typeid(TType));
+
+ lua_pushlightuserdata(mState, const_cast<std::type_info*>(&typeid(TType*)));
+ lua_pushnil(mState);
+ lua_settable(mState, LUA_REGISTRYINDEX);
+ checkTypeRegistration(mState, &typeid(TType*));
+
+ lua_pushlightuserdata(mState, const_cast<std::type_info*>(&typeid(std::shared_ptr<TType>)));
+ lua_pushnil(mState);
+ lua_settable(mState, LUA_REGISTRYINDEX);
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TType>));
+ }
+
+ /**
+ * Registers a member variable
+ * This is the version "registerMember(name, &Foo::member)"
+ */
+ template<typename TObject, typename TVarType>
+ void registerMember(const std::string& name, TVarType TObject::*member)
+ {
+ // implementation simply calls the custom member with getter and setter
+ const auto getter = [=](const TObject& obj) -> TVarType { return obj.*member; };
+ const auto setter = [=](TObject& obj, const TVarType& value) { obj.*member = value; };
+ registerMember<TVarType (TObject::*)>(name, getter, setter);
+ }
+
+ /**
+ * Registers a member variable
+ * This is the version "registerMember<Foo, int>(name, getter, setter)"
+ * @tparam TObject Type to register the member to
+ * @tparam TVarType Type of the member
+ * @param name Name of the member to register
+ * @param readFunction Function of type "TVarType (const TObject&)"
+ * @param writeFunction Function of type "void (TObject&, const TVarType&)"
+ */
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMember(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(name, std::move(readFunction), std::move(writeFunction));
+ }
+
+ /**
+ * Registers a member variable
+ * This is the version "registerMember<int (Foo::*)>(name, getter, setter)"
+ * @tparam TMemberType Pointer to member object representing the type
+ * @param name Name of the member to register
+ * @param readFunction Function of type "TVarType (const TObject&)"
+ * @param writeFunction Function of type "void (TObject&, const TVarType&)"
+ */
+ template<typename TMemberType, typename TReadFunction, typename TWriteFunction>
+ void registerMember(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ static_assert(std::is_member_object_pointer<TMemberType>::value, "registerMember must take a member object pointer type as template parameter");
+ registerMemberImpl(tag<TMemberType>{}, name, std::move(readFunction), std::move(writeFunction));
+ }
+
+ /**
+ * Registers a non-modifiable member variable
+ * This is the version "registerMember<Foo, int>(name, getter)"
+ * @tparam TObject Type to register the member to
+ * @tparam TVarType Type of the member
+ * @param name Name of the member to register
+ * @param readFunction Function of type "TVarType (const TObject&)"
+ */
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMember(const std::string& name, TReadFunction readFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(name, std::move(readFunction));
+ }
+
+ /**
+ * Registers a non-modifiable member variable
+ * This is the version "registerMember<int (Foo::*)>(name, getter)"
+ * @tparam TMemberType Pointer to member object representing the type
+ * @param name Name of the member to register
+ * @param readFunction Function of type "TVarType (const TObject&)"
+ */
+ template<typename TMemberType, typename TReadFunction>
+ void registerMember(const std::string& name, TReadFunction readFunction)
+ {
+ static_assert(std::is_member_object_pointer<TMemberType>::value, "registerMember must take a member object pointer type as template parameter");
+ registerMemberImpl(tag<TMemberType>{}, name, std::move(readFunction));
+ }
+
+ /**
+ * Registers a dynamic member variable
+ * This is the version "registerMember<Foo, int>(getter, setter)"
+ * @tparam TObject Type to register the member to
+ * @tparam TVarType Type of the member
+ * @param readFunction Function of type "TVarType (const TObject&, const std::string&)"
+ * @param writeFunction Function of type "void (TObject&, const std::string&, const TVarType&)"
+ */
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMember(TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(std::move(readFunction), std::move(writeFunction));
+ }
+
+ /**
+ * Registers a dynamic member variable
+ * This is the version "registerMember<int (Foo::*)>(getter, setter)"
+ * @tparam TMemberType Pointer to member object representing the type
+ * @param readFunction Function of type "TVarType (const TObject&, const std::string&)"
+ * @param writeFunction Function of type "void (TObject&, const std::string&, const TVarType&)"
+ */
+ template<typename TMemberType, typename TReadFunction, typename TWriteFunction>
+ void registerMember(TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ static_assert(std::is_member_object_pointer<TMemberType>::value, "registerMember must take a member object pointer type as template parameter");
+ registerMemberImpl(tag<TMemberType>{}, std::move(readFunction), std::move(writeFunction));
+ }
+
+ /**
+ * Registers a dynamic non-modifiable member variable
+ * This is the version "registerMember<Foo, int>(getter)"
+ * @tparam TObject Type to register the member to
+ * @tparam TVarType Type of the member
+ * @param readFunction Function of type "TVarType (const TObject&, const std::string&)"
+ */
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMember(TReadFunction readFunction)
+ {
+ registerMemberImpl<TObject, TVarType>(std::move(readFunction));
+ }
+
+ /**
+ * Registers a dynamic non-modifiable member variable
+ * This is the version "registerMember<int (Foo::*)>(getter)"
+ * @tparam TMemberType Pointer to member object representing the type
+ * @param readFunction Function of type "TVarType (const TObject&, const std::string&)"
+ */
+ template<typename TMemberType, typename TReadFunction>
+ void registerMember(TReadFunction readFunction)
+ {
+ static_assert(std::is_member_object_pointer<TMemberType>::value, "registerMember must take a member object pointer type as template parameter");
+ registerMemberImpl(tag<TMemberType>{}, std::move(readFunction));
+ }
+
+ /**
+ * Creates a new thread
+ * A Lua thread is not really a thread, but rather an "execution stack".
+ * You can destroy the thread by calling destroyThread
+ * @sa destroyThread
+ */
+ auto createThread()
+ -> ThreadID
+ {
+ ThreadID result;
+
+ result.state = lua_newthread(mState);
+ result.threadInRegistry = std::unique_ptr<ValueInRegistry>(new ValueInRegistry(mState));
+ lua_pop(mState, 1);
+
+ return std::move(result);
+ }
+
+ /**
+ * Destroys a thread created with createThread
+ * @sa createThread
+ */
+ void destroyThread(ThreadID& id)
+ {
+ id.threadInRegistry.reset();
+ }
+
+ /**
+ * Reads the content of a Lua variable
+ *
+ * @tparam TType Type requested for the read
+ * @throw WrongTypeException When the variable is not convertible to the requested type
+ * @sa writeVariable
+ *
+ * Readable types are all types accepted by writeVariable except nullptr, std::unique_ptr and function pointers
+ * Additionaly supported:
+ * - LuaFunctionCaller<FunctionType>, which is an alternative to std::function
+ * - references to custom objects, in which case it will return the object in-place
+ *
+ * After the variable name, you can add other parameters.
+ * If the variable is an array, it will instead get the element of that array whose offset is the second parameter.
+ * Same applies for third, fourth, etc. parameters.
+ */
+ template<typename TType, typename... TTypes>
+ TType readVariable(const std::string& name, TTypes&&... elements) const
+ {
+ lua_getglobal(mState, name.c_str());
+ lookIntoStackTop(mState, std::forward<TTypes>(elements)...);
+ return readTopAndPop<TType>(mState, PushedObject{mState, 1});
+ }
+
+ /**
+ * @sa readVariable
+ */
+ template<typename TType, typename... TTypes>
+ TType readVariable(const char* name, TTypes&&... elements) const
+ {
+ lua_getglobal(mState, name);
+ lookIntoStackTop(mState, std::forward<TTypes>(elements)...);
+ return readTopAndPop<TType>(mState, PushedObject{mState, 1});
+ }
+
+ /**
+ * @sa readVariable
+ */
+ template<typename TType, typename... TTypes>
+ TType readVariable(const ThreadID& thread, const std::string& name, TTypes&&... elements) const
+ {
+ lua_getglobal(thread.state, name.c_str());
+ lookIntoStackTop(thread.state, std::forward<TTypes>(elements)...);
+ return readTopAndPop<TType>(thread.state, PushedObject{thread.state, 1});
+ }
+
+ /**
+ * @sa readVariable
+ */
+ template<typename TType, typename... TTypes>
+ TType readVariable(const ThreadID& thread, const char* name, TTypes&&... elements) const
+ {
+ lua_getglobal(thread.state, name);
+ lookIntoStackTop(thread.state, std::forward<TTypes>(elements)...);
+ return readTopAndPop<TType>(thread.state, PushedObject{thread.state, 1});
+ }
+
+ /**
+ * Changes the content of a Lua variable
+ *
+ * Accepted values are:
+ * - all base types (char, short, int, float, double, bool)
+ * - std::string
+ * - enums
+ * - std::vector<>
+ * - std::vector<std::pair<>>, std::map<> and std::unordered_map<> (the key and value must also be accepted values)
+ * - std::function<> (all parameters must be accepted values, and return type must be either an accepted value for readVariable or a tuple)
+ * - std::shared_ptr<> (std::unique_ptr<> are converted to std::shared_ptr<>)
+ * - nullptr (writes nil)
+ * - any object
+ *
+ * All objects are passed by copy and destroyed by the garbage collector if necessary.
+ */
+ template<typename... TData>
+ void writeVariable(TData&&... data) noexcept {
+ static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeVariable");
+ typedef typename std::decay<typename std::tuple_element<sizeof...(TData) - 1,std::tuple<TData...>>::type>::type
+ RealDataType;
+ static_assert(!std::is_same<typename Tupleizer<RealDataType>::type,RealDataType>::value, "Error: you can't use LuaContext::writeVariable with a tuple");
+
+ setTable<RealDataType>(mState, Globals, std::forward<TData>(data)...);
+ }
+
+ /**
+ * Equivalent to writeVariable(varName, ..., std::function<TFunctionType>(data));
+ * This version is more effecient than writeVariable if you want to write functions
+ */
+ template<typename TFunctionType, typename... TData>
+ void writeFunction(TData&&... data) noexcept {
+ static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeFunction");
+
+ setTable<TFunctionType>(mState, Globals, std::forward<TData>(data)...);
+ }
+
+ /**
+ * Same as the other writeFunction, except that the template parameter is automatically detected
+ * This only works if the data is either a native function pointer, or contains one operator() (this is the case for lambdas)
+ */
+ template<typename... TData>
+ void writeFunction(TData&&... data) noexcept {
+ static_assert(sizeof...(TData) >= 2, "You must pass at least a variable name and a value to writeFunction");
+ typedef typename std::decay<typename std::tuple_element<sizeof...(TData) - 1,std::tuple<TData...>>::type>::type
+ RealDataType;
+ typedef typename FunctionTypeDetector<RealDataType>::type
+ DetectedFunctionType;
+
+ return writeFunction<DetectedFunctionType>(std::forward<TData>(data)...);
+ }
+
+
+private:
+ // the state is the most important variable in the class since it is our interface with Lua
+ // - registered members and functions are stored in tables at offset &typeid(type) of the registry
+ // each table has its getter functions at offset 0, getter members at offset 1, default getter at offset 2
+ // offset 3 is unused, setter members at offset 4, default setter at offset 5
+ lua_State* mState;
+
+
+ /**************************************************/
+ /* PUSH OBJECT */
+ /**************************************************/
+ struct PushedObject {
+ PushedObject(lua_State* state, int num = 1) : state(state), num(num) {}
+ ~PushedObject() { assert(lua_gettop(state) >= num); if (num >= 1) lua_pop(state, num); }
+
+ PushedObject& operator=(const PushedObject&) = delete;
+ PushedObject(const PushedObject&) = delete;
+ PushedObject& operator=(PushedObject&& other) { std::swap(state, other.state); std::swap(num, other.num); return *this; }
+ PushedObject(PushedObject&& other) : state(other.state), num(other.num) { other.num = 0; }
+
+ PushedObject operator+(PushedObject&& other) && { PushedObject obj(state, num + other.num); num = 0; other.num = 0; return std::move(obj); }
+ void operator+=(PushedObject&& other) { assert(state == other.state); num += other.num; other.num = 0; }
+
+ auto getState() const -> lua_State* { return state; }
+ auto getNum() const -> int { return num; }
+
+ int release() { const auto n = num; num = 0; return n; }
+ void pop() { if (num >= 1) lua_pop(state, num); num = 0; }
+ void pop(int n) { assert(num >= n); lua_pop(state, n); num -= n; }
+
+ private:
+ lua_State* state;
+ int num = 0;
+ };
+
+
+ /**************************************************/
+ /* MISC */
+ /**************************************************/
+ // type used as a tag
+ template<typename T>
+ struct tag {};
+
+ // tag for "the registry"
+ enum RegistryTag { Registry };
+
+ // this function takes a value representing the offset to look into
+ // it will look into the top element of the stack and replace the element by its content at the given index
+ template<typename OffsetType1, typename... OffsetTypeOthers>
+ static void lookIntoStackTop(lua_State* state, OffsetType1&& offset1, OffsetTypeOthers&&... offsetOthers) {
+ static_assert(Pusher<typename std::decay<OffsetType1>::type>::minSize == 1 && Pusher<typename std::decay<OffsetType1>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+ auto p1 = Pusher<typename std::decay<OffsetType1>::type>::push(state, offset1);
+ lua_gettable(state, -2);
+ lua_remove(state, -2);
+ p1.release();
+
+ lookIntoStackTop(state, std::forward<OffsetTypeOthers>(offsetOthers)...);
+ }
+
+ template<typename... OffsetTypeOthers>
+ static void lookIntoStackTop(lua_State* state, Metatable_t, OffsetTypeOthers&&... offsetOthers) {
+ lua_getmetatable(state, -1);
+ lua_remove(state, -2);
+
+ lookIntoStackTop(state, std::forward<OffsetTypeOthers>(offsetOthers)...);
+ }
+
+ static void lookIntoStackTop(lua_State*) {
+ }
+
+ // equivalent of lua_settable with t[k]=n, where t is the value at the index in the template parameter, k is the second parameter, n is the last parameter, and n is pushed by the function in the first parameter
+ // if there are more than 3 parameters, parameters 3 to n-1 are considered as sub-indices into the array
+ // the dataPusher MUST push only one thing on the stack
+ // TTableIndex must be either LUA_REGISTERYINDEX, LUA_GLOBALSINDEX, LUA_ENVINDEX, or the position of the element on the stack
+ template<typename TDataType, typename TIndex, typename TData>
+ static void setTable(lua_State* state, const PushedObject&, TIndex&& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TIndex>::type>::minSize == 1 && Pusher<typename std::decay<TIndex>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TIndex>::type>::push(state, index);
+ auto p2 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+
+ lua_settable(state, -3);
+ p1.release();
+ p2.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, const PushedObject&, const std::string& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setfield(state, -2, index.c_str());
+ p1.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, const PushedObject&, const char* index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setfield(state, -2, index);
+ p1.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, const PushedObject&, Metatable_t, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setmetatable(state, -2);
+ p1.release();
+ }
+
+ template<typename TDataType, typename TIndex1, typename TIndex2, typename TIndex3, typename... TIndices>
+ static auto setTable(lua_State* state, PushedObject&, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ -> typename std::enable_if<!std::is_same<typename std::decay<TIndex1>::type, Metatable_t>::value>::type
+ {
+ static_assert(Pusher<typename std::decay<TIndex1>::type>::minSize == 1 && Pusher<typename std::decay<TIndex1>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+
+ auto p1 = Pusher<typename std::decay<TIndex1>::type>::push(state, std::forward<TIndex1>(index1));
+ lua_gettable(state, -2);
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+
+ template<typename TDataType, typename TIndex1, typename TIndex2, typename TIndex3, typename... TIndices>
+ static auto setTable(lua_State* state, PushedObject&& pushedTable, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ -> typename std::enable_if<!std::is_same<typename std::decay<TIndex1>::type, Metatable_t>::value>::type
+ {
+ static_assert(Pusher<typename std::decay<TIndex1>::type>::minSize == 1 && Pusher<typename std::decay<TIndex1>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+
+ auto p1 = Pusher<typename std::decay<TIndex1>::type>::push(state, std::forward<TIndex1>(index1)) + std::move(pushedTable);
+ lua_gettable(state, -2);
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+
+ template<typename TDataType, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, PushedObject& pushedObject, Metatable_t, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ if (lua_getmetatable(state, -1) == 0)
+ {
+ lua_newtable(state);
+ PushedObject p1{state, 1};
+
+ setTable<TDataType>(state, p1, std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+
+ lua_setmetatable(state, -2);
+ p1.release();
+ }
+ else
+ {
+ setTable<TDataType>(state, pushedObject, std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+ }
+
+ template<typename TDataType, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, PushedObject&& pushedObject, Metatable_t, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ if (lua_getmetatable(state, -1) == 0)
+ {
+ lua_newtable(state);
+ PushedObject p1{state, 1};
+
+ setTable<TDataType>(state, p1, std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+
+ lua_setmetatable(state, -2);
+ p1.release();
+ }
+ else
+ {
+ setTable<TDataType>(state, std::move(pushedObject), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+ }
+
+ template<typename TDataType, typename TIndex, typename TData>
+ static void setTable(lua_State* state, RegistryTag, TIndex&& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TIndex>::type>::minSize == 1 && Pusher<typename std::decay<TIndex>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TIndex>::type>::push(state, index);
+ auto p2 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+
+ lua_settable(state, LUA_REGISTRYINDEX);
+ p1.release();
+ p2.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, RegistryTag, const std::string& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setfield(state, LUA_REGISTRYINDEX, index.c_str());
+ p1.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, RegistryTag, const char* index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setfield(state, LUA_REGISTRYINDEX, index);
+ p1.release();
+ }
+
+ template<typename TDataType, typename TIndex1, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, RegistryTag, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TIndex1>::type>::minSize == 1 && Pusher<typename std::decay<TIndex1>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+
+ auto p1 = Pusher<typename std::decay<TIndex1>::type>::push(state, std::forward<TIndex1>(index1));
+ lua_gettable(state, LUA_REGISTRYINDEX);
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+
+ template<typename TDataType, typename TIndex, typename TData>
+ static void setTable(lua_State* state, Globals_t, TIndex&& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TIndex>::type>::minSize == 1 && Pusher<typename std::decay<TIndex>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+
+# if LUA_VERSION_NUM >= 502
+
+ lua_pushglobaltable(state);
+ PushedObject p3{state, 1};
+ auto p1 = Pusher<typename std::decay<TIndex>::type>::push(state, index);
+ auto p2 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_settable(state, -3);
+
+# else
+
+ auto p1 = Pusher<typename std::decay<TIndex>::type>::push(state, index);
+ auto p2 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_settable(state, LUA_GLOBALSINDEX);
+
+# endif
+
+ p1.release();
+ p2.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, Globals_t, const std::string& index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setglobal(state, index.c_str());
+ p1.release();
+ }
+
+ template<typename TDataType, typename TData>
+ static void setTable(lua_State* state, Globals_t, const char* index, TData&& data) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TDataType>::type>::minSize == 1 && Pusher<typename std::decay<TDataType>::type>::maxSize == 1, "Impossible to have a multiple-values data");
+
+ auto p1 = Pusher<typename std::decay<TDataType>::type>::push(state, std::forward<TData>(data));
+ lua_setglobal(state, index);
+ p1.release();
+ }
+
+ template<typename TDataType, typename TIndex1, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, Globals_t, TIndex1&& index1, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ static_assert(Pusher<typename std::decay<TIndex1>::type>::minSize == 1 && Pusher<typename std::decay<TIndex1>::type>::maxSize == 1, "Impossible to have a multiple-values index");
+
+# if LUA_VERSION_NUM >= 502
+
+ lua_pushglobaltable(state);
+ auto p1 = Pusher<typename std::decay<TIndex1>::type>::push(state, std::forward<TIndex1>(index1)) + PushedObject{state, 1};
+ lua_gettable(state, -2);
+
+# else
+
+ auto p1 = Pusher<typename std::decay<TIndex1>::type>::push(state, std::forward<TIndex1>(index1));
+ lua_gettable(state, LUA_GLOBALSINDEX);
+
+# endif
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+
+ // TODO: g++ reports "ambiguous overload"
+ /*template<typename TDataType, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, Globals_t, const char* index, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ lua_getglobal(state, index);
+ PushedObject p1{state, 1};
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }
+
+ template<typename TDataType, typename TIndex2, typename TIndex3, typename... TIndices>
+ static void setTable(lua_State* state, Globals_t, const std::string& index, TIndex2&& index2, TIndex3&& index3, TIndices&&... indices) noexcept
+ {
+ lua_getglobal(state, index.c_str());
+ PushedObject p1{state, 1};
+
+ setTable<TDataType>(state, std::move(p1), std::forward<TIndex2>(index2), std::forward<TIndex3>(index3), std::forward<TIndices>(indices)...);
+ }*/
+
+ // simple function that reads the "nb" first top elements of the stack, pops them, and returns the value
+ // warning: first parameter is the number of parameters, not the parameter index
+ // if read generates an exception, stack is poped anyway
+ template<typename TReturnType>
+ static auto readTopAndPop(lua_State* state, PushedObject object)
+ -> TReturnType
+ {
+ auto val = Reader<typename std::decay<TReturnType>::type>::read(state, -object.getNum());
+ if (!val.is_initialized())
+ throw WrongTypeException{lua_typename(state, lua_type(state, -object.getNum())), typeid(TReturnType)};
+ return val.get();
+ }
+
+ // checks that the offsets for a type's registrations are set in the registry
+ static void checkTypeRegistration(lua_State* state, const std::type_info* type)
+ {
+ lua_pushlightuserdata(state, const_cast<std::type_info*>(type));
+ lua_gettable(state, LUA_REGISTRYINDEX);
+ if (!lua_isnil(state, -1)) {
+ lua_pop(state, 1);
+ return;
+ }
+ lua_pop(state, 1);
+
+ lua_pushlightuserdata(state, const_cast<std::type_info*>(type));
+ lua_newtable(state);
+
+ lua_pushinteger(state, 0);
+ lua_newtable(state);
+ lua_settable(state, -3);
+
+ lua_pushinteger(state, 1);
+ lua_newtable(state);
+ lua_settable(state, -3);
+
+ lua_pushinteger(state, 3);
+ lua_newtable(state);
+ lua_settable(state, -3);
+
+ lua_pushinteger(state, 4);
+ lua_newtable(state);
+ lua_settable(state, -3);
+
+ lua_settable(state, LUA_REGISTRYINDEX);
+ }
+
+ //
+# ifdef _MSC_VER
+ __declspec(noreturn)
+# else
+ [[noreturn]]
+# endif
+ static void luaError(lua_State* state)
+ {
+ lua_error(state);
+ assert(false);
+ std::terminate(); // removes compilation warning
+ }
+
+
+ /**************************************************/
+ /* FUNCTIONS REGISTRATION */
+ /**************************************************/
+ // the "registerFunction" public functions call this one
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<TObject>, tag<TRetValue (TOtherParams...)>)
+ {
+ static_assert(std::is_class<TObject>::value || std::is_pointer<TObject>::value || std::is_union<TObject>::value , "registerFunction can only be used for a class a union or a pointer");
+
+ checkTypeRegistration(mState, &typeid(TObject));
+ setTable<TRetValue(TObject&, TOtherParams...)>(mState, Registry, &typeid(TObject), 0, functionName, std::move(function));
+
+ checkTypeRegistration(mState, &typeid(TObject*));
+ setTable<TRetValue(TObject*, TOtherParams...)>(mState, Registry, &typeid(TObject*), 0, functionName, [=](TObject* obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward<TOtherParams>(rest)...); });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject>));
+ setTable<TRetValue(std::shared_ptr<TObject>, TOtherParams...)>(mState, Registry, &typeid(std::shared_ptr<TObject>), 0, functionName, [=](const std::shared_ptr<TObject>& obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward<TOtherParams>(rest)...); });
+ }
+
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<const TObject>, tag<TRetValue (TOtherParams...)> fTypeTag)
+ {
+ registerFunctionImpl(functionName, function, tag<TObject>{}, fTypeTag);
+
+ checkTypeRegistration(mState, &typeid(TObject const*));
+ setTable<TRetValue(TObject const*, TOtherParams...)>(mState, Registry, &typeid(TObject const*), 0, functionName, [=](TObject const* obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward<TOtherParams>(rest)...); });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject const>));
+ setTable<TRetValue(std::shared_ptr<TObject const>, TOtherParams...)>(mState, Registry, &typeid(std::shared_ptr<TObject const>), 0, functionName, [=](const std::shared_ptr<TObject const>& obj, TOtherParams... rest) { assert(obj); return function(*obj, std::forward<TOtherParams>(rest)...); });
+ }
+
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<TRetValue (TObject::*)(TOtherParams...)>)
+ {
+ registerFunctionImpl(functionName, std::move(function), tag<TObject>{}, tag<TRetValue (TOtherParams...)>{});
+ }
+
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<TRetValue (TObject::*)(TOtherParams...) const>)
+ {
+ registerFunctionImpl(functionName, std::move(function), tag<const TObject>{}, tag<TRetValue (TOtherParams...)>{});
+ }
+
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<TRetValue (TObject::*)(TOtherParams...) volatile>)
+ {
+ registerFunctionImpl(functionName, std::move(function), tag<TObject>{}, tag<TRetValue (TOtherParams...)>{});
+ }
+
+ template<typename TFunctionType, typename TRetValue, typename TObject, typename... TOtherParams>
+ void registerFunctionImpl(const std::string& functionName, TFunctionType function, tag<TRetValue (TObject::*)(TOtherParams...) const volatile>)
+ {
+ registerFunctionImpl(functionName, std::move(function), tag<const TObject>{}, tag<TRetValue (TOtherParams...)>{});
+ }
+
+ // the "registerMember" public functions call this one
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMemberImpl(const std::string& name, TReadFunction readFunction)
+ {
+ static_assert(std::is_class<TObject>::value || std::is_pointer<TObject>::value, "registerMember can only be called on a class or a pointer");
+
+ checkTypeRegistration(mState, &typeid(TObject));
+ setTable<TVarType (TObject&)>(mState, Registry, &typeid(TObject), 1, name, [readFunction](TObject const& object) {
+ return readFunction(object);
+ });
+
+ checkTypeRegistration(mState, &typeid(TObject*));
+ setTable<TVarType (TObject*)>(mState, Registry, &typeid(TObject*), 1, name, [readFunction](TObject const* object) {
+ assert(object);
+ return readFunction(*object);
+ });
+
+ checkTypeRegistration(mState, &typeid(TObject const*));
+ setTable<TVarType (TObject const*)>(mState, Registry, &typeid(TObject const*), 1, name, [readFunction](TObject const* object) {
+ assert(object);
+ return readFunction(*object);
+ });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject>));
+ setTable<TVarType (std::shared_ptr<TObject>)>(mState, Registry, &typeid(std::shared_ptr<TObject>), 1, name, [readFunction](const std::shared_ptr<TObject>& object) {
+ assert(object);
+ return readFunction(*object);
+ });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject const>));
+ setTable<TVarType (std::shared_ptr<TObject const>)>(mState, Registry, &typeid(std::shared_ptr<TObject const>), 1, name, [readFunction](const std::shared_ptr<TObject const>& object) {
+ assert(object);
+ return readFunction(*object);
+ });
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMemberImpl(const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(name, readFunction);
+
+ setTable<void (TObject&, TVarType)>(mState, Registry, &typeid(TObject), 4, name, [writeFunction](TObject& object, const TVarType& value) {
+ writeFunction(object, value);
+ });
+
+ setTable<void (TObject*, TVarType)>(mState, Registry, &typeid(TObject*), 4, name, [writeFunction](TObject* object, const TVarType& value) {
+ assert(object);
+ writeFunction(*object, value);
+ });
+
+ setTable<void (std::shared_ptr<TObject>, TVarType)>(mState, Registry, &typeid(std::shared_ptr<TObject>), 4, name, [writeFunction](std::shared_ptr<TObject> object, const TVarType& value) {
+ assert(object);
+ writeFunction(*object, value);
+ });
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMemberImpl(tag<TVarType (TObject::*)>, const std::string& name, TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(name, std::move(readFunction), std::move(writeFunction));
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMemberImpl(tag<TVarType(TObject::*)>, const std::string& name, TReadFunction readFunction)
+ {
+ registerMemberImpl<TObject, TVarType>(name, std::move(readFunction));
+ }
+
+ // the "registerMember" public functions call this one
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMemberImpl(TReadFunction readFunction)
+ {
+ checkTypeRegistration(mState, &typeid(TObject));
+ setTable<TVarType (TObject const&, std::string)>(mState, Registry, &typeid(TObject), 2, [readFunction](TObject const& object, const std::string& name) {
+ return readFunction(object, name);
+ });
+
+ checkTypeRegistration(mState, &typeid(TObject*));
+ setTable<TVarType (TObject*, std::string)>(mState, Registry, &typeid(TObject*), 2, [readFunction](TObject const* object, const std::string& name) {
+ assert(object);
+ return readFunction(*object, name);
+ });
+
+ checkTypeRegistration(mState, &typeid(TObject const*));
+ setTable<TVarType (TObject const*, std::string)>(mState, Registry, &typeid(TObject const*), 2, [readFunction](TObject const* object, const std::string& name) {
+ assert(object);
+ return readFunction(*object, name);
+ });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject>));
+ setTable<TVarType (std::shared_ptr<TObject>, std::string)>(mState, Registry, &typeid(std::shared_ptr<TObject>), 2, [readFunction](const std::shared_ptr<TObject>& object, const std::string& name) {
+ assert(object);
+ return readFunction(*object, name);
+ });
+
+ checkTypeRegistration(mState, &typeid(std::shared_ptr<TObject const>));
+ setTable<TVarType (std::shared_ptr<TObject const>, std::string)>(mState, Registry, &typeid(std::shared_ptr<TObject const>), 2, [readFunction](const std::shared_ptr<TObject const>& object, const std::string& name) {
+ assert(object);
+ return readFunction(*object, name);
+ });
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMemberImpl(TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(readFunction);
+
+ setTable<void (TObject&, std::string, TVarType)>(mState, Registry, &typeid(TObject), 5, [writeFunction](TObject& object, const std::string& name, const TVarType& value) {
+ writeFunction(object, name, value);
+ });
+
+ setTable<void (TObject*, std::string, TVarType)>(mState, Registry, &typeid(TObject*), 2, [writeFunction](TObject* object, const std::string& name, const TVarType& value) {
+ assert(object);
+ writeFunction(*object, name, value);
+ });
+
+ setTable<void (std::shared_ptr<TObject>, std::string, TVarType)>(mState, Registry, &typeid(std::shared_ptr<TObject>), 2, [writeFunction](const std::shared_ptr<TObject>& object, const std::string& name, const TVarType& value) {
+ assert(object);
+ writeFunction(*object, name, value);
+ });
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction, typename TWriteFunction>
+ void registerMemberImpl(tag<TVarType (TObject::*)>, TReadFunction readFunction, TWriteFunction writeFunction)
+ {
+ registerMemberImpl<TObject,TVarType>(std::move(readFunction), std::move(writeFunction));
+ }
+
+ template<typename TObject, typename TVarType, typename TReadFunction>
+ void registerMemberImpl(tag<TVarType(TObject::*)>, TReadFunction readFunction)
+ {
+ registerMemberImpl<TObject, TVarType>(std::move(readFunction));
+ }
+
+
+ /**************************************************/
+ /* LOADING AND CALLING */
+ /**************************************************/
+ // this function loads data from the stream and pushes a function at the top of the stack
+ // throws in case of syntax error
+ static PushedObject load(lua_State* state, std::istream& code) {
+ // since the lua_load function requires a static function, we use this structure
+ // the Reader structure is at the same time an object storing an istream and a buffer,
+ // and a static function provider
+ struct Reader {
+ Reader(std::istream& str) : stream(str) {}
+ std::istream& stream;
+ std::array<char,512> buffer;
+
+ // read function ; "data" must be an instance of Reader
+ static const char* read(lua_State* l, void* data, size_t* size) {
+ assert(size != nullptr);
+ assert(data != nullptr);
+ Reader& me = *static_cast<Reader*>(data);
+ if (me.stream.eof()) { *size = 0; return nullptr; }
+
+ me.stream.read(me.buffer.data(), me.buffer.size());
+ *size = static_cast<size_t>(me.stream.gcount()); // gcount could return a value larger than a size_t, but its maximum is me.buffer.size() so there's no problem
+ return me.buffer.data();
+ }
+ };
+
+ // we create an instance of Reader, and we call lua_load
+ Reader reader{code};
+ const auto loadReturnValue = lua_load(state, &Reader::read, &reader, "chunk"
+# if LUA_VERSION_NUM >= 502
+ , nullptr
+# endif
+ );
+
+ // now we have to check return value
+ if (loadReturnValue != 0) {
+ // there was an error during loading, an error message was pushed on the stack
+ const std::string errorMsg = lua_tostring(state, -1);
+ lua_pop(state, 1);
+ if (loadReturnValue == LUA_ERRMEM)
+ throw std::bad_alloc();
+ else if (loadReturnValue == LUA_ERRSYNTAX)
+ throw SyntaxErrorException{errorMsg};
+ throw std::runtime_error("Error while calling lua_load: " + errorMsg);
+ }
+
+ return PushedObject{state, 1};
+ }
+
+ // this function loads data and pushes a function at the top of the stack
+ // throws in case of syntax error
+ static PushedObject load(lua_State* state, const char* code) {
+ auto loadReturnValue = luaL_loadstring(state, code);
+
+ // now we have to check return value
+ if (loadReturnValue != 0) {
+ // there was an error during loading, an error message was pushed on the stack
+ const std::string errorMsg = lua_tostring(state, -1);
+ lua_pop(state, 1);
+ if (loadReturnValue == LUA_ERRMEM)
+ throw std::bad_alloc();
+ else if (loadReturnValue == LUA_ERRSYNTAX)
+ throw SyntaxErrorException{errorMsg};
+ throw std::runtime_error("Error while calling lua_load: " + errorMsg);
+ }
+
+ return PushedObject{state, 1};
+ }
+
+ // this function calls what is on the top of the stack and removes it (just like lua_call)
+ // if an exception is triggered, the top of the stack will be removed anyway
+ template<typename TReturnType, typename... TParameters>
+ static auto call(lua_State* state, PushedObject toCall, TParameters&&... input)
+ -> TReturnType
+ {
+ typedef typename Tupleizer<TReturnType>::type
+ RealReturnType;
+
+ // we push the parameters on the stack
+ auto inArguments = Pusher<std::tuple<TParameters...>>::push(state, std::forward_as_tuple((input)...));
+
+ //
+ const int outArgumentsCount = std::tuple_size<RealReturnType>::value;
+ auto outArguments = callRaw(state, std::move(toCall) + std::move(inArguments), outArgumentsCount);
+
+ // pcall succeeded, we pop the returned values and return them
+ return readTopAndPop<TReturnType>(state, std::move(outArguments));
+ }
+
+ // this function just calls lua_pcall and checks for errors
+ static PushedObject callRaw(lua_State* state, PushedObject functionAndArguments, const int outArguments)
+ {
+ // calling pcall automatically pops the parameters and pushes output
+ const auto pcallReturnValue = lua_pcall(state, functionAndArguments.getNum() - 1, outArguments, 0);
+ functionAndArguments.release();
+
+ // if pcall failed, analyzing the problem and throwing
+ if (pcallReturnValue != 0) {
+ PushedObject errorCode{state, 1};
+
+ // an error occured during execution, either an error message or a std::exception_ptr was pushed on the stack
+ if (pcallReturnValue == LUA_ERRMEM) {
+ throw std::bad_alloc{};
+
+ } else if (pcallReturnValue == LUA_ERRRUN) {
+ if (lua_isstring(state, 1)) {
+ // the error is a string
+ const auto str = readTopAndPop<std::string>(state, std::move(errorCode));
+ throw ExecutionErrorException{str};
+
+ } else {
+ // an exception_ptr was pushed on the stack
+ // rethrowing it with an additional ExecutionErrorException
+ try {
+ if (const auto exp = readTopAndPop<std::exception_ptr>(state, std::move(errorCode))) {
+ std::rethrow_exception(exp);
+ }
+ } catch(...) {
+ std::throw_with_nested(ExecutionErrorException{"Exception thrown by a callback function called by Lua"});
+ }
+ throw ExecutionErrorException{"Unknown Lua error"};
+ }
+ }
+ }
+
+ return PushedObject{state, outArguments};
+ }
+
+
+ /**************************************************/
+ /* PUSH FUNCTIONS */
+ /**************************************************/
+ template<typename T>
+ static PushedObject push(lua_State* state, T&& value)
+ {
+ return Pusher<typename std::decay<T>::type>::push(state, std::forward<T>(value));
+ }
+
+ // the Pusher structures allow you to push a value on the stack
+ // - static const int minSize : minimum size on the stack that the value can have
+ // - static const int maxSize : maximum size on the stack that the value can have
+ // - static int push(const LuaContext&, ValueType) : pushes the value on the stack and returns the size on the stack
+
+ // implementation for custom objects
+ template<typename TType, typename = void>
+ struct Pusher {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ template<typename TType2>
+ static PushedObject push(lua_State* state, TType2&& value) noexcept {
+ // this function is called when lua's garbage collector wants to destroy our object
+ // we simply call its destructor
+ const auto garbageCallbackFunction = [](lua_State* lua) -> int {
+ assert(lua_gettop(lua) == 1);
+ TType* ptr = static_cast<TType*>(lua_touserdata(lua, 1));
+ assert(ptr);
+ ptr->~TType();
+ return 0;
+ };
+
+ // this function will be stored in __index in the metatable
+ const auto indexFunction = [](lua_State* lua) -> int {
+ try {
+ assert(lua_gettop(lua) == 2);
+ assert(lua_isuserdata(lua, 1));
+
+ // searching for a handler
+ lua_pushlightuserdata(lua, const_cast<std::type_info*>(&typeid(TType)));
+ lua_gettable(lua, LUA_REGISTRYINDEX);
+ assert(!lua_isnil(lua, -1));
+
+ // looking into getter functions
+ lua_pushinteger(lua, 0);
+ lua_gettable(lua, -2);
+ lua_pushvalue(lua, 2);
+ lua_gettable(lua, -2);
+ if (!lua_isnil(lua, -1))
+ return 1;
+ lua_pop(lua, 2);
+
+ // looking into getter members
+ lua_pushinteger(lua, 1);
+ lua_gettable(lua, -2);
+ lua_pushvalue(lua, 2);
+ lua_gettable(lua, -2);
+ if (!lua_isnil(lua, -1)) {
+ lua_pushvalue(lua, 1);
+ return callRaw(lua, PushedObject{lua, 2}, 1).release();
+ }
+ lua_pop(lua, 2);
+
+ // looking into default getter
+ lua_pushinteger(lua, 2);
+ lua_gettable(lua, -2);
+ if (lua_isnil(lua, -1))
+ return 1;
+ lua_pushvalue(lua, 1);
+ lua_pushvalue(lua, 2);
+ return callRaw(lua, PushedObject{lua, 3}, 1).release();
+
+ } catch (...) {
+ Pusher<std::exception_ptr>::push(lua, std::current_exception()).release();
+ luaError(lua);
+ }
+ };
+
+ // this function will be stored in __newindex in the metatable
+ const auto newIndexFunction = [](lua_State* lua) -> int {
+ try {
+ assert(lua_gettop(lua) == 3);
+ assert(lua_isuserdata(lua, 1));
+
+ // searching for a handler
+ lua_pushlightuserdata(lua, const_cast<std::type_info*>(&typeid(TType)));
+ lua_rawget(lua, LUA_REGISTRYINDEX);
+ assert(!lua_isnil(lua, -1));
+
+ // looking into setter members
+ lua_pushinteger(lua, 4);
+ lua_rawget(lua, -2);
+ lua_pushvalue(lua, 2);
+ lua_rawget(lua, -2);
+ if (!lua_isnil(lua, -1)) {
+ lua_pushvalue(lua, 1);
+ lua_pushvalue(lua, 3);
+ callRaw(lua, PushedObject{lua, 3}, 0);
+ lua_pop(lua, 2);
+ return 0;
+ }
+ lua_pop(lua, 2);
+
+ // looking into default setter
+ lua_pushinteger(lua, 5);
+ lua_rawget(lua, -2);
+ if (lua_isnil(lua, -1))
+ {
+ lua_pop(lua, 2);
+ lua_pushstring(lua, "No setter found");
+ luaError(lua);
+ }
+ lua_pushvalue(lua, 1);
+ lua_pushvalue(lua, 2);
+ lua_pushvalue(lua, 3);
+ callRaw(lua, PushedObject{lua, 4}, 0);
+ lua_pop(lua, 1);
+ return 0;
+
+ } catch (...) {
+ Pusher<std::exception_ptr>::push(lua, std::current_exception()).release();
+ luaError(lua);
+ }
+ };
+
+ // writing structure for this type into the registry
+ checkTypeRegistration(state, &typeid(TType));
+
+ // creating the object
+ // lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it
+ // and that's what we do with placement-new
+ const auto pointerLocation = static_cast<TType*>(lua_newuserdata(state, sizeof(TType)));
+ new (pointerLocation) TType(std::forward<TType2>(value));
+ PushedObject obj{state, 1};
+
+ // creating the metatable (over the object on the stack)
+ // lua_settable pops the key and value we just pushed, so stack management is easy
+ // all that remains on the stack after these function calls is the metatable
+ lua_newtable(state);
+ PushedObject pushedTable{state, 1};
+
+ // using the garbage collecting function we created above
+ if (!boost::has_trivial_destructor<TType>::value)
+ {
+ lua_pushstring(state, "__gc");
+ lua_pushcfunction(state, garbageCallbackFunction);
+ lua_settable(state, -3);
+ }
+
+ // the _typeid index of the metatable will store the type_info*
+ lua_pushstring(state, "_typeid");
+ lua_pushlightuserdata(state, const_cast<std::type_info*>(&typeid(TType)));
+ lua_settable(state, -3);
+
+ // using the index function we created above
+ lua_pushstring(state, "__index");
+ lua_pushcfunction(state, indexFunction);
+ lua_settable(state, -3);
+
+ // using the newindex function we created above
+ lua_pushstring(state, "__newindex");
+ lua_pushcfunction(state, newIndexFunction);
+ lua_settable(state, -3);
+
+ // at this point, the stack contains the object at offset -2 and the metatable at offset -1
+ // lua_setmetatable will bind the two together and pop the metatable
+ // our custom type remains on the stack (and that's what we want since this is a push function)
+ lua_setmetatable(state, -2);
+ pushedTable.release();
+
+ return std::move(obj);
+ }
+ };
+
+ // this structure has a "size" int static member which is equal to the total of the push min size of all the types
+ template<typename... TTypes>
+ struct PusherTotalMinSize;
+
+ // this structure has a "size" int static member which is equal to the total of the push max size of all the types
+ template<typename... TTypes>
+ struct PusherTotalMaxSize;
+
+ // this structure has a "size" int static member which is equal to the maximum size of the push of all the types
+ template<typename... TTypes>
+ struct PusherMinSize;
+
+ // this structure has a "size" int static member which is equal to the maximum size of the push of all the types
+ template<typename... TTypes>
+ struct PusherMaxSize;
+
+
+ /**************************************************/
+ /* READ FUNCTIONS */
+ /**************************************************/
+ // the "Reader" structures allow to read data from the stack
+ // - the "ReturnType" type is what is returned by the reader, and can be different than the template parameter (especially with references and constness)
+ // - the "read" static function will check and read at the same time, returning an empty optional if it is the wrong type
+
+ template<typename TType, typename = void>
+ struct Reader {
+ typedef typename std::conditional<std::is_pointer<TType>::value, TType, TType&>::type
+ ReturnType;
+
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ if (!test(state, index))
+ return boost::none;
+ return boost::optional<ReturnType>(*static_cast<TType*>(lua_touserdata(state, index)));
+ }
+
+ private:
+ static bool test(lua_State* state, int index)
+ {
+ if (!lua_isuserdata(state, index))
+ return false;
+ if (!lua_getmetatable(state, index))
+ return false;
+
+ // now we have our metatable on the top of the stack
+ // retrieving its _typeid member
+ lua_pushstring(state, "_typeid");
+ lua_gettable(state, -2);
+ const auto storedTypeID = static_cast<const std::type_info*>(lua_touserdata(state, -1));
+ const auto typeIDToCompare = &typeid(TType);
+
+ // if wrong typeid, returning false
+ lua_pop(state, 2);
+ if (storedTypeID != typeIDToCompare)
+ return false;
+
+ return true;
+ }
+ };
+
+ /**
+ * This functions reads multiple values starting at "index" and passes them to the callback
+ */
+ template<typename TRetValue, typename TCallback>
+ static auto readIntoFunction(lua_State* state, tag<TRetValue>, TCallback&& callback, int index)
+ -> TRetValue
+ {
+ return callback();
+ }
+ template<typename TRetValue, typename TCallback, typename TFirstType, typename... TTypes>
+ static auto readIntoFunction(lua_State* state, tag<TRetValue> retValueTag, TCallback&& callback, int index, tag<TFirstType>, tag<TTypes>... othersTags)
+ -> typename std::enable_if<IsOptional<TFirstType>::value, TRetValue>::type
+ {
+ if (index >= 0) {
+ Binder<TCallback, const TFirstType&> binder{ callback, {} };
+ return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...);
+ }
+
+ const auto& firstElem = Reader<typename std::decay<TFirstType>::type>::read(state, index);
+ if (!firstElem)
+ throw WrongTypeException(lua_typename(state, index), typeid(TFirstType));
+
+ Binder<TCallback, const TFirstType&> binder{ callback, *firstElem };
+ return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...);
+ }
+ template<typename TRetValue, typename TCallback, typename TFirstType, typename... TTypes>
+ static auto readIntoFunction(lua_State* state, tag<TRetValue> retValueTag, TCallback&& callback, int index, tag<TFirstType>, tag<TTypes>... othersTags)
+ -> typename std::enable_if<!IsOptional<TFirstType>::value, TRetValue>::type
+ {
+ if (index >= 0)
+ throw std::logic_error("Wrong number of parameters");
+
+ const auto& firstElem = Reader<typename std::decay<TFirstType>::type>::read(state, index);
+ if (!firstElem)
+ throw WrongTypeException(lua_typename(state, index), typeid(TFirstType));
+
+ Binder<TCallback, const TFirstType&> binder{ callback, *firstElem };
+ return readIntoFunction(state, retValueTag, binder, index + 1, othersTags...);
+ }
+
+
+ /**************************************************/
+ /* UTILITIES */
+ /**************************************************/
+ // structure that will ensure that a certain is stored somewhere in the registry
+ struct ValueInRegistry {
+ // this constructor will clone and hold the value at the top of the stack in the registry
+ ValueInRegistry(lua_State* lua) : lua{lua}
+ {
+ lua_pushlightuserdata(lua, this);
+ lua_pushvalue(lua, -2);
+ lua_settable(lua, LUA_REGISTRYINDEX);
+ }
+
+ // removing the function from the registry
+ ~ValueInRegistry()
+ {
+ lua_pushlightuserdata(lua, this);
+ lua_pushnil(lua);
+ lua_settable(lua, LUA_REGISTRYINDEX);
+ }
+
+ // loads the value and puts it at the top of the stack
+ PushedObject pop()
+ {
+ lua_pushlightuserdata(lua, this);
+ lua_gettable(lua, LUA_REGISTRYINDEX);
+ return PushedObject{lua, 1};
+ }
+
+ ValueInRegistry(const ValueInRegistry&) = delete;
+ ValueInRegistry& operator=(const ValueInRegistry&) = delete;
+
+ private:
+ lua_State* lua;
+ };
+
+ // binds the first parameter of a function object
+ template<typename TFunctionObject, typename TFirstParamType>
+ struct Binder {
+ TFunctionObject function;
+ TFirstParamType param;
+
+ template<typename... TParams>
+ auto operator()(TParams&&... params)
+ -> decltype(function(param, std::forward<TParams>(params)...))
+ {
+ return function(param, std::forward<TParams>(params)...);
+ }
+ };
+
+ // turns a type into a tuple
+ // void is turned into std::tuple<>
+ // existing tuples are untouched
+ template<typename T>
+ struct Tupleizer;
+
+ // this structure takes a pointer to a member function type and returns the base function type
+ template<typename TType>
+ struct RemoveMemberPointerFunction { typedef void type; }; // required because of a compiler bug
+
+ // this structure takes any object and detects its function type
+ template<typename TObjectType>
+ struct FunctionTypeDetector { typedef typename RemoveMemberPointerFunction<decltype(&std::decay<TObjectType>::type::operator())>::type type; };
+
+ // this structure takes a function arguments list and has the "min" and the "max" static const member variables, whose value equal to the min and max number of parameters for the function
+ // the only case where "min != max" is with boost::optional at the end of the list
+ template<typename... TArgumentsList>
+ struct FunctionArgumentsCounter {};
+
+ // true is the template parameter is a boost::optional
+ template<typename T>
+ struct IsOptional : public std::false_type {};
+};
+
+/// @deprecated
+static LuaContext::EmptyArray_t ATTR_UNUSED
+ LuaEmptyArray {};
+/// @deprecated
+static LuaContext::Metatable_t ATTR_UNUSED
+ LuaMetatable {};
+
+/**************************************************/
+/* PARTIAL IMPLEMENTATIONS */
+/**************************************************/
+template<>
+inline auto LuaContext::readTopAndPop<void>(lua_State* state, PushedObject obj)
+ -> void
+{
+}
+
+// this structure takes a template parameter T
+// if T is a tuple, it returns T ; if T is not a tuple, it returns std::tuple<T>
+// we have to use this structure because std::tuple<std::tuple<...>> triggers a bug in both MSVC++ and GCC
+template<typename T>
+struct LuaContext::Tupleizer { typedef std::tuple<T> type; };
+template<typename... Args>
+struct LuaContext::Tupleizer<std::tuple<Args...>> { typedef std::tuple<Args...> type; };
+template<>
+struct LuaContext::Tupleizer<void> { typedef std::tuple<> type; };
+
+// this structure takes any object and detects its function type
+template<typename TRetValue, typename... TParameters>
+struct LuaContext::FunctionTypeDetector<TRetValue (TParameters...)> { typedef TRetValue type(TParameters...); };
+template<typename TObjectType>
+struct LuaContext::FunctionTypeDetector<TObjectType*> { typedef typename FunctionTypeDetector<TObjectType>::type type; };
+
+// this structure takes a pointer to a member function type and returns the base function type
+template<typename TType, typename TRetValue, typename... TParameters>
+struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...)> { typedef TRetValue type(TParameters...); };
+template<typename TType, typename TRetValue, typename... TParameters>
+struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) const> { typedef TRetValue type(TParameters...); };
+template<typename TType, typename TRetValue, typename... TParameters>
+struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) volatile> { typedef TRetValue type(TParameters...); };
+template<typename TType, typename TRetValue, typename... TParameters>
+struct LuaContext::RemoveMemberPointerFunction<TRetValue (TType::*)(TParameters...) const volatile> { typedef TRetValue type(TParameters...); };
+
+// implementation of PusherTotalMinSize
+template<typename TFirst, typename... TTypes>
+struct LuaContext::PusherTotalMinSize<TFirst, TTypes...> { static const int size = Pusher<typename std::decay<TFirst>::type>::minSize + PusherTotalMinSize<TTypes...>::size; };
+template<>
+struct LuaContext::PusherTotalMinSize<> { static const int size = 0; };
+
+// implementation of PusherTotalMaxSize
+template<typename TFirst, typename... TTypes>
+struct LuaContext::PusherTotalMaxSize<TFirst, TTypes...> { static const int size = Pusher<typename std::decay<TFirst>::type>::maxSize + PusherTotalMaxSize<TTypes...>::size; };
+template<>
+struct LuaContext::PusherTotalMaxSize<> { static const int size = 0; };
+
+// implementation of PusherMinSize
+template<typename TFirst, typename TSecond, typename... TTypes>
+struct LuaContext::PusherMinSize<TFirst, TSecond, TTypes...>
+{
+ static const int size = Pusher<typename std::decay<TFirst>::type>::minSize < Pusher<typename std::decay<TSecond>::type>::minSize
+ ?
+ PusherMinSize<typename std::decay<TFirst>::type, TTypes...>::size
+ :
+ PusherMinSize<typename std::decay<TSecond>::type, TTypes...>::size;
+};
+
+template<typename TFirst>
+struct LuaContext::PusherMinSize<TFirst> { static const int size = Pusher<typename std::decay<TFirst>::type>::minSize; };
+
+// implementation of PusherMaxSize
+template<typename TFirst, typename... TTypes>
+struct LuaContext::PusherMaxSize<TFirst, TTypes...> { static const int size = Pusher<typename std::decay<TFirst>::type>::maxSize > PusherTotalMaxSize<TTypes...>::size ? Pusher<typename std::decay<TFirst>::type>::maxSize : PusherMaxSize<TTypes...>::size; };
+template<>
+struct LuaContext::PusherMaxSize<> { static const int size = 0; };
+
+// implementation of FunctionArgumentsCounter
+template<typename TFirst, typename... TParams>
+struct LuaContext::FunctionArgumentsCounter<TFirst, TParams...> {
+ typedef FunctionArgumentsCounter<TParams...>
+ SubType;
+ static const int min = (IsOptional<TFirst>::value && SubType::min == 0) ? 0 : 1 + SubType::min;
+ static const int max = 1 + SubType::max;
+};
+template<>
+struct LuaContext::FunctionArgumentsCounter<> {
+ static const int min = 0;
+ static const int max = 0;
+};
+
+// implementation of IsOptional
+template<typename T>
+struct LuaContext::IsOptional<boost::optional<T>> : public std::true_type {};
+
+// implementation of LuaFunctionCaller
+template<typename TFunctionType>
+class LuaContext::LuaFunctionCaller { static_assert(std::is_function<TFunctionType>::value, "Template parameter of LuaFunctionCaller must be a function type"); };
+template<typename TRetValue, typename... TParams>
+class LuaContext::LuaFunctionCaller<TRetValue (TParams...)>
+{
+public:
+ TRetValue operator()(TParams&&... params) const
+ {
+ auto obj = valueHolder->pop();
+ return call<TRetValue>(state, std::move(obj), std::forward<TParams>(params)...);
+ }
+
+private:
+ std::shared_ptr<ValueInRegistry> valueHolder;
+ lua_State* state;
+
+private:
+ friend LuaContext;
+ explicit LuaFunctionCaller(lua_State* state) :
+ valueHolder(std::make_shared<ValueInRegistry>(state)),
+ state(state)
+ {}
+};
+
+
+/**************************************************/
+/* PUSH FUNCTIONS */
+/**************************************************/
+// specializations of the Pusher structure
+
+// boolean
+template<>
+struct LuaContext::Pusher<bool> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, bool value) noexcept {
+ lua_pushboolean(state, value);
+ return PushedObject{state, 1};
+ }
+};
+
+// string
+template<>
+struct LuaContext::Pusher<std::string> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::string& value) noexcept {
+ lua_pushlstring(state, value.c_str(), value.length());
+ return PushedObject{state, 1};
+ }
+};
+
+// const char*
+template<>
+struct LuaContext::Pusher<const char*> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const char* value) noexcept {
+ lua_pushstring(state, value);
+ return PushedObject{state, 1};
+ }
+};
+
+// const char[N]
+template<int N>
+struct LuaContext::Pusher<const char[N]> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const char* value) noexcept {
+ lua_pushstring(state, value);
+ return PushedObject{state, 1};
+ }
+};
+
+// floating numbers
+template<typename T>
+struct LuaContext::Pusher<T, typename std::enable_if<std::is_floating_point<T>::value>::type> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, T value) noexcept {
+ lua_pushnumber(state, value);
+ return PushedObject{state, 1};
+ }
+};
+
+// integers
+template<typename T>
+struct LuaContext::Pusher<T, typename std::enable_if<std::is_integral<T>::value>::type> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, T value) noexcept {
+ lua_pushinteger(state, value);
+ return PushedObject{state, 1};
+ }
+};
+
+// nil
+template<>
+struct LuaContext::Pusher<std::nullptr_t> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, std::nullptr_t value) noexcept {
+ assert(value == nullptr);
+ lua_pushnil(state);
+ return PushedObject{state, 1};
+ }
+};
+
+// empty arrays
+template<>
+struct LuaContext::Pusher<LuaContext::EmptyArray_t> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, EmptyArray_t) noexcept {
+ lua_newtable(state);
+ return PushedObject{state, 1};
+ }
+};
+
+// std::type_info* is a lightuserdata
+template<>
+struct LuaContext::Pusher<const std::type_info*> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::type_info* ptr) noexcept {
+ lua_pushlightuserdata(state, const_cast<std::type_info*>(ptr));
+ return PushedObject{state, 1};
+ }
+};
+
+// thread
+template<>
+struct LuaContext::Pusher<LuaContext::ThreadID> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const LuaContext::ThreadID& value) noexcept {
+ lua_pushthread(value.state);
+ return PushedObject{state, 1};
+ }
+};
+
+// maps
+template<typename TKey, typename TValue>
+struct LuaContext::Pusher<std::map<TKey,TValue>> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::map<TKey,TValue>& value) noexcept {
+ static_assert(Pusher<typename std::decay<TKey>::type>::minSize == 1 && Pusher<typename std::decay<TKey>::type>::maxSize == 1, "Can't push multiple elements for a table key");
+ static_assert(Pusher<typename std::decay<TValue>::type>::minSize == 1 && Pusher<typename std::decay<TValue>::type>::maxSize == 1, "Can't push multiple elements for a table value");
+
+ auto obj = Pusher<EmptyArray_t>::push(state, EmptyArray);
+
+ for (auto i = value.begin(), e = value.end(); i != e; ++i)
+ setTable<TValue>(state, obj, i->first, i->second);
+
+ return std::move(obj);
+ }
+};
+
+// unordered_maps
+template<typename TKey, typename TValue>
+struct LuaContext::Pusher<std::unordered_map<TKey,TValue>> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::unordered_map<TKey,TValue>& value) noexcept {
+ static_assert(Pusher<typename std::decay<TKey>::type>::minSize == 1 && Pusher<typename std::decay<TKey>::type>::maxSize == 1, "Can't push multiple elements for a table key");
+ static_assert(Pusher<typename std::decay<TValue>::type>::minSize == 1 && Pusher<typename std::decay<TValue>::type>::maxSize == 1, "Can't push multiple elements for a table value");
+
+ auto obj = Pusher<EmptyArray_t>::push(state, EmptyArray);
+
+ for (auto i = value.begin(), e = value.end(); i != e; ++i)
+ setTable<TValue>(state, obj, i->first, i->second);
+
+ return std::move(obj);
+ }
+};
+
+// vectors of pairs
+template<typename TType1, typename TType2>
+struct LuaContext::Pusher<std::vector<std::pair<TType1,TType2>>> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::vector<std::pair<TType1,TType2>>& value) noexcept {
+ static_assert(Pusher<typename std::decay<TType1>::type>::minSize == 1 && Pusher<typename std::decay<TType1>::type>::maxSize == 1, "Can't push multiple elements for a table key");
+ static_assert(Pusher<typename std::decay<TType2>::type>::minSize == 1 && Pusher<typename std::decay<TType2>::type>::maxSize == 1, "Can't push multiple elements for a table value");
+
+ auto obj = Pusher<EmptyArray_t>::push(state, EmptyArray);
+
+ for (auto i = value.begin(), e = value.end(); i != e; ++i)
+ setTable<TType2>(state, obj, i->first, i->second);
+
+ return std::move(obj);
+ }
+};
+
+// vectors
+template<typename TType>
+struct LuaContext::Pusher<std::vector<TType>> {
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ static PushedObject push(lua_State* state, const std::vector<TType>& value) noexcept {
+ static_assert(Pusher<typename std::decay<TType>::type>::minSize == 1 && Pusher<typename std::decay<TType>::type>::maxSize == 1, "Can't push multiple elements for a table value");
+
+ auto obj = Pusher<EmptyArray_t>::push(state, EmptyArray);
+
+ for (unsigned int i = 0; i < value.size(); ++i)
+ setTable<TType>(state, obj, i + 1, value[i]);
+
+ return std::move(obj);
+ }
+};
+
+// unique_ptr
+template<typename TType>
+struct LuaContext::Pusher<std::unique_ptr<TType>> {
+ static const int minSize = Pusher<std::shared_ptr<TType>>::minSize;
+ static const int maxSize = Pusher<std::shared_ptr<TType>>::maxSize;
+
+ static PushedObject push(lua_State* state, std::unique_ptr<TType> value) noexcept {
+ return Pusher<std::shared_ptr<TType>>::push(state, std::move(value));
+ }
+};
+
+// enum
+template<typename TEnum>
+struct LuaContext::Pusher<TEnum, typename std::enable_if<std::is_enum<TEnum>::value>::type> {
+ #if !defined(__clang__) || __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ > 3)
+ typedef typename std::underlying_type<TEnum>::type
+ RealType;
+ #else
+ // implementation when std::underlying_type is not supported
+ typedef unsigned long
+ RealType;
+ #endif
+
+ static const int minSize = Pusher<RealType>::minSize;
+ static const int maxSize = Pusher<RealType>::maxSize;
+
+ static PushedObject push(lua_State* state, TEnum value) noexcept {
+ return Pusher<RealType>::push(state, static_cast<RealType>(value));
+ }
+};
+
+// any function
+// this specialization is not directly called, but is called by other specializations
+template<typename TReturnType, typename... TParameters>
+struct LuaContext::Pusher<TReturnType (TParameters...)>
+{
+ static const int minSize = 1;
+ static const int maxSize = 1;
+
+ // counts the number of arguments
+ typedef FunctionArgumentsCounter<TParameters...>
+ LocalFunctionArgumentsCounter;
+
+ // this is the version of "push" for non-trivially destructible function objects
+ template<typename TFunctionObject>
+ static auto push(lua_State* state, TFunctionObject fn) noexcept
+ -> typename std::enable_if<!boost::has_trivial_destructor<TFunctionObject>::value, PushedObject>::type
+ {
+ // TODO: is_move_constructible not supported by some compilers
+ //static_assert(std::is_move_constructible<TFunctionObject>::value, "The function object must be move-constructible");
+
+ // when the lua script calls the thing we will push on the stack, we want "fn" to be executed
+ // if we used lua's cfunctions system, we could not detect when the function is no longer in use, which could cause problems
+ // so we use userdata instead
+
+ // this function is called when the lua script tries to call our custom data type
+ // we transfer execution to the "callback" function below
+ const auto callCallback = [](lua_State* lua) -> int {
+ assert(lua_gettop(lua) >= 1);
+ assert(lua_isuserdata(lua, 1));
+ auto function = static_cast<TFunctionObject*>(lua_touserdata(lua, 1));
+ assert(function);
+
+ return callback(lua, function, lua_gettop(lua) - 1).release();
+ };
+
+ // this one is called when lua's garbage collector no longer needs our custom data type
+ // we call the function object's destructor
+ const auto garbageCallback = [](lua_State* lua) -> int {
+ assert(lua_gettop(lua) == 1);
+ auto function = static_cast<TFunctionObject*>(lua_touserdata(lua, 1));
+ assert(function);
+ function->~TFunctionObject();
+ return 0;
+ };
+
+ // creating the object
+ // lua_newuserdata allocates memory in the internals of the lua library and returns it so we can fill it
+ // and that's what we do with placement-new
+ const auto functionLocation = static_cast<TFunctionObject*>(lua_newuserdata(state, sizeof(TFunctionObject)));
+ new (functionLocation) TFunctionObject(std::move(fn));
+
+ // creating the metatable (over the object on the stack)
+ // lua_settable pops the key and value we just pushed, so stack management is easy
+ // all that remains on the stack after these function calls is the metatable
+ lua_newtable(state);
+ lua_pushstring(state, "__call");
+ lua_pushcfunction(state, callCallback);
+ lua_settable(state, -3);
+
+ lua_pushstring(state, "__gc");
+ lua_pushcfunction(state, garbageCallback);
+ lua_settable(state, -3);
+
+ // at this point, the stack contains the object at offset -2 and the metatable at offset -1
+ // lua_setmetatable will bind the two together and pop the metatable
+ // our custom function remains on the stack (and that's what we want)
+ lua_setmetatable(state, -2);
+
+ return PushedObject{state, 1};
+ }
+
+ // this is the version of "push" for trivially destructible objects
+ template<typename TFunctionObject>
+ static auto push(lua_State* state, TFunctionObject fn) noexcept
+ -> typename std::enable_if<boost::has_trivial_destructor<TFunctionObject>::value, PushedObject>::type
+ {
+ // TODO: is_move_constructible not supported by some compilers
+ //static_assert(std::is_move_constructible<TFunctionObject>::value, "The function object must be move-constructible");
+
+ // when the lua script calls the thing we will push on the stack, we want "fn" to be executed
+ // since "fn" doesn't need to be destroyed, we simply push it on the stack
+
+ // this is the cfunction that is the callback
+ const auto function = [](lua_State* state) -> int
+ {
+ // the function object is an upvalue
+ const auto toCall = static_cast<TFunctionObject*>(lua_touserdata(state, lua_upvalueindex(1)));
+ return callback(state, toCall, lua_gettop(state)).release();
+ };
+
+ // we copy the function object onto the stack
+ const auto functionObjectLocation = static_cast<TFunctionObject*>(lua_newuserdata(state, sizeof(TFunctionObject)));
+ new (functionObjectLocation) TFunctionObject(std::move(fn));
+
+ // pushing the function with the function object as upvalue
+ lua_pushcclosure(state, function, 1);
+ return PushedObject{state, 1};
+ }
+
+ // this is the version of "push" for pointer to functions
+ static auto push(lua_State* state, TReturnType (*fn)(TParameters...)) noexcept
+ -> PushedObject
+ {
+ // when the lua script calls the thing we will push on the stack, we want "fn" to be executed
+ // since "fn" doesn't need to be destroyed, we simply push it on the stack
+
+ // this is the cfunction that is the callback
+ const auto function = [](lua_State* state) -> int
+ {
+ // the function object is an upvalue
+ const auto toCall = reinterpret_cast<TReturnType (*)(TParameters...)>(lua_touserdata(state, lua_upvalueindex(1)));
+ return callback(state, toCall, lua_gettop(state)).release();
+ };
+
+ // we copy the function object onto the stack
+ lua_pushlightuserdata(state, reinterpret_cast<void*>(fn));
+
+ // pushing the function with the function object as upvalue
+ lua_pushcclosure(state, function, 1);
+ return PushedObject{state, 1};
+ }
+
+ // this is the version of "push" for references to functions
+ static auto push(lua_State* state, TReturnType (&fn)(TParameters...)) noexcept
+ -> PushedObject
+ {
+ return push(state, &fn);
+ }
+
+private:
+ // callback that calls the function object
+ // this function is used by the callbacks and handles loading arguments from the stack and pushing the return value back
+ template<typename TFunctionObject>
+ static auto callback(lua_State* state, TFunctionObject* toCall, int argumentsCount)
+ -> PushedObject
+ {
+ // checking if number of parameters is correct
+ if (argumentsCount < LocalFunctionArgumentsCounter::min) {
+ // if not, using lua_error to return an error
+ luaL_where(state, 1);
+ lua_pushstring(state, "This function requires at least ");
+ lua_pushnumber(state, LocalFunctionArgumentsCounter::min);
+ lua_pushstring(state, " parameter(s)");
+ lua_concat(state, 4);
+ luaError(state);
+
+ } else if (argumentsCount > LocalFunctionArgumentsCounter::max) {
+ // if not, using lua_error to return an error
+ luaL_where(state, 1);
+ lua_pushstring(state, "This function requires at most ");
+ lua_pushnumber(state, LocalFunctionArgumentsCounter::max);
+ lua_pushstring(state, " parameter(s)");
+ lua_concat(state, 4);
+ luaError(state);
+ }
+
+ // calling the function
+ try {
+ return callback2(state, *toCall, argumentsCount);
+
+ } catch (const WrongTypeException& ex) {
+ // wrong parameter type, using lua_error to return an error
+ luaL_where(state, 1);
+ lua_pushstring(state, "Unable to convert parameter from ");
+ lua_pushstring(state, ex.luaType.c_str());
+ lua_pushstring(state, " to ");
+ lua_pushstring(state, ex.destination.name());
+ lua_concat(state, 4);
+ luaError(state);
+
+ } catch (...) {
+ Pusher<std::exception_ptr>::push(state, std::current_exception()).release();
+ luaError(state);
+ }
+ }
+
+ template<typename TFunctionObject>
+ static auto callback2(lua_State* state, TFunctionObject&& toCall, int argumentsCount)
+ -> typename std::enable_if<!std::is_void<TReturnType>::value && !std::is_void<TFunctionObject>::value, PushedObject>::type
+ {
+ // pushing the result on the stack and returning number of pushed elements
+ typedef Pusher<typename std::decay<TReturnType>::type>
+ P;
+ return P::push(state, readIntoFunction(state, tag<TReturnType>{}, toCall, -argumentsCount, tag<TParameters>{}...));
+ }
+
+ template<typename TFunctionObject>
+ static auto callback2(lua_State* state, TFunctionObject&& toCall, int argumentsCount)
+ -> typename std::enable_if<std::is_void<TReturnType>::value && !std::is_void<TFunctionObject>::value, PushedObject>::type
+ {
+ readIntoFunction(state, tag<TReturnType>{}, toCall, -argumentsCount, tag<TParameters>{}...);
+ return PushedObject{state, 0};
+ }
+};
+
+// C function pointers
+template<typename TReturnType, typename... TParameters>
+struct LuaContext::Pusher<TReturnType (*)(TParameters...)>
+{
+ // using the function-pushing implementation
+ typedef Pusher<TReturnType (TParameters...)>
+ SubPusher;
+ static const int minSize = SubPusher::minSize;
+ static const int maxSize = SubPusher::maxSize;
+
+ template<typename TType>
+ static PushedObject push(lua_State* state, TType value) noexcept {
+ return SubPusher::push(state, value);
+ }
+};
+
+// C function references
+template<typename TReturnType, typename... TParameters>
+struct LuaContext::Pusher<TReturnType (&)(TParameters...)>
+{
+ // using the function-pushing implementation
+ typedef Pusher<TReturnType(TParameters...)>
+ SubPusher;
+ static const int minSize = SubPusher::minSize;
+ static const int maxSize = SubPusher::maxSize;
+
+ template<typename TType>
+ static PushedObject push(lua_State* state, TType value) noexcept {
+ return SubPusher::push(state, value);
+ }
+};
+
+// std::function
+template<typename TReturnType, typename... TParameters>
+struct LuaContext::Pusher<std::function<TReturnType (TParameters...)>>
+{
+ // using the function-pushing implementation
+ typedef Pusher<TReturnType (TParameters...)>
+ SubPusher;
+ static const int minSize = SubPusher::minSize;
+ static const int maxSize = SubPusher::maxSize;
+
+ static PushedObject push(lua_State* state, const std::function<TReturnType (TParameters...)>& value) noexcept {
+ return SubPusher::push(state, value);
+ }
+};
+
+// boost::variant
+template<typename... TTypes>
+struct LuaContext::Pusher<boost::variant<TTypes...>>
+{
+ static const int minSize = PusherMinSize<TTypes...>::size;
+ static const int maxSize = PusherMaxSize<TTypes...>::size;
+
+ static PushedObject push(lua_State* state, const boost::variant<TTypes...>& value) noexcept {
+ PushedObject obj{state, 0};
+ VariantWriter writer{state, obj};
+ value.apply_visitor(writer);
+ return std::move(obj);
+ }
+
+private:
+ struct VariantWriter : public boost::static_visitor<> {
+ template<typename TType>
+ void operator()(TType value) noexcept
+ {
+ obj = Pusher<typename std::decay<TType>::type>::push(state, std::move(value));
+ }
+
+ VariantWriter(lua_State* state, PushedObject& obj) : state(state), obj(obj) {}
+ lua_State* state;
+ PushedObject& obj;
+ };
+};
+
+// boost::optional
+template<typename TType>
+struct LuaContext::Pusher<boost::optional<TType>> {
+ typedef Pusher<typename std::decay<TType>::type>
+ UnderlyingPusher;
+
+ static const int minSize = UnderlyingPusher::minSize < 1 ? UnderlyingPusher::minSize : 1;
+ static const int maxSize = UnderlyingPusher::maxSize > 1 ? UnderlyingPusher::maxSize : 1;
+
+ static PushedObject push(lua_State* state, const boost::optional<TType>& value) noexcept {
+ if (value) {
+ return UnderlyingPusher::push(state, value.get());
+ } else {
+ lua_pushnil(state);
+ return PushedObject{state, 1};
+ }
+ }
+};
+
+// tuple
+template<typename... TTypes>
+struct LuaContext::Pusher<std::tuple<TTypes...>> {
+ // TODO: NOT EXCEPTION SAFE /!\ //
+ static const int minSize = PusherTotalMinSize<TTypes...>::size;
+ static const int maxSize = PusherTotalMaxSize<TTypes...>::size;
+
+ static PushedObject push(lua_State* state, const std::tuple<TTypes...>& value) noexcept {
+ return PushedObject{state, push2(state, value, std::integral_constant<int,0>{})};
+ }
+
+ static PushedObject push(lua_State* state, std::tuple<TTypes...>&& value) noexcept {
+ return PushedObject{state, push2(state, std::move(value), std::integral_constant<int,0>{})};
+ }
+
+private:
+ template<int N>
+ static int push2(lua_State* state, const std::tuple<TTypes...>& value, std::integral_constant<int,N>) noexcept {
+ typedef typename std::tuple_element<N,std::tuple<TTypes...>>::type ElemType;
+
+ return Pusher<typename std::decay<ElemType>::type>::push(state, std::get<N>(value)).release() +
+ push2(state, value, std::integral_constant<int,N+1>{});
+ }
+
+ template<int N>
+ static int push2(lua_State* state, std::tuple<TTypes...>&& value, std::integral_constant<int,N>) noexcept {
+ typedef typename std::tuple_element<N,std::tuple<TTypes...>>::type ElemType;
+
+ return Pusher<typename std::decay<ElemType>::type>::push(state, std::move(std::get<N>(value))).release() +
+ push2(state, std::move(value), std::integral_constant<int,N+1>{});
+ }
+
+ static int push2(lua_State* state, const std::tuple<TTypes...>&, std::integral_constant<int,sizeof...(TTypes)>) noexcept {
+ return 0;
+ }
+
+ static int push2(lua_State* state, std::tuple<TTypes...>&&, std::integral_constant<int,sizeof...(TTypes)>) noexcept {
+ return 0;
+ }
+};
+
+/**************************************************/
+/* READ FUNCTIONS */
+/**************************************************/
+// specializations of the Reader structures
+
+// reading null
+template<>
+struct LuaContext::Reader<std::nullptr_t>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::nullptr_t>
+ {
+ if (!lua_isnil(state, index))
+ return boost::none;
+ return nullptr;
+ }
+};
+
+// integrals
+template<typename TType>
+struct LuaContext::Reader<
+ TType,
+ typename std::enable_if<std::is_integral<TType>::value>::type
+ >
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<TType>
+ {
+# if LUA_VERSION_NUM >= 502
+
+ int success;
+ auto value = lua_tointegerx(state, index, &success);
+ if (success == 0)
+ return boost::none;
+ return static_cast<TType>(value);
+
+# else
+
+ if (!lua_isnumber(state, index))
+ return boost::none;
+ return static_cast<TType>(lua_tointeger(state, index));
+
+# endif
+ }
+};
+
+// floating points
+template<typename TType>
+struct LuaContext::Reader<
+ TType,
+ typename std::enable_if<std::is_floating_point<TType>::value>::type
+ >
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<TType>
+ {
+# if LUA_VERSION_NUM >= 502
+
+ int success;
+ auto value = lua_tonumberx(state, index, &success);
+ if (success == 0)
+ return boost::none;
+ return static_cast<TType>(value);
+
+# else
+
+ if (!lua_isnumber(state, index))
+ return boost::none;
+ return static_cast<TType>(lua_tonumber(state, index));
+
+# endif
+ }
+};
+
+// boolean
+template<>
+struct LuaContext::Reader<bool>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<bool>
+ {
+ if (!lua_isboolean(state, index))
+ return boost::none;
+ return lua_toboolean(state, index) != 0;
+ }
+};
+
+// string
+// lua_tostring returns a temporary pointer, but that's not a problem since we copy
+// the data into a std::string
+template<>
+struct LuaContext::Reader<std::string>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::string>
+ {
+ const auto val = lua_tostring(state, index);
+ if (val == 0)
+ return boost::none;
+ return std::string(val);
+ }
+};
+
+// enums
+template<typename TType>
+struct LuaContext::Reader<
+ TType,
+ typename std::enable_if<std::is_enum<TType>::value>::type
+ >
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<TType>
+ {
+ if (!lua_isnumber(state, index) || fmod(lua_tonumber(state, index), 1.) != 0)
+ return boost::none;
+ return static_cast<TType>(lua_tointeger(state, index));
+ }
+};
+
+// LuaFunctionCaller
+template<typename TRetValue, typename... TParameters>
+struct LuaContext::Reader<LuaContext::LuaFunctionCaller<TRetValue (TParameters...)>>
+{
+ typedef LuaFunctionCaller<TRetValue (TParameters...)>
+ ReturnType;
+
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ if (lua_isfunction(state, index) == 0 && lua_isuserdata(state, index) == 0)
+ return boost::none;
+ return ReturnType(state);
+ }
+};
+
+// function
+template<typename TRetValue, typename... TParameters>
+struct LuaContext::Reader<std::function<TRetValue (TParameters...)>>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::function<TRetValue (TParameters...)>>
+ {
+ if (auto val = Reader<LuaContext::LuaFunctionCaller<TRetValue (TParameters...)>>::read(state, index))
+ {
+ std::function<TRetValue (TParameters...)> f{*val};
+ return boost::optional<std::function<TRetValue (TParameters...)>>{std::move(f)};
+ }
+
+ return boost::none;
+ }
+};
+
+// vector of pairs
+template<typename TType1, typename TType2>
+struct LuaContext::Reader<std::vector<std::pair<TType1,TType2>>>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::vector<std::pair<TType1, TType2>>>
+ {
+ if (!lua_istable(state, index))
+ return boost::none;
+
+ std::vector<std::pair<TType1, TType2>> result;
+
+ // we traverse the table at the top of the stack
+ lua_pushnil(state); // first key
+ while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) {
+ // now a key and its value are pushed on the stack
+ try {
+ auto val1 = Reader<TType1>::read(state, -2);
+ auto val2 = Reader<TType2>::read(state, -1);
+
+ if (!val1.is_initialized() || !val2.is_initialized()) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+
+ result.push_back({ std::move(val1.get()), std::move(val2.get()) });
+ lua_pop(state, 1); // we remove the value but keep the key for the next iteration
+
+ } catch(...) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+ }
+
+ return { std::move(result) };
+ }
+};
+
+// map
+template<typename TKey, typename TValue>
+struct LuaContext::Reader<std::map<TKey,TValue>>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::map<TKey,TValue>>
+ {
+ if (!lua_istable(state, index))
+ return boost::none;
+
+ std::map<TKey,TValue> result;
+
+ // we traverse the table at the top of the stack
+ lua_pushnil(state); // first key
+ while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) {
+ // now a key and its value are pushed on the stack
+ try {
+ auto key = Reader<TKey>::read(state, -2);
+ auto value = Reader<TValue>::read(state, -1);
+
+ if (!key.is_initialized() || !value.is_initialized()) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+
+ result.insert({ std::move(key.get()), std::move(value.get()) });
+ lua_pop(state, 1); // we remove the value but keep the key for the next iteration
+
+ } catch(...) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+ }
+
+ return { std::move(result) };
+ }
+};
+
+// unordered_map
+template<typename TKey, typename TValue>
+struct LuaContext::Reader<std::unordered_map<TKey,TValue>>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<std::unordered_map<TKey,TValue>>
+ {
+ if (!lua_istable(state, index))
+ return boost::none;
+
+ std::unordered_map<TKey,TValue> result;
+
+ // we traverse the table at the top of the stack
+ lua_pushnil(state); // first key
+ while (lua_next(state, (index > 0) ? index : (index - 1)) != 0) {
+ // now a key and its value are pushed on the stack
+ try {
+ auto key = Reader<TKey>::read(state, -2);
+ auto value = Reader<TValue>::read(state, -1);
+
+ if (!key.is_initialized() || !value.is_initialized()) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+
+ result.insert({ std::move(key.get()), std::move(value.get()) });
+ lua_pop(state, 1); // we remove the value but keep the key for the next iteration
+
+ } catch(...) {
+ lua_pop(state, 2); // we remove the value and the key
+ return {};
+ }
+ }
+
+ return { std::move(result) };
+ }
+};
+
+// optional
+// IMPORTANT: optional means "either nil or the value of the right type"
+// * if the value is nil, then an optional containing an empty optional is returned
+// * if the value is of the right type, then an optional containing an optional containing the value is returned
+// * if the value is of the wrong type, then an empty optional is returned
+template<typename TType>
+struct LuaContext::Reader<boost::optional<TType>>
+{
+ static auto read(lua_State* state, int index)
+ -> boost::optional<boost::optional<TType>>
+ {
+ if (lua_isnil(state, index))
+ return boost::optional<TType>{boost::none};
+ if (auto&& other = Reader<TType>::read(state, index))
+ return std::move(other);
+ return boost::none;
+ }
+};
+
+// variant
+template<typename... TTypes>
+struct LuaContext::Reader<boost::variant<TTypes...>>
+{
+ typedef boost::variant<TTypes...>
+ ReturnType;
+
+private:
+ // class doing operations for a range of types from TIterBegin to TIterEnd
+ template<typename TIterBegin, typename TIterEnd, typename = void>
+ struct VariantReader
+ {
+ using SubReader = Reader<typename std::decay<typename boost::mpl::deref<TIterBegin>::type>::type>;
+
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ // note: using SubReader::read triggers a compilation error when used with a reference
+ if (const auto val = SubReader::read(state, index))
+ return boost::variant<TTypes...>{*val};
+ return VariantReader<typename boost::mpl::next<TIterBegin>::type, TIterEnd>::read(state, index);
+ }
+ };
+
+ // specialization of class above being called when list of remaining types is empty
+ template<typename TIterBegin, typename TIterEnd>
+ struct VariantReader<TIterBegin, TIterEnd, typename std::enable_if<boost::mpl::distance<TIterBegin, TIterEnd>::type::value == 0>::type>
+ {
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ return boost::none;
+ }
+ };
+
+ // this is the main type
+ typedef VariantReader<typename boost::mpl::begin<typename ReturnType::types>::type, typename boost::mpl::end<typename ReturnType::types>::type>
+ MainVariantReader;
+
+public:
+ static auto read(lua_State* state, int index)
+ -> boost::optional<ReturnType>
+ {
+ return MainVariantReader::read(state, index);
+ }
+};
+
+// reading a tuple
+// tuple have an additional argument for their functions, that is the maximum size to read
+// if maxSize is smaller than the tuple size, then the remaining parameters will be left to default value
+template<>
+struct LuaContext::Reader<std::tuple<>>
+{
+ static auto read(lua_State* state, int index, int maxSize = 0)
+ -> boost::optional<std::tuple<>>
+ {
+ return std::tuple<>{};
+ }
+};
+
+template<typename TFirst, typename... TOthers>
+struct LuaContext::Reader<std::tuple<TFirst, TOthers...>,
+ typename std::enable_if<!LuaContext::IsOptional<TFirst>::value>::type // TODO: replace by std::is_default_constructible when it works on every compiler
+ >
+{
+ // this is the "TFirst is NOT default constructible" version
+
+ typedef std::tuple<TFirst, TOthers...>
+ ReturnType;
+
+ static auto read(lua_State* state, int index, int maxSize = std::tuple_size<ReturnType>::value)
+ -> boost::optional<ReturnType>
+ {
+ if (maxSize <= 0)
+ return boost::none;
+
+ auto firstVal = Reader<TFirst>::read(state, index);
+ auto othersVal = Reader<std::tuple<TOthers...>>::read(state, index + 1, maxSize - 1);
+
+ if (!firstVal || !othersVal)
+ return boost::none;
+
+ return std::tuple_cat(std::tuple<TFirst>(*firstVal), std::move(*othersVal));
+ }
+};
+
+template<typename TFirst, typename... TOthers>
+struct LuaContext::Reader<std::tuple<TFirst, TOthers...>,
+ typename std::enable_if<LuaContext::IsOptional<TFirst>::value>::type // TODO: replace by std::is_default_constructible when it works on every compiler
+ >
+{
+ // this is the "TFirst is default-constructible" version
+
+ typedef std::tuple<TFirst, TOthers...>
+ ReturnType;
+
+ static auto read(lua_State* state, int index, int maxSize = std::tuple_size<ReturnType>::value)
+ -> boost::optional<ReturnType>
+ {
+ auto othersVal = Reader<std::tuple<TOthers...>>::read(state, index + 1, maxSize - 1);
+ if (!othersVal)
+ return boost::none;
+
+ if (maxSize <= 0)
+ return std::tuple_cat(std::tuple<TFirst>(), std::move(*othersVal));
+
+ auto firstVal = Reader<TFirst>::read(state, index);
+ if (!firstVal)
+ return boost::none;
+
+ return std::tuple_cat(std::tuple<TFirst>(*firstVal), std::move(*othersVal));
+ }
+};
+
+#endif
--- /dev/null
+The MIT License (MIT)
+
+Copyright (c) 2014 Aki Tuomi
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+SUBDIRS = yahttp
+
+EXTRA_DIST = LICENSE README.md
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/yahttp
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = $(SUBDIRS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = yahttp
+EXTRA_DIST = LICENSE README.md
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/yahttp/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ext/yahttp/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+Yet Another HTTP Library
+========================
+
+YaHTTP aims to be a pure http request/response parser that has no IO ties. It is intended to be used on small-footprint applications and other utilities that want to use HTTP over something else than network IO.
+
+[](https://travis-ci.org/cmouse/yahttp)
+[](https://scan.coverity.com/projects/2161)
+[](https://coveralls.io/r/cmouse/yahttp?branch=master%0A)
+
+WARNINGS
+--------
+If you are upgrading from version before May 02, 2014 - *PLEASE BE SURE TO CHECK THAT EVERYTHING WORKS AS EXPECTED*. There has been complete overhaul of the library and many things have changed.
+
+NOTES
+-----
+Do not use resp = req, or resp(req) to build the response object, despite it being supported. This will cause request headers to get duplicated. Also, you *must* set response#version to request#version if you intend to support older than HTTP/1.1 clients. Set response#status to at least 200, it won't be done for you. No Server or Product token is sent either, you can add those if you want.
+
+If you do not want to send chunked responses, set content-length header. Setting this header will always disable chunked responses. This will also happen if you downgrade your responses to version 10 or 9.
+
+Integration guide
+-----------------
+
+Here are some instructions on how to integrate YaHTTP into your project.
+
+With automake and libtool
+-------------------------
+
+If you don't need router or any of the C++11 features, you can just create empty yahttp-config.h, or symlink it to your project's config.h for the yahttp.hpp to include. Then just put this stuff into it's own folder and create Makefile.am with following contents (you can change the compilation flags):
+
+```
+noinst_LTLIBRARIES=libyahttp.la
+libyahttp_la_CXXFLAGS=$(RELRO_CFLAGS) $(PIE_CFLAGS) -D__STRICT_ANSI__
+libyahttp_la_SOURCES=cookie.hpp exception.hpp reqresp.cpp reqresp.hpp router.cpp router.hpp url.hpp utility.hpp yahttp.hpp
+```
+
+You can define RELRO and PIE to match your project.
+
+To compile your project use -Lpath/to/yahttp -lyahttp
+
+If you need router, additionally check for boost or C++11 and replace yahttp-config.h to config.h in yahttp.hpp or add relevant options to your compiler CXXFLAGS. See below for the flags.
+
+Without automake
+----------------
+
+Create simple Makefile with contents for C++11:
+
+```
+OBJECTS=reqresp.o router.o
+CXX=gcc
+CXXFLAGS=-W -Wall -DHAVE_CXX11 -std=c++11
+```
+
+Or create simple Makefile with contents for boost:
+
+```
+OBJECTS=reqresp.o router.o
+CXX=gcc
+CXXFLAGS=-W -Wall -DHAVE_BOOST
+```
+
+Or if you don't need either one, just:
+
+```
+OBJECTS=reqresp.o
+CXX=gcc
+CXXFLAGS=-W -Wall
+```
+
+YaHTTP include files can be placed where the rest of your includes are. Then just add your own code there and it should work just fine.
--- /dev/null
+noinst_LTLIBRARIES = libyahttp.la
+
+libyahttp_la_SOURCES = \
+ cookie.hpp \
+ exception.hpp \
+ reqresp.cpp \
+ reqresp.hpp \
+ router.cpp \
+ router.hpp \
+ url.hpp \
+ utility.hpp \
+ yahttp-config.h \
+ yahttp.hpp
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = ext/yahttp/yahttp
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+libyahttp_la_LIBADD =
+am_libyahttp_la_OBJECTS = reqresp.lo router.lo
+libyahttp_la_OBJECTS = $(am_libyahttp_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libyahttp_la_SOURCES)
+DIST_SOURCES = $(libyahttp_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+noinst_LTLIBRARIES = libyahttp.la
+libyahttp_la_SOURCES = \
+ cookie.hpp \
+ exception.hpp \
+ reqresp.cpp \
+ reqresp.hpp \
+ router.cpp \
+ router.hpp \
+ url.hpp \
+ utility.hpp \
+ yahttp-config.h \
+ yahttp.hpp
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cpp .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign ext/yahttp/yahttp/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign ext/yahttp/yahttp/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libyahttp.la: $(libyahttp_la_OBJECTS) $(libyahttp_la_DEPENDENCIES) $(EXTRA_libyahttp_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(CXXLINK) $(libyahttp_la_OBJECTS) $(libyahttp_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reqresp.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/router.Plo@am__quote@
+
+.cpp.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cpp.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cpp.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-noinstLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-noinstLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+namespace YaHTTP {
+ /*! Implements a single cookie */
+ class Cookie {
+ public:
+ Cookie() {
+ secure = false;
+ httponly = false;
+ name = value = "";
+ expires = DateTime();
+ }; //!< Set the cookie to empty value
+
+ Cookie(const Cookie &rhs) {
+ name = rhs.name;
+ value = rhs.value;
+ domain = rhs.domain;
+ path = rhs.path;
+ secure = rhs.secure;
+ httponly = rhs.httponly;
+ expires = rhs.expires;
+ }; //<! Copy cookie values
+
+ Cookie& operator=(const Cookie &rhs) {
+ name = rhs.name;
+ value = rhs.value;
+ domain = rhs.domain;
+ path = rhs.path;
+ secure = rhs.secure;
+ httponly = rhs.httponly;
+ expires = rhs.expires;
+ return *this;
+ }
+
+ DateTime expires; /*!< Expiration date */
+ std::string domain; /*!< Domain where cookie is valid */
+ std::string path; /*!< Path where the cookie is valid */
+ bool httponly; /*!< Whether the cookie is for server use only */
+ bool secure; /*!< Whether the cookie is for HTTPS only */
+
+ std::string name; /*!< Cookie name */
+ std::string value; /*!< Cookie value */
+
+ std::string str() const {
+ std::ostringstream oss;
+ oss << YaHTTP::Utility::encodeURL(name) << "=" << YaHTTP::Utility::encodeURL(value);
+
+ if (expires.isSet)
+ oss << "; expires=" << expires.cookie_str();
+ if (domain.size()>0)
+ oss << "; domain=" << domain;
+ if (path.size()>0)
+ oss << "; path=" << path;
+ if (secure)
+ oss << "; secure";
+ if (httponly)
+ oss << "; httpOnly";
+ return oss.str();
+ }; //!< Stringify the cookie
+ };
+
+ /*! Implements a Cookie jar for storing multiple cookies */
+ class CookieJar {
+ public:
+ std::map<std::string, Cookie, ASCIICINullSafeComparator> cookies; //<! cookie container
+
+ CookieJar() {}; //<! constructs empty cookie jar
+ CookieJar(const CookieJar & rhs) {
+ this->cookies = rhs.cookies;
+ } //<! copy cookies from another cookie jar
+
+ void clear() {
+ this->cookies.clear();
+ }
+
+ void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value) {
+ size_t pos;
+ pos = keyvalue.find("=");
+ if (pos == std::string::npos) throw "Not a Key-Value pair (cookie)";
+ key = std::string(keyvalue.begin(), keyvalue.begin()+pos);
+ value = std::string(keyvalue.begin()+pos+1, keyvalue.end());
+ } //<! key value pair parser
+
+ void parseCookieHeader(const std::string &cookiestr) {
+ size_t pos, npos;
+ std::list<Cookie> lcookies;
+ Cookie c;
+ pos = 0;
+ while(pos < cookiestr.size()) {
+ if ((npos = cookiestr.find("; ", pos)) == std::string::npos)
+ npos = cookiestr.size();
+ keyValuePair(cookiestr.substr(pos, npos-pos), c.name, c.value);
+ c.name = YaHTTP::Utility::decodeURL(c.name);
+ c.value = YaHTTP::Utility::decodeURL(c.value);
+ lcookies.push_back(c);
+ pos = npos+2;
+ }
+ for(std::list<Cookie>::iterator i = lcookies.begin(); i != lcookies.end(); i++) {
+ this->cookies[i->name] = *i;
+ }
+ }
+
+ void parseSetCookieHeader(const std::string &cookiestr) {
+ Cookie c;
+ size_t pos,npos;
+ std::string k, v;
+
+ if ((pos = cookiestr.find("; ", 0)) == std::string::npos)
+ pos = cookiestr.size();
+ keyValuePair(cookiestr.substr(0, pos), c.name, c.value);
+ c.name = YaHTTP::Utility::decodeURL(c.name);
+ c.value = YaHTTP::Utility::decodeURL(c.value);
+ if (pos < cookiestr.size()) pos+=2;
+
+ while(pos < cookiestr.size()) {
+ if ((npos = cookiestr.find("; ", pos)) == std::string::npos)
+ npos = cookiestr.size();
+ std::string s = cookiestr.substr(pos, npos-pos);
+ if (s.find("=") != std::string::npos)
+ keyValuePair(s, k, v);
+ else
+ k = s;
+ if (k == "expires") {
+ DateTime dt;
+ dt.parseCookie(v);
+ c.expires = dt;
+ } else if (k == "domain") {
+ c.domain = v;
+ } else if (k == "path") {
+ c.path = v;
+ } else if (k == "httpOnly") {
+ c.httponly = true;
+ } else if (k == "secure") {
+ c.secure = true;
+ } else {
+ // ignore crap
+ break;
+ }
+ pos = npos+2;
+ }
+
+ this->cookies[c.name] = c;
+ }; //<! Parse multiple cookies from header
+ };
+};
--- /dev/null
+#ifndef _YAHTTP_EXCEPTION_HPP
+#define _YAHTTP_EXCEPTION_HPP 1
+
+#include <exception>
+
+namespace YaHTTP {
+ /*! Generic error class */
+ class Error: public std::exception {
+ public:
+ Error() {};
+ Error(const std::string& reason_): reason(reason_) {};
+ virtual ~Error() throw() {};
+
+ virtual const char* what() const throw()
+ {
+ return reason.c_str();
+ }
+ const std::string reason; //<! Cause of the error
+ };
+ /*! Parse error class */
+ class ParseError: public YaHTTP::Error {
+ public:
+ ParseError() {};
+ ParseError(const std::string& reason_): Error(reason_) {};
+ };
+};
+
+#endif
--- /dev/null
+#include "yahttp.hpp"
+
+namespace YaHTTP {
+
+ bool isspace(char c) {
+ return std::isspace(c) != 0;
+ }
+
+ bool isspace(char c, const std::locale& loc) {
+ return std::isspace(c, loc);
+ }
+
+ bool isxdigit(char c) {
+ return std::isxdigit(c) != 0;
+ }
+
+ bool isxdigit(char c, const std::locale& loc) {
+ return std::isxdigit(c, loc);
+ }
+
+ bool isdigit(char c) {
+ return std::isdigit(c) != 0;
+ }
+
+ bool isdigit(char c, const std::locale& loc) {
+ return std::isdigit(c, loc);
+ }
+
+ bool isalnum(char c) {
+ return std::isalnum(c) != 0;
+ }
+
+ bool isalnum(char c, const std::locale& loc) {
+ return std::isalnum(c, loc);
+ }
+
+ template <class T>
+ bool AsyncLoader<T>::feed(const std::string& somedata) {
+ buffer.append(somedata);
+ while(state < 2) {
+ int cr=0;
+ pos = buffer.find_first_of("\n");
+ // need to find CRLF in buffer
+ if (pos == std::string::npos) return false;
+ if (pos>0 && buffer[pos-1]=='\r')
+ cr=1;
+ std::string line(buffer.begin(), buffer.begin()+pos-cr); // exclude CRLF
+ buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer including CRLF
+
+ if (state == 0) { // startup line
+ if (target->kind == YAHTTP_TYPE_REQUEST) {
+ std::string ver;
+ std::string tmpurl;
+ std::istringstream iss(line);
+ iss >> target->method >> tmpurl >> ver;
+ if (ver.size() == 0)
+ target->version = 9;
+ else if (ver.find("HTTP/0.9") == 0)
+ target->version = 9;
+ else if (ver.find("HTTP/1.0") == 0)
+ target->version = 10;
+ else if (ver.find("HTTP/1.1") == 0)
+ target->version = 11;
+ else
+ throw ParseError("HTTP version not supported");
+ // uppercase the target method
+ std::transform(target->method.begin(), target->method.end(), target->method.begin(), ::toupper);
+ target->url.parse(tmpurl);
+ target->getvars = Utility::parseUrlParameters(target->url.parameters);
+ state = 1;
+ } else if(target->kind == YAHTTP_TYPE_RESPONSE) {
+ std::string ver;
+ std::istringstream iss(line);
+ std::string::size_type pos1;
+ iss >> ver >> target->status;
+ std::getline(iss, target->statusText);
+ pos1=0;
+ while(pos1 < target->statusText.size() && YaHTTP::isspace(target->statusText.at(pos1))) pos1++;
+ target->statusText = target->statusText.substr(pos1);
+ if ((pos1 = target->statusText.find("\r")) != std::string::npos) {
+ target->statusText = target->statusText.substr(0, pos1-1);
+ }
+ if (ver.size() == 0) {
+ target->version = 9;
+ } else if (ver.find("HTTP/0.9") == 0)
+ target->version = 9;
+ else if (ver.find("HTTP/1.0") == 0)
+ target->version = 10;
+ else if (ver.find("HTTP/1.1") == 0)
+ target->version = 11;
+ else
+ throw ParseError("HTTP version not supported");
+ state = 1;
+ }
+ } else if (state == 1) {
+ std::string key,value;
+ size_t pos1;
+ if (line.empty()) {
+ chunked = (target->headers.find("transfer-encoding") != target->headers.end() && target->headers["transfer-encoding"] == "chunked");
+ state = 2;
+ break;
+ }
+ // split headers
+ if ((pos1 = line.find(": ")) == std::string::npos)
+ throw ParseError("Malformed header line");
+ key = line.substr(0, pos1);
+ value = line.substr(pos1+2);
+ for(std::string::iterator it=key.begin(); it != key.end(); it++)
+ if (YaHTTP::isspace(*it))
+ throw ParseError("Header key contains whitespace which is not allowed by RFC");
+
+ Utility::trim(value);
+ std::transform(key.begin(), key.end(), key.begin(), ::tolower);
+ // is it already defined
+
+ if (key == "set-cookie" && target->kind == YAHTTP_TYPE_RESPONSE) {
+ target->jar.parseSetCookieHeader(value);
+ } else if (key == "cookie" && target->kind == YAHTTP_TYPE_REQUEST) {
+ target->jar.parseCookieHeader(value);
+ } else {
+ if (key == "host" && target->kind == YAHTTP_TYPE_REQUEST) {
+ // maybe it contains port?
+ if ((pos1 = value.find(":")) == std::string::npos) {
+ target->url.host = value;
+ } else {
+ target->url.host = value.substr(0, pos1);
+ target->url.port = ::atoi(value.substr(pos1).c_str());
+ }
+ }
+ if (target->headers.find(key) != target->headers.end()) {
+ target->headers[key] = target->headers[key] + ";" + value;
+ } else {
+ target->headers[key] = value;
+ }
+ }
+ }
+ }
+
+ minbody = 0;
+ // check for expected body size
+ if (target->kind == YAHTTP_TYPE_REQUEST) maxbody = target->max_request_size;
+ else if (target->kind == YAHTTP_TYPE_RESPONSE) maxbody = target->max_response_size;
+ else maxbody = 0;
+
+ if (!chunked) {
+ if (target->headers.find("content-length") != target->headers.end()) {
+ std::istringstream maxbodyS(target->headers["content-length"]);
+ maxbodyS >> minbody;
+ maxbody = minbody;
+ }
+ if (minbody < 1) return true; // guess there isn't anything left.
+ if (target->kind == YAHTTP_TYPE_REQUEST && static_cast<ssize_t>(minbody) > target->max_request_size) throw ParseError("Max request body size exceeded");
+ else if (target->kind == YAHTTP_TYPE_RESPONSE && static_cast<ssize_t>(minbody) > target->max_response_size) throw ParseError("Max response body size exceeded");
+ }
+
+ if (maxbody == 0) hasBody = false;
+ else hasBody = true;
+
+ if (buffer.size() == 0) return ready();
+
+ while(buffer.size() > 0) {
+ if (chunked) {
+ if (chunk_size == 0) {
+ char buf[100];
+ // read chunk length
+ if ((pos = buffer.find('\n')) == std::string::npos) return false;
+ if (pos > 99)
+ throw ParseError("Impossible chunk_size");
+ buffer.copy(buf, pos);
+ buf[pos]=0; // just in case...
+ buffer.erase(buffer.begin(), buffer.begin()+pos+1); // remove line from buffer
+ sscanf(buf, "%x", &chunk_size);
+ if (chunk_size == 0) { state = 3; break; } // last chunk
+ } else {
+ int crlf=1;
+ if (buffer.size() < static_cast<size_t>(chunk_size+1)) return false; // expect newline
+ if (buffer.at(chunk_size) == '\r') {
+ if (buffer.size() < static_cast<size_t>(chunk_size+2) || buffer.at(chunk_size+1) != '\n') return false; // expect newline after carriage return
+ crlf=2;
+ } else if (buffer.at(chunk_size) != '\n') return false;
+ std::string tmp = buffer.substr(0, chunk_size);
+ buffer.erase(buffer.begin(), buffer.begin()+chunk_size+crlf);
+ bodybuf << tmp;
+ chunk_size = 0;
+ if (buffer.size() == 0) break; // just in case
+ }
+ } else {
+ if (bodybuf.str().length() + buffer.length() > maxbody)
+ bodybuf << buffer.substr(0, maxbody - bodybuf.str().length());
+ else
+ bodybuf << buffer;
+ buffer = "";
+ }
+ }
+
+ if (chunk_size!=0) return false; // need more data
+
+ return ready();
+ };
+
+ void HTTPBase::write(std::ostream& os) const {
+ if (kind == YAHTTP_TYPE_REQUEST) {
+ std::ostringstream getparmbuf;
+ std::string getparms;
+ // prepare URL
+ for(strstr_map_t::const_iterator i = getvars.begin(); i != getvars.end(); i++) {
+ getparmbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
+ }
+ if (getparmbuf.str().length() > 0) {
+ std::string buf = getparmbuf.str();
+ getparms = "?" + std::string(buf.begin(), buf.end() - 1);
+ }
+ else
+ getparms = "";
+ os << method << " " << url.path << getparms << " HTTP/" << versionStr(this->version);
+ } else if (kind == YAHTTP_TYPE_RESPONSE) {
+ os << "HTTP/" << versionStr(this->version) << " " << status << " ";
+ if (statusText.empty())
+ os << Utility::status2text(status);
+ else
+ os << statusText;
+ }
+ os << "\r\n";
+
+ bool cookieSent = false;
+ bool sendChunked = false;
+
+ if (this->version > 10) { // 1.1 or better
+ if (headers.find("content-length") == headers.end() && !this->is_multipart) {
+ // must use chunked on response
+ sendChunked = (kind == YAHTTP_TYPE_RESPONSE);
+ if ((headers.find("transfer-encoding") != headers.end() && headers.find("transfer-encoding")->second != "chunked")) {
+ throw YaHTTP::Error("Transfer-encoding must be chunked, or Content-Length defined");
+ }
+ if ((headers.find("transfer-encoding") == headers.end() && kind == YAHTTP_TYPE_RESPONSE)) {
+ sendChunked = true;
+ os << "Transfer-Encoding: chunked\r\n";
+ }
+ } else {
+ sendChunked = false;
+ }
+ }
+
+ // write headers
+ strstr_map_t::const_iterator iter = headers.begin();
+ while(iter != headers.end()) {
+ if (iter->first == "host" && (kind != YAHTTP_TYPE_REQUEST || version < 10)) { iter++; continue; }
+ if (iter->first == "transfer-encoding" && sendChunked) { iter++; continue; }
+ std::string header = Utility::camelizeHeader(iter->first);
+ if (header == "Cookie" || header == "Set-Cookie") cookieSent = true;
+ os << Utility::camelizeHeader(iter->first) << ": " << iter->second << "\r\n";
+ iter++;
+ }
+ if (version > 9 && !cookieSent && jar.cookies.size() > 0) { // write cookies
+ if (kind == YAHTTP_TYPE_REQUEST) {
+ bool first = true;
+ os << "Cookie: ";
+ for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) {
+ if (first)
+ first = false;
+ else
+ os << "; ";
+ os << Utility::encodeURL(i->second.name) << "=" << Utility::encodeURL(i->second.value);
+ }
+ } else if (kind == YAHTTP_TYPE_REQUEST) {
+ for(strcookie_map_t::const_iterator i = jar.cookies.begin(); i != jar.cookies.end(); i++) {
+ os << "Set-Cookie: ";
+ os << i->second.str() << "\r\n";
+ }
+ }
+ }
+ os << "\r\n";
+#ifdef HAVE_CPP_FUNC_PTR
+ this->renderer(this, os, sendChunked);
+#else
+ SendbodyRenderer r;
+ r(this, os, chunked)
+#endif
+ };
+
+ std::ostream& operator<<(std::ostream& os, const Response &resp) {
+ resp.write(os);
+ return os;
+ };
+
+ std::istream& operator>>(std::istream& is, Response &resp) {
+ YaHTTP::AsyncResponseLoader arl;
+ arl.initialize(&resp);
+ while(is.good()) {
+ char buf[1024];
+ is.read(buf, 1024);
+ if (is.gcount()>0) { // did we actually read anything
+ is.clear();
+ if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
+ }
+ }
+ // throw unless ready
+ if (arl.ready() == false)
+ throw ParseError("Was not able to extract a valid Response from stream");
+ arl.finalize();
+ return is;
+ };
+
+ std::ostream& operator<<(std::ostream& os, const Request &req) {
+ req.write(os);
+ return os;
+ };
+
+ std::istream& operator>>(std::istream& is, Request &req) {
+ YaHTTP::AsyncRequestLoader arl;
+ arl.initialize(&req);
+ while(is.good()) {
+ char buf[1024];
+ is.read(buf, 1024);
+ if (is.gcount() > 0) { // did we actually read anything
+ is.clear();
+ if (arl.feed(std::string(buf, is.gcount())) == true) break; // completed
+ }
+ }
+ if (arl.ready() == false)
+ throw ParseError("Was not able to extract a valid Request from stream");
+ arl.finalize();
+ return is;
+ };
+};
--- /dev/null
+#ifdef HAVE_CXX11
+#include <functional>
+#define HAVE_CPP_FUNC_PTR
+namespace funcptr = std;
+#else
+#ifdef HAVE_BOOST
+#include <boost/function.hpp>
+namespace funcptr = boost;
+#define HAVE_CPP_FUNC_PTR
+#endif
+#endif
+
+#include <fstream>
+#include <cctype>
+
+#ifndef WIN32
+#include <cstdio>
+#include <unistd.h>
+#endif
+
+#include <algorithm>
+
+#ifndef YAHTTP_MAX_REQUEST_SIZE
+#define YAHTTP_MAX_REQUEST_SIZE 2097152
+#endif
+
+#ifndef YAHTTP_MAX_RESPONSE_SIZE
+#define YAHTTP_MAX_RESPONSE_SIZE 2097152
+#endif
+
+#define YAHTTP_TYPE_REQUEST 1
+#define YAHTTP_TYPE_RESPONSE 2
+
+namespace YaHTTP {
+ typedef std::map<std::string,Cookie,ASCIICINullSafeComparator> strcookie_map_t; //<! String to Cookie map
+
+ typedef enum {
+ urlencoded,
+ multipart
+ } postformat_t; //<! Enumeration of possible post encodings, url encoding or multipart
+
+ /*! Base class for request and response */
+ class HTTPBase {
+ public:
+ /*! Default renderer for request/response, simply copies body to response */
+ class SendBodyRender {
+ public:
+ SendBodyRender() {};
+
+ size_t operator()(const HTTPBase *doc, std::ostream& os, bool chunked) const {
+ if (chunked) {
+ std::string::size_type i,cl;
+ for(i=0;i<doc->body.length();i+=1024) {
+ cl = std::min(static_cast<std::string::size_type>(1024), doc->body.length()-i); // for less than 1k blocks
+ os << std::hex << cl << std::dec << "\r\n";
+ os << doc->body.substr(i, cl) << "\r\n";
+ }
+ os << 0 << "\r\n\r\n"; // last chunk
+ } else {
+ os << doc->body;
+ }
+ return doc->body.length();
+ }; //<! writes body to ostream and returns length
+ };
+ /* Simple sendfile renderer which streams file to ostream */
+ class SendFileRender {
+ public:
+ SendFileRender(const std::string& path_) {
+ this->path = path_;
+ };
+
+ size_t operator()(const HTTPBase *doc __attribute__((unused)), std::ostream& os, bool chunked) const {
+ char buf[4096];
+ size_t n,k;
+#ifdef HAVE_CXX11
+ std::ifstream ifs(path, std::ifstream::binary);
+#else
+ std::ifstream ifs(path.c_str(), std::ifstream::binary);
+#endif
+ n = 0;
+
+ while(ifs.good()) {
+ ifs.read(buf, sizeof buf);
+ n += (k = ifs.gcount());
+ if (k > 0) {
+ if (chunked) os << std::hex << k << std::dec << "\r\n";
+ os.write(buf, k);
+ if (chunked) os << "\r\n";
+ }
+ }
+ if (chunked) os << 0 << "\r\n\r\n";
+ return n;
+ }; //<! writes file to ostream and returns length
+
+ std::string path; //<! File to send
+ };
+
+ HTTPBase() {
+ initialize();
+ };
+
+ virtual void initialize() {
+ kind = 0;
+ status = 0;
+#ifdef HAVE_CPP_FUNC_PTR
+ renderer = SendBodyRender();
+#endif
+ max_request_size = YAHTTP_MAX_REQUEST_SIZE;
+ max_response_size = YAHTTP_MAX_RESPONSE_SIZE;
+ url = "";
+ method = "";
+ statusText = "";
+ jar.clear();
+ headers.clear();
+ parameters.clear();
+ getvars.clear();
+ postvars.clear();
+ body = "";
+ routeName = "";
+ version = 11; // default to version 1.1
+ is_multipart = false;
+ }
+protected:
+ HTTPBase(const HTTPBase& rhs) {
+ this->url = rhs.url; this->kind = rhs.kind;
+ this->status = rhs.status; this->statusText = rhs.statusText;
+ this->method = rhs.method; this->headers = rhs.headers;
+ this->jar = rhs.jar; this->postvars = rhs.postvars;
+ this->parameters = rhs.parameters; this->getvars = rhs.getvars;
+ this->body = rhs.body; this->max_request_size = rhs.max_request_size;
+ this->max_response_size = rhs.max_response_size; this->version = rhs.version;
+#ifdef HAVE_CPP_FUNC_PTR
+ this->renderer = rhs.renderer;
+#endif
+ };
+ HTTPBase& operator=(const HTTPBase& rhs) {
+ this->url = rhs.url; this->kind = rhs.kind;
+ this->status = rhs.status; this->statusText = rhs.statusText;
+ this->method = rhs.method; this->headers = rhs.headers;
+ this->jar = rhs.jar; this->postvars = rhs.postvars;
+ this->parameters = rhs.parameters; this->getvars = rhs.getvars;
+ this->body = rhs.body; this->max_request_size = rhs.max_request_size;
+ this->max_response_size = rhs.max_response_size; this->version = rhs.version;
+#ifdef HAVE_CPP_FUNC_PTR
+ this->renderer = rhs.renderer;
+#endif
+ return *this;
+ };
+public:
+ URL url; //<! URL of this request/response
+ int kind; //<! Type of object (1 = request, 2 = response)
+ int status; //<! status code
+ int version; //<! http version 9 = 0.9, 10 = 1.0, 11 = 1.1
+ std::string statusText; //<! textual representation of status code
+ std::string method; //<! http verb
+ strstr_map_t headers; //<! map of header(s)
+ CookieJar jar; //<! cookies
+ strstr_map_t postvars; //<! map of POST variables (from POST body)
+ strstr_map_t getvars; //<! map of GET variables (from URL)
+// these two are for Router
+ strstr_map_t parameters; //<! map of route parameters (only if you use YaHTTP::Router)
+ std::string routeName; //<! name of the current route (only if you use YaHTTP::Router)
+
+ std::string body; //<! the actual content
+
+ ssize_t max_request_size; //<! maximum size of request
+ ssize_t max_response_size; //<! maximum size of response
+ bool is_multipart; //<! if the request is multipart, prevents Content-Length header
+#ifdef HAVE_CPP_FUNC_PTR
+ funcptr::function<size_t(const HTTPBase*,std::ostream&,bool)> renderer; //<! rendering function
+#endif
+ void write(std::ostream& os) const; //<! writes request to the given output stream
+
+ strstr_map_t& GET() { return getvars; }; //<! acccessor for getvars
+ strstr_map_t& POST() { return postvars; }; //<! accessor for postvars
+ strcookie_map_t& COOKIES() { return jar.cookies; }; //<! accessor for cookies
+
+ std::string versionStr(int version_) const {
+ switch(version_) {
+ case 9: return "0.9";
+ case 10: return "1.0";
+ case 11: return "1.1";
+ default: throw YaHTTP::Error("Unsupported version");
+ }
+ };
+
+ std::string str() const {
+ std::ostringstream oss;
+ write(oss);
+ return oss.str();
+ }; //<! return string representation of this object
+ };
+
+ /*! Response class, represents a HTTP Response document */
+ class Response: public HTTPBase {
+ public:
+ Response() { initialize(); };
+ Response(const HTTPBase& rhs): HTTPBase(rhs) {
+ this->kind = YAHTTP_TYPE_RESPONSE;
+ };
+ Response& operator=(const HTTPBase& rhs) {
+ HTTPBase::operator=(rhs);
+ this->kind = YAHTTP_TYPE_RESPONSE;
+ return *this;
+ };
+ void initialize() {
+ HTTPBase::initialize();
+ this->kind = YAHTTP_TYPE_RESPONSE;
+ }
+ void initialize(const HTTPBase& rhs) {
+ HTTPBase::initialize();
+ this->kind = YAHTTP_TYPE_RESPONSE;
+ // copy SOME attributes
+ this->url = rhs.url;
+ this->method = rhs.method;
+ this->jar = rhs.jar;
+ this->version = rhs.version;
+ }
+ friend std::ostream& operator<<(std::ostream& os, const Response &resp);
+ friend std::istream& operator>>(std::istream& is, Response &resp);
+ };
+
+ /* Request class, represents a HTTP Request document */
+ class Request: public HTTPBase {
+ public:
+ Request() { initialize(); };
+ Request(const HTTPBase& rhs): HTTPBase(rhs) {
+ this->kind = YAHTTP_TYPE_REQUEST;
+ };
+ Request& operator=(const HTTPBase& rhs) {
+ HTTPBase::operator=(rhs);
+ this->kind = YAHTTP_TYPE_REQUEST;
+ return *this;
+ };
+ void initialize() {
+ HTTPBase::initialize();
+ this->kind = YAHTTP_TYPE_REQUEST;
+ }
+ void initialize(const HTTPBase& rhs) {
+ HTTPBase::initialize();
+ this->kind = YAHTTP_TYPE_REQUEST;
+ // copy SOME attributes
+ this->url = rhs.url;
+ this->method = rhs.method;
+ this->jar = rhs.jar;
+ this->version = rhs.version;
+ }
+ void setup(const std::string& method_, const std::string& url_) {
+ this->url.parse(url_);
+ this->headers["host"] = this->url.host;
+ this->method = method_;
+ std::transform(this->method.begin(), this->method.end(), this->method.begin(), ::toupper);
+ this->headers["user-agent"] = "YaHTTP v1.0";
+ }; //<! Set some initial things for a request
+
+ void preparePost(postformat_t format = urlencoded) {
+ std::ostringstream postbuf;
+ if (format == urlencoded) {
+ for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
+ postbuf << Utility::encodeURL(i->first, false) << "=" << Utility::encodeURL(i->second, false) << "&";
+ }
+ // remove last bit
+ if (postbuf.str().length()>0)
+ body = postbuf.str().substr(0, postbuf.str().length()-1);
+ else
+ body = "";
+ headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ } else if (format == multipart) {
+ headers["content-type"] = "multipart/form-data; boundary=YaHTTP-12ca543";
+ this->is_multipart = true;
+ for(strstr_map_t::const_iterator i = POST().begin(); i != POST().end(); i++) {
+ postbuf << "--YaHTTP-12ca543\r\nContent-Disposition: form-data; name=\"" << Utility::encodeURL(i->first, false) << "\"; charset=UTF-8\r\nContent-Length: " << i->second.size() << "\r\n\r\n"
+ << Utility::encodeURL(i->second, false) << "\r\n";
+ }
+ postbuf << "--";
+ body = postbuf.str();
+ }
+
+ postbuf.str("");
+ postbuf << body.length();
+ // set method and change headers
+ method = "POST";
+ if (!this->is_multipart)
+ headers["content-length"] = postbuf.str();
+ }; //<! convert all postvars into string and stuff it into body
+
+ friend std::ostream& operator<<(std::ostream& os, const Request &resp);
+ friend std::istream& operator>>(std::istream& is, Request &resp);
+ };
+
+ /*! Asynchronous HTTP document loader */
+ template <class T>
+ class AsyncLoader {
+ public:
+ T* target; //<! target to populate
+ int state; //<! reader state
+ size_t pos; //<! reader position
+
+ std::string buffer; //<! read buffer
+ bool chunked; //<! whether we are parsing chunked data
+ int chunk_size; //<! expected size of next chunk
+ std::ostringstream bodybuf; //<! buffer for body
+ size_t maxbody; //<! maximum size of body
+ size_t minbody; //<! minimum size of body
+ bool hasBody; //<! are we expecting body
+
+ void keyValuePair(const std::string &keyvalue, std::string &key, std::string &value); //<! key value pair parser helper
+
+ void initialize(T* target_) {
+ chunked = false; chunk_size = 0;
+ bodybuf.str(""); minbody = 0; maxbody = 0;
+ pos = 0; state = 0; this->target = target_;
+ hasBody = false;
+ buffer = "";
+ this->target->initialize();
+ }; //<! Initialize the parser for target and clear state
+ bool feed(const std::string& somedata); //<! Feed data to the parser
+ bool ready() {
+ return (chunked == true && state == 3) || // if it's chunked we get end of data indication
+ (chunked == false && state > 1 &&
+ (!hasBody ||
+ (bodybuf.str().size() <= maxbody &&
+ bodybuf.str().size() >= minbody)
+ )
+ );
+ }; //<! whether we have received enough data
+ void finalize() {
+ bodybuf.flush();
+ if (ready()) {
+ strstr_map_t::iterator cpos = target->headers.find("content-type");
+ if (cpos != target->headers.end() && Utility::iequals(cpos->second, "application/x-www-form-urlencoded", 32)) {
+ target->postvars = Utility::parseUrlParameters(bodybuf.str());
+ }
+ target->body = bodybuf.str();
+ }
+ bodybuf.str("");
+ this->target = NULL;
+ }; //<! finalize and release target
+ };
+
+ /*! Asynchronous HTTP response loader */
+ class AsyncResponseLoader: public AsyncLoader<Response> {
+ };
+
+ /*! Asynchronous HTTP request loader */
+ class AsyncRequestLoader: public AsyncLoader<Request> {
+ };
+
+};
--- /dev/null
+/* @file
+ * @brief Concrete implementation of Router
+ */
+#include "yahttp.hpp"
+#include "router.hpp"
+
+namespace YaHTTP {
+ typedef funcptr::tuple<int,int> TDelim;
+
+ // router is defined here.
+ YaHTTP::Router Router::router;
+
+ void Router::map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name) {
+ std::string method2 = method;
+ bool isopen=false;
+ // add into vector
+ for(std::string::const_iterator i = url.begin(); i != url.end(); i++) {
+ if (*i == '<' && isopen) throw Error("Invalid URL mask, cannot have < after <");
+ if (*i == '<') isopen = true;
+ if (*i == '>' && !isopen) throw Error("Invalid URL mask, cannot have > without < first");
+ if (*i == '>') isopen = false;
+ }
+ std::transform(method2.begin(), method2.end(), method2.begin(), ::toupper);
+ routes.push_back(funcptr::make_tuple(method2, url, handler, name));
+ };
+
+ bool Router::route(Request *req, THandlerFunction& handler) {
+ std::map<std::string, TDelim> params;
+ int pos1,pos2;
+ bool matched = false;
+ std::string rname;
+
+ // iterate routes
+ for(TRouteList::iterator i = routes.begin(); !matched && i != routes.end(); i++) {
+ int k1,k2,k3;
+ std::string pname;
+ std::string method, url;
+ funcptr::tie(method, url, handler, rname) = *i;
+
+ if (method.empty() == false && req->method != method) continue; // no match on method
+ // see if we can't match the url
+ params.clear();
+ // simple matcher func
+ for(k1=0, k2=0; k1 < static_cast<int>(url.size()) && k2 < static_cast<int>(req->url.path.size()); ) {
+ if (url[k1] == '<') {
+ pos1 = k2;
+ k3 = k1+1;
+ // start of parameter
+ while(k1 < static_cast<int>(url.size()) && url[k1] != '>') k1++;
+ pname = std::string(url.begin()+k3, url.begin()+k1);
+ // then we also look it on the url
+ if (pname[0]=='*') {
+ pname = pname.substr(1);
+ // this matches whatever comes after it, basically end of string
+ pos2 = req->url.path.size();
+ matched = true;
+ if (pname != "")
+ params[pname] = funcptr::tie(pos1,pos2);
+ k1 = url.size();
+ k2 = req->url.path.size();
+ break;
+ } else {
+ // match until url[k1]
+ while(k2 < static_cast<int>(req->url.path.size()) && req->url.path[k2] != url[k1+1]) k2++;
+ pos2 = k2;
+ params[pname] = funcptr::tie(pos1,pos2);
+ }
+ k2--;
+ }
+ else if (url[k1] != req->url.path[k2]) {
+ break;
+ }
+
+ k1++; k2++;
+ }
+
+ // ensure.
+ if (url[k1] != req->url.path[k2])
+ matched = false;
+ else
+ matched = true;
+ }
+
+ if (!matched) { return false; } // no route
+ req->parameters.clear();
+
+ for(std::map<std::string, TDelim>::iterator i = params.begin(); i != params.end(); i++) {
+ int p1,p2;
+ funcptr::tie(p1,p2) = i->second;
+ std::string value(req->url.path.begin() + p1, req->url.path.begin() + p2);
+ value = Utility::decodeURL(value);
+ req->parameters[i->first] = value;
+ }
+
+ req->routeName = rname;
+
+ return true;
+ };
+
+ void Router::printRoutes(std::ostream &os) {
+ for(TRouteList::iterator i = routes.begin(); i != routes.end(); i++) {
+#ifdef HAVE_CXX11
+ std::streamsize ss = os.width();
+ std::ios::fmtflags ff = os.setf(std::ios::left);
+ os.width(10);
+ os << std::get<0>(*i);
+ os.width(50);
+ os << std::get<1>(*i);
+ os.width(ss);
+ os.setf(ff);
+ os << " " << std::get<3>(*i);
+ os << std::endl;
+#else
+ os << i->get<0>() << " " << i->get<1>() << " " << i->get<3>() << std::endl;
+#endif
+ }
+ };
+
+ std::pair<std::string,std::string> Router::urlFor(const std::string &name, const strstr_map_t& arguments) {
+ std::ostringstream path;
+ std::string mask,method,result;
+ int k1,k2,k3;
+
+ bool found = false;
+ for(TRouteList::iterator i = routes.begin(); !found && i != routes.end(); i++) {
+#ifdef HAVE_CXX11
+ if (std::get<3>(*i) == name) { mask = std::get<1>(*i); method = std::get<0>(*i); found = true; }
+#else
+ if (i->get<3>() == name) { mask = i->get<1>(); method = i->get<0>(); found = true; }
+#endif
+ }
+
+ if (!found)
+ throw Error("Route not found");
+
+ for(k1=0,k3=0;k1<static_cast<int>(mask.size());k1++) {
+ if (mask[k1] == '<') {
+ std::string pname;
+ strstr_map_t::const_iterator pptr;
+ k2=k1;
+ while(k1<static_cast<int>(mask.size()) && mask[k1]!='>') k1++;
+ path << mask.substr(k3,k2-k3);
+ if (mask[k2+1] == '*')
+ pname = std::string(mask.begin() + k2 + 2, mask.begin() + k1);
+ else
+ pname = std::string(mask.begin() + k2 + 1, mask.begin() + k1);
+ if ((pptr = arguments.find(pname)) != arguments.end())
+ path << Utility::encodeURL(pptr->second);
+ k3 = k1+1;
+ }
+ else if (mask[k1] == '*') {
+ // ready
+ k3++;
+ continue;
+ }
+ }
+ path << mask.substr(k3);
+ result = path.str();
+ return std::make_pair(method, result);
+ }
+};
--- /dev/null
+#ifndef _YAHTTP_ROUTER_HPP
+#define _YAHTTP_ROUTER_HPP 1
+/* @file
+ * @brief Defines router class and support structures
+ */
+#ifdef HAVE_CXX11
+#include <functional>
+#include <tuple>
+#define HAVE_CPP_FUNC_PTR
+#define IGNORE std::ignore
+namespace funcptr = std;
+#else
+#ifdef HAVE_BOOST
+#include <boost/function.hpp>
+#include <boost/tuple/tuple.hpp>
+#define IGNORE boost::tuples::ignore
+namespace funcptr = boost;
+#define HAVE_CPP_FUNC_PTR
+#else
+#warning "You need to configure with boost or have C++11 capable compiler for router"
+#endif
+#endif
+
+#ifdef HAVE_CPP_FUNC_PTR
+#include <vector>
+#include <utility>
+
+namespace YaHTTP {
+ typedef funcptr::function <void(Request* req, Response* resp)> THandlerFunction; //!< Handler function pointer
+ typedef funcptr::tuple<std::string, std::string, THandlerFunction, std::string> TRoute; //!< Route tuple (method, urlmask, handler, name)
+ typedef std::vector<TRoute> TRouteList; //!< List of routes in order of evaluation
+
+ /*! Implements simple router.
+
+This class implements a router for masked urls. The URL mask syntax is as of follows
+
+/<masked>/url<number>/<hi>.<format>
+
+You can use <*param> to denote that everything will be matched and consumed into the parameter, including slash (/). Use <*> to denote that URL
+is consumed but not stored. Note that only path is matched, scheme, host and url parameters are ignored.
+ */
+ class Router {
+ private:
+ Router() {};
+ static Router router; //<! Singleton instance of Router
+ public:
+ void map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name); //<! Instance method for mapping urls
+ bool route(Request *req, THandlerFunction& handler); //<! Instance method for performing routing
+ void printRoutes(std::ostream &os); //<! Instance method for printing routes
+ std::pair<std::string, std::string> urlFor(const std::string &name, const strstr_map_t& arguments); //<! Instance method for generating paths
+
+/*! Map an URL.
+If method is left empty, it will match any method. Name is also optional, but needed if you want to find it for making URLs
+*/
+ static void Map(const std::string& method, const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map(method, url, handler, name); };
+ static void Get(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("GET", url, handler, name); }; //<! Helper for mapping GET
+ static void Post(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("POST", url, handler, name); }; //<! Helper for mapping POST
+ static void Put(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PUT", url, handler, name); }; //<! Helper for mapping PUT
+ static void Patch(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("PATCH", url, handler, name); }; //<! Helper for mapping PATCH
+ static void Delete(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("DELETE", url, handler, name); }; //<! Helper for mapping DELETE
+ static void Any(const std::string& url, THandlerFunction handler, const std::string& name = "") { router.map("", url, handler, name); }; //<! Helper for mapping any method
+
+ static bool Route(Request *req, THandlerFunction& handler) { return router.route(req, handler); }; //<! Performs routing based on req->url.path
+ static void PrintRoutes(std::ostream &os) { router.printRoutes(os); }; //<! Prints all known routes to given output stream
+
+ static std::pair<std::string, std::string> URLFor(const std::string &name, const strstr_map_t& arguments) { return router.urlFor(name,arguments); }; //<! Generates url from named route and arguments. Missing arguments are assumed empty
+ static const TRouteList& GetRoutes() { return router.routes; } //<! Reference to route list
+
+ TRouteList routes; //<! Instance variable for routes
+ };
+};
+#endif
+
+#endif
--- /dev/null
+#ifndef _YAHTTP_URL_HPP
+#define _YAHTTP_URL_HPP 1
+#include <sstream>
+#include <string>
+
+#include "utility.hpp"
+
+#ifndef YAHTTP_MAX_URL_LENGTH
+#define YAHTTP_MAX_URL_LENGTH 2048
+#endif
+
+namespace YaHTTP {
+ /*! URL parser and container */
+ class URL {
+ private:
+ bool parseSchema(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return false; // no data
+ if ( (pos1 = url.find_first_of(":",pos)) == std::string::npos ) return false; // schema is mandatory
+ protocol = url.substr(pos, pos1-pos);
+ if (protocol == "http") port = 80;
+ if (protocol == "https") port = 443;
+ pos = pos1+1; // after :
+ if (url.compare(pos, 2, "//") == 0) {
+ pathless = false; // if this is true we put rest into parameters
+ pos += 2;
+ }
+ return true;
+ }; //<! parse schema/protocol part
+
+ bool parseHost(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if ( (pos1 = url.find_first_of("/", pos)) == std::string::npos ) {
+ host = url.substr(pos);
+ path = "/";
+ pos = url.size();
+ } else {
+ host = url.substr(pos, pos1-pos);
+ pos = pos1;
+ }
+ if ( (pos1 = host.find_first_of(":")) != std::string::npos ) {
+ std::istringstream tmp(host.substr(pos1+1));
+ tmp >> port;
+ host = host.substr(0, pos1);
+ }
+ return true;
+ }; //<! parse host and port
+
+ bool parseUserPass(const std::string& url, size_t &pos) {
+ size_t pos1,pos2;
+ if (pos >= url.size()) return true; // no data
+
+ if ( (pos1 = url.find_first_of("@",pos)) == std::string::npos ) return true; // no userinfo
+ pos2 = url.find_first_of(":",pos);
+
+ if (pos2 != std::string::npos) { // comes with password
+ username = url.substr(pos, pos2 - pos);
+ password = url.substr(pos2+1, pos1 - pos2 - 1);
+ password = Utility::decodeURL(password);
+ } else {
+ username = url.substr(pos, pos1 - pos);
+ }
+ pos = pos1+1;
+ username = Utility::decodeURL(username);
+ return true;
+ }; //<! parse possible username and password
+
+ bool parsePath(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] != '/') return false; // not an url
+ if ( (pos1 = url.find_first_of("?", pos)) == std::string::npos ) {
+ path = url.substr(pos);
+ pos = url.size();
+ } else {
+ path = url.substr(pos, pos1-pos);
+ pos = pos1;
+ }
+ return true;
+ }; //<! parse path component
+
+ bool parseParameters(const std::string& url, size_t &pos) {
+ size_t pos1;
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] == '#') return true; // anchor starts here
+ if (url[pos] != '?') return false; // not a parameter
+ if ( (pos1 = url.find_first_of("#", pos)) == std::string::npos ) {
+ parameters = url.substr(pos+1);;
+ pos = url.size();
+ } else {
+ parameters = url.substr(pos+1, pos1-pos-1);
+ pos = pos1;
+ }
+ if (parameters.size()>0 && *(parameters.end()-1) == '&') parameters.resize(parameters.size()-1);
+ return true;
+ }; //<! parse url parameters
+
+ bool parseAnchor(const std::string& url, size_t &pos) {
+ if (pos >= url.size()) return true; // no data
+ if (url[pos] != '#') return false; // not anchor
+ anchor = url.substr(pos+1);
+ return true;
+ }; //<! parse anchor
+
+ void initialize() {
+ protocol = ""; host = ""; port = 0; username = ""; password = ""; path = ""; parameters = ""; anchor =""; pathless = true;
+ }; //<! initialize to empty URL
+
+ public:
+ std::string to_string() const {
+ std::string tmp;
+ std::ostringstream oss;
+
+ if (protocol.empty() == false) {
+ oss << protocol << ":";
+ if (host.empty() == false) {
+ oss << "//";
+ }
+ }
+
+ if (username.empty() == false) {
+ if (password.empty() == false)
+ oss << Utility::encodeURL(username) << ":" << Utility::encodeURL(password) << "@";
+ else
+ oss << Utility::encodeURL(username) << "@";
+ }
+ if (host.empty() == false)
+ oss << host;
+ if (!(protocol == "http" && port == 80) &&
+ !(protocol == "https" && port == 443) &&
+ port > 0)
+ oss << ":" << port;
+
+ oss << path;
+ if (parameters.empty() == false) {
+ if (!pathless)
+ oss << "?";
+ oss << parameters;
+ }
+ if (anchor.empty() == false)
+ oss << "#" << anchor;
+ return oss.str();
+ }; //<! convert this URL to string
+
+ std::string protocol; //<! schema/protocol
+ std::string host; //<! host
+ int port; //<! port
+ std::string username; //<! username
+ std::string password; //<! password
+ std::string path; //<! path
+ std::string parameters; //<! url parameters
+ std::string anchor; //<! anchor
+ bool pathless; //<! whether this url has no path
+
+ URL() { initialize(); }; //<! construct empty url
+ URL(const std::string& url) {
+ parse(url);
+ }; //<! calls parse with url
+
+ URL(const char *url) {
+ parse(std::string(url));
+ }; //<! calls parse with url
+
+ bool parse(const std::string& url) {
+ // setup
+ initialize();
+
+ if (url.size() > YAHTTP_MAX_URL_LENGTH) return false;
+ size_t pos = 0;
+ if (*(url.begin()) != '/') { // full url?
+ if (parseSchema(url, pos) == false) return false;
+ if (pathless) {
+ parameters = url.substr(pos);
+ return true;
+ }
+ if (parseUserPass(url, pos) == false) return false;
+ if (parseHost(url, pos) == false) return false;
+ }
+ if (parsePath(url, pos) == false) return false;
+ if (parseParameters(url, pos) == false) return false;
+ return parseAnchor(url, pos);
+ }; //<! parse various formats of urls ranging from http://example.com/foo?bar=baz into data:base64:d089swt64wt...
+
+ friend std::ostream & operator<<(std::ostream& os, const URL& url) {
+ os<<url.to_string();
+ return os;
+ };
+ };
+};
+#endif
--- /dev/null
+#ifndef _YAHTTP_UTILITY_HPP
+#define _YAHTTP_UTILITY_HPP 1
+
+namespace YaHTTP {
+ static const char *MONTHS[] = {0,"Jan","Feb","Mar","Apr","May","Jun","Jul","Aug","Sep","Oct","Nov","Dec",0}; //<! List of months
+ static const char *DAYS[] = {"Sun","Mon","Tue","Wed","Thu","Fri","Sat",0}; //<! List of days
+
+ bool isspace(char c);
+ bool isspace(char c, const std::locale& loc);
+ bool isxdigit(char c);
+ bool isxdigit(char c, const std::locale& loc);
+ bool isdigit(char c);
+ bool isdigit(char c, const std::locale& loc);
+ bool isalnum(char c);
+ bool isalnum(char c, const std::locale& loc);
+
+ /*! Case-Insensitive NULL safe comparator for string maps */
+ struct ASCIICINullSafeComparator {
+ bool operator() (const std::string& lhs, const std::string& rhs) const {
+ int v;
+ std::string::const_iterator lhi = lhs.begin();
+ std::string::const_iterator rhi = rhs.begin();
+ for(;lhi != lhs.end() && rhi != rhs.end(); lhi++, rhi++)
+ if ((v = ::tolower(*lhi) - ::tolower(*rhi)) != 0) return v<0;
+ if (lhi == lhs.end() && rhi != rhs.end()) return true;
+ if (lhi != lhs.end() && rhi == rhs.end()) return false;
+ return false; // they are equal
+ }
+ };
+
+ typedef std::map<std::string,std::string,ASCIICINullSafeComparator> strstr_map_t; //<! String to String map
+
+ /*! Represents a date/time with utc offset */
+ class DateTime {
+ public:
+ bool isSet; //<! if this is initialized yet
+
+ int year; //<! year, 0 is year 0, not 1900
+
+ int month; //<! month, range 1-12
+ int day; //<! day, range 1-31
+ int wday; //<! week day, range 1-7
+
+ int hours; //<! hours, range 0-23
+ int minutes; //<! minutes, range 0-59
+ int seconds; //<! seconds, range 0-60
+
+ int utc_offset; //<! UTC offset with minutes (hhmm)
+
+ DateTime() {
+ initialize();
+ }; //<! Construct and initialize
+
+ void initialize() {
+ isSet = false;
+ year = month = day = wday = hours = minutes = seconds = utc_offset = 0;
+ month = 1; // it's invalid otherwise
+ }; //<! Creates year 0 date
+
+ void setLocal() {
+ fromLocaltime(time((time_t*)NULL));
+ }; //<! sets current local time
+
+ void setGm() {
+ fromGmtime(time((time_t*)NULL));
+ }; //<! sets current gmtime (almost UTC)
+
+ void fromLocaltime(time_t t) {
+#ifdef HAVE_LOCALTIME_R
+ struct tm tm;
+ localtime_r(&t, &tm);
+ fromTm(&tm);
+#else
+ struct tm *tm;
+ tm = localtime(&t);
+ fromTm(tm);
+#endif
+#ifndef HAVE_TM_GMTOFF
+ time_t t2;
+# ifdef HAVE_LOCALTIME_R
+ gmtime_r(&t, &tm);
+ t2 = mktime(&tm);
+# else
+ tm = gmtime(&t);
+ t2 = mktime(tm);
+# endif
+ this->utc_offset = ((t2-t)/10)*10; // removes any possible differences.
+#endif
+ }; //<! uses localtime for time
+
+ void fromGmtime(time_t t) {
+#ifdef HAVE_GMTIME_R
+ struct tm tm;
+ gmtime_r(&t, &tm);
+ fromTm(&tm);
+#else
+ struct tm *tm;
+ tm = gmtime(&t);
+ fromTm(tm);
+#endif
+#ifndef HAVE_TM_GMTOFF
+ this->utc_offset = 0;
+#endif
+ }; //<! uses gmtime for time
+
+ void fromTm(const struct tm *tm) {
+ year = tm->tm_year + 1900;
+ month = tm->tm_mon + 1;
+ day = tm->tm_mday;
+ hours = tm->tm_hour;
+ minutes = tm->tm_min;
+ seconds = tm->tm_sec;
+ wday = tm->tm_wday;
+#ifdef HAVE_TM_GMTOFF
+ utc_offset = tm->tm_gmtoff;
+#endif
+ isSet = true;
+ }; //<! parses date from struct tm
+
+ void validate() const {
+ if (wday < 0 || wday > 6) throw std::range_error("Invalid date");
+ if (month < 1 || month > 12) throw std::range_error("Invalid date");
+ if (year < 0) throw std::range_error("Invalid date");
+ if (hours < 0 || hours > 23 ||
+ minutes < 0 || minutes > 59 ||
+ seconds < 0 || seconds > 60) throw std::range_error("Invalid date");
+ }; //<! make sure we are within ranges (not a *REAL* validation, just range check)
+
+ std::string rfc_str() const {
+ std::ostringstream oss;
+ validate();
+ oss << DAYS[wday] << ", " << std::setfill('0') << std::setw(2) << day << " " << MONTHS[month] << " " <<
+ std::setfill('0') << std::setw(2) << year << " " <<
+ std::setfill('0') << std::setw(2) << hours << ":" <<
+ std::setfill('0') << std::setw(2) << minutes << ":" <<
+ std::setfill('0') << std::setw(2) << seconds << " ";
+ if (utc_offset>=0) oss << "+";
+ else oss << "-";
+ int tmp_off = ( utc_offset < 0 ? utc_offset*-1 : utc_offset );
+ oss << std::setfill('0') << std::setw(2) << (tmp_off/3600);
+ oss << std::setfill('0') << std::setw(2) << (tmp_off%3600)/60;
+
+ return oss.str();
+ }; //<! converts this date into a RFC-822 format
+
+ std::string cookie_str() const {
+ std::ostringstream oss;
+ validate();
+ oss << std::setfill('0') << std::setw(2) << day << "-" << MONTHS[month] << "-" << year << " " <<
+ std::setfill('0') << std::setw(2) << hours << ":" <<
+ std::setfill('0') << std::setw(2) << minutes << ":" <<
+ std::setfill('0') << std::setw(2) << seconds << " GMT";
+ return oss.str();
+ }; //<! converts this date into a HTTP Cookie date
+
+ void parse822(const std::string &rfc822_date) {
+ struct tm tm;
+ const char *ptr;
+#ifdef HAVE_TM_GMTOFF
+ if ( (ptr = strptime(rfc822_date.c_str(), "%a, %d %b %Y %T %z", &tm)) != NULL) {
+#else
+ if ( (ptr = strptime(rfc822_date.c_str(), "%a, %d %b %Y %T", &tm)) != NULL) {
+ int sign;
+ // parse the timezone parameter
+ while(*ptr && YaHTTP::isspace(*ptr)) ptr++;
+ if (*ptr == '+') sign = 0;
+ else if (*ptr == '-') sign = -1;
+ else throw YaHTTP::ParseError("Unparseable date");
+ ptr++;
+ utc_offset = ::atoi(ptr) * sign;
+ while(*ptr != '\0' && YaHTTP::isdigit(*ptr)) ptr++;
+#endif
+ while(*ptr != '\0' && YaHTTP::isspace(*ptr)) ptr++;
+ if (*ptr != '\0') throw YaHTTP::ParseError("Unparseable date"); // must be final.
+ fromTm(&tm);
+ } else {
+ throw YaHTTP::ParseError("Unparseable date");
+ }
+ }; //<! parses RFC-822 date
+
+ void parseCookie(const std::string &cookie_date) {
+ struct tm tm;
+ const char *ptr;
+ if ( (ptr = strptime(cookie_date.c_str(), "%d-%b-%Y %T", &tm)) != NULL
+#ifdef HAVE_TM_GMTOFF
+ || (ptr = strptime(cookie_date.c_str(), "%d-%b-%Y %T %z", &tm)) != NULL
+ || (ptr = strptime(cookie_date.c_str(), "%a, %d-%b-%Y %T %Z", &tm)) != NULL
+#endif
+ ) {
+ while(*ptr != '\0' && ( YaHTTP::isspace(*ptr) || YaHTTP::isalnum(*ptr) )) ptr++;
+ if (*ptr != '\0') throw YaHTTP::ParseError("Unparseable date (non-final)"); // must be final.
+ fromTm(&tm);
+ this->utc_offset = 0;
+ } else {
+ std::cout << cookie_date << std::endl;
+ throw YaHTTP::ParseError("Unparseable date (did not match pattern cookie)");
+ }
+ }; //<! parses HTTP Cookie date
+
+ time_t unixtime() const {
+ struct tm tm;
+ tm.tm_year = year-1900;
+ tm.tm_mon = month-1;
+ tm.tm_mday = day;
+ tm.tm_hour = hours;
+ tm.tm_min = minutes;
+ tm.tm_sec = seconds;
+ tm.tm_isdst = 0;
+#ifdef HAVE_TM_GMTOFF
+ tm.tm_gmtoff = utc_offset;
+#endif
+ return mktime(&tm);
+ }; //<! returns this datetime as unixtime. will not work for dates before 1970/1/1 00:00:00 GMT
+ };
+
+ /*! Various helpers needed in the code */
+ class Utility {
+ public:
+ static std::string decodeURL(const std::string& component) {
+ std::string result = component;
+ size_t pos1,pos2;
+ pos2 = 0;
+ while((pos1 = result.find_first_of("%", pos2))!=std::string::npos) {
+ std::string code;
+ char a,b,c;
+ if (pos1 + 2 > result.length()) return result; // end of result
+ code = result.substr(pos1+1, 2);
+ a = std::tolower(code[0]); b = std::tolower(code[1]);
+
+ if ((( '0' > a || a > '9') && ('a' > a || a > 'f')) ||
+ (( '0' > b || b > '9') && ('a' > b || b > 'f'))) {
+ pos2 = pos1+3;
+ continue;
+ }
+
+ if ('0' <= a && a <= '9') a = a - '0';
+ if ('a' <= a && a <= 'f') a = a - 'a' + 0x0a;
+ if ('0' <= b && b <= '9') b = b - '0';
+ if ('a' <= b && b <= 'f') b = b - 'a' + 0x0a;
+
+ c = (a<<4)+b;
+ result = result.replace(pos1,3,1,c);
+ pos2=pos1;
+ }
+ return result;
+ }; //<! Decodes %xx from string into bytes
+
+ static std::string encodeURL(const std::string& component, bool asUrl = true) {
+ std::string result = component;
+ std::string skip = "+-.:,&;_#%[]?/@(){}=";
+ char repl[3];
+ size_t pos;
+ for(std::string::iterator iter = result.begin(); iter != result.end(); iter++) {
+ if (!YaHTTP::isalnum(*iter) && (!asUrl || skip.find(*iter) == std::string::npos)) {
+ // replace with different thing
+ pos = std::distance(result.begin(), iter);
+ ::snprintf(repl,3,"%02x", static_cast<unsigned char>(*iter));
+ result = result.replace(pos, 1, "%", 1).insert(pos+1, repl, 2);
+ iter = result.begin() + pos + 2;
+ }
+ }
+ return result;
+ }; //<! Escapes any characters into %xx representation when necessary, set asUrl to false to fully encode the url
+
+ static std::string encodeURL(const std::wstring& component, bool asUrl = true) {
+ unsigned char const *p = reinterpret_cast<unsigned char const*>(&component[0]);
+ std::size_t s = component.size() * sizeof((*component.begin()));
+ std::vector<unsigned char> vec(p, p+s);
+
+ std::ostringstream result;
+ std::string skip = "+-.,&;_#%[]?/@(){}=";
+ for(std::vector<unsigned char>::iterator iter = vec.begin(); iter != vec.end(); iter++) {
+ if (!YaHTTP::isalnum((char)*iter) && (!asUrl || skip.find((char)*iter) == std::string::npos)) {
+ // bit more complex replace
+ result << "%" << std::hex << std::setw(2) << std::setfill('0') << static_cast<unsigned int>(*iter);
+ } else result << (char)*iter;
+ }
+ return result.str();
+ }; //<! Escapes any characters into %xx representation when necessary, set asUrl to false to fully encode the url, for wide strings, returns ordinary string
+
+ static std::string status2text(int status) {
+ switch(status) {
+ case 200:
+ return "OK";
+ case 201:
+ return "Created";
+ case 202:
+ return "Accepted";
+ case 203:
+ return "Non-Authoritative Information";
+ case 204:
+ return "No Content";
+ case 205:
+ return "Reset Content";
+ case 206:
+ return "Partial Content";
+ case 300:
+ return "Multiple Choices";
+ case 301:
+ return "Moved Permanently";
+ case 302:
+ return "Found";
+ case 303:
+ return "See Other";
+ case 304:
+ return "Not Modified";
+ case 305:
+ return "Use Proxy";
+ case 307:
+ return "Temporary Redirect";
+ case 400:
+ return "Bad Request";
+ case 401:
+ return "Unauthorized";
+ case 402:
+ return "Payment Required";
+ case 403:
+ return "Forbidden";
+ case 404:
+ return "Not Found";
+ case 405:
+ return "Method Not Allowed";
+ case 406:
+ return "Not Acceptable";
+ case 407:
+ return "Proxy Authentication Required";
+ case 408:
+ return "Request Time-out";
+ case 409:
+ return "Conflict";
+ case 410:
+ return "Gone";
+ case 411:
+ return "Length Required";
+ case 412:
+ return "Precondition Failed";
+ case 413:
+ return "Request Entity Too Large";
+ case 414:
+ return "Request-URI Too Large";
+ case 415:
+ return "Unsupported Media Type";
+ case 416:
+ return "Requested range not satisfiable";
+ case 417:
+ return "Expectation Failed";
+ case 422:
+ return "Unprocessable Entity";
+ case 500:
+ return "Internal Server Error";
+ case 501:
+ return "Not Implemented";
+ case 502:
+ return "Bad Gateway";
+ case 503:
+ return "Service Unavailable";
+ case 504:
+ return "Gateway Time-out";
+ case 505:
+ return "HTTP Version not supported";
+ default:
+ return "Unknown Status";
+ }
+ }; //<! static HTTP codes to text mappings
+
+ static strstr_map_t parseUrlParameters(std::string parameters) {
+ std::string::size_type pos = 0;
+ strstr_map_t parameter_map;
+ while (pos != std::string::npos) {
+ // find next parameter start
+ std::string::size_type nextpos = parameters.find("&", pos);
+ std::string::size_type delim = parameters.find("=", pos);
+ if (delim > nextpos) {
+ delim = nextpos;
+ }
+ std::string key;
+ std::string value;
+ if (delim == std::string::npos) {
+ key = parameters.substr(pos);
+ } else {
+ key = parameters.substr(pos, delim-pos);
+ if (nextpos == std::string::npos) {
+ value = parameters.substr(delim+1);
+ } else {
+ value = parameters.substr(delim+1, nextpos-delim-1);
+ }
+ }
+ if (key.empty()) {
+ // no parameters at all
+ break;
+ }
+ key = decodeURL(key);
+ value = decodeURL(value);
+ parameter_map[key] = value;
+ if (nextpos == std::string::npos) {
+ // no more parameters left
+ break;
+ }
+
+ pos = nextpos+1;
+ }
+ return parameter_map;
+ }; //<! parses URL parameters into string map
+
+ static bool iequals(const std::string& a, const std::string& b, size_t length) {
+ std::string::const_iterator ai, bi;
+ size_t i;
+ for(ai = a.begin(), bi = b.begin(), i = 0; ai != a.end() && bi != b.end() && i < length; ai++,bi++,i++) {
+ if (::toupper(*ai) != ::toupper(*bi)) return false;
+ }
+
+ if (ai == a.end() && bi == b.end()) return true;
+ if ((ai == a.end() && bi != b.end()) ||
+ (ai != a.end() && bi == b.end())) return false;
+
+ return ::toupper(*ai) == ::toupper(*bi);
+ }; //<! case-insensitive comparison with length
+
+ static bool iequals(const std::string& a, const std::string& b) {
+ if (a.size() != b.size()) return false;
+ return iequals(a,b,a.size());
+ }; //<! case-insensitive comparison
+
+ static void trimLeft(std::string &str) {
+ const std::locale &loc = std::locale::classic();
+ std::string::iterator iter = str.begin();
+ while(iter != str.end() && YaHTTP::isspace(*iter, loc)) iter++;
+ str.erase(str.begin(), iter);
+ }; //<! removes whitespace from left
+
+ static void trimRight(std::string &str) {
+ const std::locale &loc = std::locale::classic();
+ std::string::reverse_iterator iter = str.rbegin();
+ while(iter != str.rend() && YaHTTP::isspace(*iter, loc)) iter++;
+ str.erase(iter.base(), str.end());
+ }; //<! removes whitespace from right
+
+ static void trim(std::string &str) {
+ trimLeft(str);
+ trimRight(str);
+ }; //<! removes whitespace from left and right
+
+ static std::string camelizeHeader(const std::string &str) {
+ std::string::const_iterator iter = str.begin();
+ std::string result;
+ const std::locale &loc = std::locale::classic();
+
+ bool doNext = true;
+
+ while(iter != str.end()) {
+ if (doNext)
+ result.insert(result.end(), std::toupper(*iter, loc));
+ else
+ result.insert(result.end(), std::tolower(*iter, loc));
+ doNext = (*(iter++) == '-');
+ }
+
+ return result;
+ }; //<! camelizes headers, such as, content-type => Content-Type
+ };
+};
+#endif
--- /dev/null
+#include "config.h"
--- /dev/null
+#include <map>
+#include <iostream>
+#include <locale>
+#include <algorithm>
+#include <string>
+#include <cstdio>
+#include <stdexcept>
+#include <sys/time.h>
+#include <iomanip>
+#include <list>
+#include <vector>
+
+#include "yahttp-config.h"
+#include "exception.hpp"
+#include "url.hpp"
+#include "utility.hpp"
+#include "url.hpp"
+#include "cookie.hpp"
+#include "reqresp.hpp"
+
+/*! \mainpage Yet Another HTTP Library Documentation
+\section sec_quick_start Quick start example
+
+@code
+#include <yahttp/yahttp.hpp>
+
+int main(void) {
+ std::ifstream ifs("request.txt");
+ YaHTTP::Request req;
+ ifs >> req;
+
+ std::cout << req.method " " << req.url.path << std::endl;
+ return 0;
+}
+@endcode
+\author Aki Tuomi
+*/
--- /dev/null
+AC_DEFUN([AX_ARG_DEFAULT_ENABLE], [
+AC_ARG_ENABLE([$1], AS_HELP_STRING([--disable-$1], [$2 (default is ENABLED)]))
+AX_PARSE_VALUE([$1], [y])
+])
+
+AC_DEFUN([AX_ARG_DEFAULT_DISABLE], [
+AC_ARG_ENABLE([$1], AS_HELP_STRING([--enable-$1], [$2 (default is DISABLED)]))
+AX_PARSE_VALUE([$1], [n])
+])
+
+dnl This function should not be called outside of this file
+AC_DEFUN([AX_PARSE_VALUE], [
+AS_IF([test "x$enable_$1" = "xno"], [
+ ax_cv_$1="n"
+], [test "x$enable_$1" = "xyes"], [
+ ax_cv_$1="y"
+], [test -z $ax_cv_$1], [
+ ax_cv_$1="$2"
+])
+$1=$ax_cv_$1
+AC_SUBST($1)])
--- /dev/null
+# ===========================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_check_link_flag.html
+# ===========================================================================
+#
+# SYNOPSIS
+#
+# AX_CHECK_LINK_FLAG(FLAG, [ACTION-SUCCESS], [ACTION-FAILURE], [EXTRA-FLAGS], [INPUT])
+#
+# DESCRIPTION
+#
+# Check whether the given FLAG works with the linker or gives an error.
+# (Warnings, however, are ignored)
+#
+# ACTION-SUCCESS/ACTION-FAILURE are shell commands to execute on
+# success/failure.
+#
+# If EXTRA-FLAGS is defined, it is added to the linker's default flags
+# when the check is done. The check is thus made with the flags: "LDFLAGS
+# EXTRA-FLAGS FLAG". This can for example be used to force the linker to
+# issue an error when a bad flag is given.
+#
+# INPUT gives an alternative input source to AC_LINK_IFELSE.
+#
+# NOTE: Implementation based on AX_CFLAGS_GCC_OPTION. Please keep this
+# macro in sync with AX_CHECK_{PREPROC,COMPILE}_FLAG.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Guido U. Draheim <guidod@gmx.de>
+# Copyright (c) 2011 Maarten Bosmans <mkbosmans@gmail.com>
+#
+# This program is free software: you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation, either version 3 of the License, or (at your
+# option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+# Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# As a special exception, the respective Autoconf Macro's copyright owner
+# gives unlimited permission to copy, distribute and modify the configure
+# scripts that are the output of Autoconf when processing the Macro. You
+# need not follow the terms of the GNU General Public License when using
+# or distributing such scripts, even though portions of the text of the
+# Macro appear in them. The GNU General Public License (GPL) does govern
+# all other use of the material that constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the Autoconf
+# Macro released by the Autoconf Archive. When you make and distribute a
+# modified version of the Autoconf Macro, you may extend this special
+# exception to the GPL to apply to your modified version as well.
+
+#serial 4
+
+AC_DEFUN([AX_CHECK_LINK_FLAG],
+[AC_PREREQ(2.64)dnl for _AC_LANG_PREFIX and AS_VAR_IF
+AS_VAR_PUSHDEF([CACHEVAR],[ax_cv_check_ldflags_$4_$1])dnl
+AC_CACHE_CHECK([whether the linker accepts $1], CACHEVAR, [
+ ax_check_save_flags=$LDFLAGS
+ LDFLAGS="$LDFLAGS $4 $1"
+ AC_LINK_IFELSE([m4_default([$5],[AC_LANG_PROGRAM()])],
+ [AS_VAR_SET(CACHEVAR,[yes])],
+ [AS_VAR_SET(CACHEVAR,[no])])
+ LDFLAGS=$ax_check_save_flags])
+AS_VAR_IF(CACHEVAR,yes,
+ [m4_default([$2], :)],
+ [m4_default([$3], :)])
+AS_VAR_POPDEF([CACHEVAR])dnl
+])dnl AX_CHECK_LINK_FLAGS
--- /dev/null
+# ============================================================================
+# http://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx_11.html
+# ============================================================================
+#
+# SYNOPSIS
+#
+# AX_CXX_COMPILE_STDCXX_11([ext|noext],[mandatory|optional])
+#
+# DESCRIPTION
+#
+# Check for baseline language coverage in the compiler for the C++11
+# standard; if necessary, add switches to CXXFLAGS to enable support.
+#
+# The first argument, if specified, indicates whether you insist on an
+# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
+# -std=c++11). If neither is specified, you get whatever works, with
+# preference for an extended mode.
+#
+# The second argument, if specified 'mandatory' or if left unspecified,
+# indicates that baseline C++11 support is required and that the macro
+# should error out if no mode with that support is found. If specified
+# 'optional', then configuration proceeds regardless, after defining
+# HAVE_CXX11 if and only if a supporting mode is found.
+#
+# LICENSE
+#
+# Copyright (c) 2008 Benjamin Kosnik <bkoz@redhat.com>
+# Copyright (c) 2012 Zack Weinberg <zackw@panix.com>
+# Copyright (c) 2013 Roy Stogner <roystgnr@ices.utexas.edu>
+# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <sokolov@google.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 10
+
+m4_define([_AX_CXX_COMPILE_STDCXX_11_testbody], [[
+ template <typename T>
+ struct check
+ {
+ static_assert(sizeof(int) <= sizeof(T), "not big enough");
+ };
+
+ struct Base {
+ virtual void f() {}
+ };
+ struct Child : public Base {
+ virtual void f() override {}
+ };
+
+ typedef check<check<bool>> right_angle_brackets;
+
+ int a;
+ decltype(a) b;
+
+ typedef check<int> check_type;
+ check_type c;
+ check_type&& cr = static_cast<check_type&&>(c);
+
+ auto d = a;
+ auto l = [](){};
+ // Prevent Clang error: unused variable 'l' [-Werror,-Wunused-variable]
+ struct use_l { use_l() { l(); } };
+
+ // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
+ // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function because of this
+ namespace test_template_alias_sfinae {
+ struct foo {};
+
+ template<typename T>
+ using member = typename T::member_type;
+
+ template<typename T>
+ void func(...) {}
+
+ template<typename T>
+ void func(member<T>*) {}
+
+ void test();
+
+ void test() {
+ func<foo>(0);
+ }
+ }
+]])
+
+AC_DEFUN([AX_CXX_COMPILE_STDCXX_11], [dnl
+ m4_if([$1], [], [],
+ [$1], [ext], [],
+ [$1], [noext], [],
+ [m4_fatal([invalid argument `$1' to AX_CXX_COMPILE_STDCXX_11])])dnl
+ m4_if([$2], [], [ax_cxx_compile_cxx11_required=true],
+ [$2], [mandatory], [ax_cxx_compile_cxx11_required=true],
+ [$2], [optional], [ax_cxx_compile_cxx11_required=false],
+ [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX_11])])
+ AC_LANG_PUSH([C++])dnl
+ ac_success=no
+ AC_CACHE_CHECK(whether $CXX supports C++11 features by default,
+ ax_cv_cxx_compile_cxx11,
+ [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+ [ax_cv_cxx_compile_cxx11=yes],
+ [ax_cv_cxx_compile_cxx11=no])])
+ if test x$ax_cv_cxx_compile_cxx11 = xyes; then
+ ac_success=yes
+ fi
+
+ m4_if([$1], [noext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=gnu++11 -std=gnu++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+
+ m4_if([$1], [ext], [], [dnl
+ if test x$ac_success = xno; then
+ for switch in -std=c++11 -std=c++0x; do
+ cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx11_$switch])
+ AC_CACHE_CHECK(whether $CXX supports C++11 features with $switch,
+ $cachevar,
+ [ac_save_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="$CXXFLAGS $switch"
+ AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_11_testbody])],
+ [eval $cachevar=yes],
+ [eval $cachevar=no])
+ CXXFLAGS="$ac_save_CXXFLAGS"])
+ if eval test x\$$cachevar = xyes; then
+ CXXFLAGS="$CXXFLAGS $switch"
+ ac_success=yes
+ break
+ fi
+ done
+ fi])
+ AC_LANG_POP([C++])
+ if test x$ax_cxx_compile_cxx11_required = xtrue; then
+ if test x$ac_success = xno; then
+ AC_MSG_ERROR([*** A compiler with support for C++11 language features is required.])
+ fi
+ else
+ if test x$ac_success = xno; then
+ HAVE_CXX11=0
+ AC_MSG_NOTICE([No compiler with C++11 support was found])
+ else
+ HAVE_CXX11=1
+ AC_DEFINE(HAVE_CXX11,1,
+ [define if the compiler supports basic C++11 syntax])
+ fi
+
+ AC_SUBST(HAVE_CXX11)
+ fi
+])
--- /dev/null
+# boost.m4: Locate Boost headers and libraries for autoconf-based projects.
+# Copyright (C) 2007-2011, 2014 Benoit Sigoure <tsuna@lrde.epita.fr>
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# Additional permission under section 7 of the GNU General Public
+# License, version 3 ("GPLv3"):
+#
+# If you convey this file as part of a work that contains a
+# configuration script generated by Autoconf, you may do so under
+# terms of your choice.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+m4_define([_BOOST_SERIAL], [m4_translit([
+# serial 26 PowerDNS modified
+], [#
+], [])])
+
+# Original sources can be found at http://github.com/tsuna/boost.m4
+# You can fetch the latest version of the script by doing:
+# wget http://github.com/tsuna/boost.m4/raw/master/build-aux/boost.m4
+
+# ------ #
+# README #
+# ------ #
+
+# This file provides several macros to use the various Boost libraries.
+# The first macro is BOOST_REQUIRE. It will simply check if it's possible to
+# find the Boost headers of a given (optional) minimum version and it will
+# define BOOST_CPPFLAGS accordingly. It will add an option --with-boost to
+# your configure so that users can specify non standard locations.
+# If the user's environment contains BOOST_ROOT and --with-boost was not
+# specified, --with-boost=$BOOST_ROOT is implicitly used.
+# For more README and documentation, go to http://github.com/tsuna/boost.m4
+# Note: THESE MACROS ASSUME THAT YOU USE LIBTOOL. If you don't, don't worry,
+# simply read the README, it will show you what to do step by step.
+
+m4_pattern_forbid([^_?(BOOST|Boost)_])
+
+
+# _BOOST_SED_CPP(SED-PROGRAM, PROGRAM,
+# [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+# --------------------------------------------------------
+# Same as AC_EGREP_CPP, but leave the result in conftest.i.
+#
+# SED-PROGRAM is *not* overquoted, as in AC_EGREP_CPP. It is expanded
+# in double-quotes, so escape your double quotes.
+#
+# It could be useful to turn this into a macro which extracts the
+# value of any macro.
+m4_define([_BOOST_SED_CPP],
+[AC_LANG_PUSH([C++])dnl
+AC_LANG_PREPROC_REQUIRE()dnl
+AC_REQUIRE([AC_PROG_SED])dnl
+AC_LANG_CONFTEST([AC_LANG_SOURCE([[$2]])])
+AS_IF([dnl eval is necessary to expand ac_cpp.
+dnl Ultrix and Pyramid sh refuse to redirect output of eval, so use subshell.
+dnl Beware of Windows end-of-lines, for instance if we are running
+dnl some Windows programs under Wine. In that case, boost/version.hpp
+dnl is certainly using "\r\n", but the regular Unix shell will only
+dnl strip `\n' with backquotes, not the `\r'. This results in
+dnl boost_cv_lib_version='1_37\r' for instance, which breaks
+dnl everything else.
+dnl Cannot use 'dnl' after [$4] because a trailing dnl may break AC_CACHE_CHECK
+dnl
+dnl Beware that GCC 5, when expanding macros, may embed # line directives
+dnl a within single line:
+dnl
+dnl # 1 "conftest.cc"
+dnl # 1 "<built-in>"
+dnl # 1 "<command-line>"
+dnl # 1 "conftest.cc"
+dnl # 1 "/opt/local/include/boost/version.hpp" 1 3
+dnl # 2 "conftest.cc" 2
+dnl boost-lib-version =
+dnl # 2 "conftest.cc" 3
+dnl "1_56"
+dnl
+dnl So get rid of the # and empty lines, and glue the remaining ones together.
+(eval "$ac_cpp conftest.$ac_ext") 2>&AS_MESSAGE_LOG_FD |
+ grep -v '#' |
+ grep -v '^[[[:space:]]]*$' |
+ tr -d '\r' |
+ tr -s '\n' ' ' |
+ $SED -n -e "$1" >conftest.i 2>&1],
+ [$3],
+ [$4])
+rm -rf conftest*
+AC_LANG_POP([C++])dnl
+])# _BOOST_SED_CPP
+
+
+
+# BOOST_REQUIRE([VERSION], [ACTION-IF-NOT-FOUND])
+# -----------------------------------------------
+# Look for Boost. If version is given, it must either be a literal of the form
+# "X.Y.Z" where X, Y and Z are integers (the ".Z" part being optional) or a
+# variable "$var".
+# Defines the value BOOST_CPPFLAGS. This macro only checks for headers with
+# the required version, it does not check for any of the Boost libraries.
+# On # success, defines HAVE_BOOST. On failure, calls the optional
+# ACTION-IF-NOT-FOUND action if one was supplied.
+# Otherwise aborts with an error message.
+AC_DEFUN_ONCE([BOOST_REQUIRE],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_PROG_GREP])dnl
+echo "$as_me: this is boost.m4[]_BOOST_SERIAL" >&AS_MESSAGE_LOG_FD
+boost_save_IFS=$IFS
+boost_version_req=$1
+IFS=.
+set x $boost_version_req 0 0 0
+IFS=$boost_save_IFS
+shift
+boost_version_req=`expr "$[1]" '*' 100000 + "$[2]" '*' 100 + "$[3]"`
+boost_version_req_string=$[1].$[2].$[3]
+AC_ARG_WITH([boost],
+ [AS_HELP_STRING([--with-boost=DIR],
+ [prefix of Boost $1 @<:@guess@:>@])])dnl
+AC_ARG_VAR([BOOST_ROOT],[Location of Boost installation])dnl
+# If BOOST_ROOT is set and the user has not provided a value to
+# --with-boost, then treat BOOST_ROOT as if it the user supplied it.
+if test x"$BOOST_ROOT" != x; then
+ if test x"$with_boost" = x; then
+ AC_MSG_NOTICE([Detected BOOST_ROOT; continuing with --with-boost=$BOOST_ROOT])
+ with_boost=$BOOST_ROOT
+ else
+ AC_MSG_NOTICE([Detected BOOST_ROOT=$BOOST_ROOT, but overridden by --with-boost=$with_boost])
+ fi
+fi
+AC_SUBST([DISTCHECK_CONFIGURE_FLAGS],
+ ["$DISTCHECK_CONFIGURE_FLAGS '--with-boost=$with_boost'"])dnl
+boost_save_CPPFLAGS=$CPPFLAGS
+ AC_CACHE_CHECK([for Boost headers version >= $boost_version_req_string],
+ [boost_cv_inc_path],
+ [boost_cv_inc_path=no
+AC_LANG_PUSH([C++])dnl
+m4_pattern_allow([^BOOST_VERSION$])dnl
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([[#include <boost/version.hpp>
+#if !defined BOOST_VERSION
+# error BOOST_VERSION is not defined
+#elif BOOST_VERSION < $boost_version_req
+# error Boost headers version < $boost_version_req
+#endif
+]])])
+ # If the user provided a value to --with-boost, use it and only it.
+ case $with_boost in #(
+ ''|yes) set x '' /opt/local/include /usr/local/include /opt/include \
+ /usr/include C:/Boost/include;; #(
+ *) set x "$with_boost/include" "$with_boost";;
+ esac
+ shift
+ for boost_dir
+ do
+ # Without --layout=system, Boost (or at least some versions) installs
+ # itself in <prefix>/include/boost-<version>. This inner loop helps to
+ # find headers in such directories.
+ #
+ # Any ${boost_dir}/boost-x_xx directories are searched in reverse version
+ # order followed by ${boost_dir}. The final '.' is a sentinel for
+ # searching $boost_dir" itself. Entries are whitespace separated.
+ #
+ # I didn't indent this loop on purpose (to avoid over-indented code)
+ boost_layout_system_search_list=`cd "$boost_dir" 2>/dev/null \
+ && ls -1 | "${GREP}" '^boost-' | sort -rn -t- -k2 \
+ && echo .`
+ for boost_inc in $boost_layout_system_search_list
+ do
+ if test x"$boost_inc" != x.; then
+ boost_inc="$boost_dir/$boost_inc"
+ else
+ boost_inc="$boost_dir" # Uses sentinel in boost_layout_system_search_list
+ fi
+ if test x"$boost_inc" != x; then
+ # We are going to check whether the version of Boost installed
+ # in $boost_inc is usable by running a compilation that
+ # #includes it. But if we pass a -I/some/path in which Boost
+ # is not installed, the compiler will just skip this -I and
+ # use other locations (either from CPPFLAGS, or from its list
+ # of system include directories). As a result we would use
+ # header installed on the machine instead of the /some/path
+ # specified by the user. So in that precise case (trying
+ # $boost_inc), make sure the version.hpp exists.
+ #
+ # Use test -e as there can be symlinks.
+ test -e "$boost_inc/boost/version.hpp" || continue
+ CPPFLAGS="$CPPFLAGS -I$boost_inc"
+ fi
+ AC_COMPILE_IFELSE([], [boost_cv_inc_path=yes], [boost_cv_version=no])
+ if test x"$boost_cv_inc_path" = xyes; then
+ if test x"$boost_inc" != x; then
+ boost_cv_inc_path=$boost_inc
+ fi
+ break 2
+ fi
+ done
+ done
+AC_LANG_POP([C++])dnl
+ ])
+ case $boost_cv_inc_path in #(
+ no)
+ boost_errmsg="cannot find Boost headers version >= $boost_version_req_string"
+ m4_if([$2], [], [AC_MSG_ERROR([$boost_errmsg])],
+ [AC_MSG_NOTICE([$boost_errmsg])])
+ $2
+ ;;#(
+ yes)
+ BOOST_CPPFLAGS=
+ ;;#(
+ *)
+ AC_SUBST([BOOST_CPPFLAGS], ["-I$boost_cv_inc_path"])dnl
+ ;;
+ esac
+ if test x"$boost_cv_inc_path" != xno; then
+ AC_DEFINE([HAVE_BOOST], [1],
+ [Defined if the requested minimum BOOST version is satisfied])
+ AC_CACHE_CHECK([for Boost's header version],
+ [boost_cv_lib_version],
+ [m4_pattern_allow([^BOOST_LIB_VERSION$])dnl
+ _BOOST_SED_CPP([[/^boost-lib-version = /{s///;s/[\" ]//g;p;q;}]],
+ [#include <boost/version.hpp>
+boost-lib-version = BOOST_LIB_VERSION],
+ [boost_cv_lib_version=`cat conftest.i`])])
+ # e.g. "134" for 1_34_1 or "135" for 1_35
+ boost_major_version=`echo "$boost_cv_lib_version" | sed 's/_//;s/_.*//'`
+ case $boost_major_version in #(
+ '' | *[[!0-9]]*)
+ AC_MSG_ERROR([invalid value: boost_major_version='$boost_major_version'])
+ ;;
+ esac
+fi
+CPPFLAGS=$boost_save_CPPFLAGS
+])# BOOST_REQUIRE
+
+
+# BOOST_STATIC()
+# --------------
+# Add the "--enable-static-boost" configure argument. If this argument is given
+# on the command line, static versions of the libraries will be looked up.
+AC_DEFUN([BOOST_STATIC],
+ [AC_ARG_ENABLE([static-boost],
+ [AS_HELP_STRING([--enable-static-boost],
+ [Prefer the static boost libraries over the shared ones [no]])],
+ [enable_static_boost=yes],
+ [enable_static_boost=no])])# BOOST_STATIC
+
+
+# BOOST_FIND_HEADER([HEADER-NAME], [ACTION-IF-NOT-FOUND], [ACTION-IF-FOUND])
+# --------------------------------------------------------------------------
+# Wrapper around AC_CHECK_HEADER for Boost headers. Useful to check for
+# some parts of the Boost library which are only made of headers and don't
+# require linking (such as Boost.Foreach).
+#
+# Default ACTION-IF-NOT-FOUND: Fail with a fatal error unless Boost couldn't be
+# found in the first place, in which case by default a notice is issued to the
+# user. Presumably if we haven't died already it's because it's OK to not have
+# Boost, which is why only a notice is issued instead of a hard error.
+#
+# Default ACTION-IF-FOUND: define the preprocessor symbol HAVE_<HEADER-NAME> in
+# case of success # (where HEADER-NAME is written LIKE_THIS, e.g.,
+# HAVE_BOOST_FOREACH_HPP).
+AC_DEFUN([BOOST_FIND_HEADER],
+[AC_REQUIRE([BOOST_REQUIRE])dnl
+if test x"$boost_cv_inc_path" = xno; then
+ m4_default([$2], [AC_MSG_NOTICE([Boost not available, not searching for $1])])
+else
+AC_LANG_PUSH([C++])dnl
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+AC_CHECK_HEADER([$1],
+ [m4_default([$3], [AC_DEFINE(AS_TR_CPP([HAVE_$1]), [1],
+ [Define to 1 if you have <$1>])])],
+ [m4_default([$2], [AC_MSG_ERROR([cannot find $1])])])
+CPPFLAGS=$boost_save_CPPFLAGS
+AC_LANG_POP([C++])dnl
+fi
+])# BOOST_FIND_HEADER
+
+
+# BOOST_FIND_LIBS([COMPONENT-NAME], [CANDIDATE-LIB-NAMES],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Look for the Boost library COMPONENT-NAME (e.g., `thread', for
+# libboost_thread) under the possible CANDIDATE-LIB-NAMES (e.g.,
+# "thread_win32 thread"). Check that HEADER-NAME works and check that
+# libboost_LIB-NAME can link with the code CXX-TEST. The optional
+# argument CXX-PROLOGUE can be used to include some C++ code before
+# the `main' function.
+#
+# Invokes BOOST_FIND_HEADER([HEADER-NAME]) (see above).
+#
+# Boost libraries typically come compiled with several flavors (with different
+# runtime options) so PREFERRED-RT-OPT is the preferred suffix. A suffix is one
+# or more of the following letters: sgdpn (in that order). s = static
+# runtime, d = debug build, g = debug/diagnostic runtime, p = STLPort build,
+# n = (unsure) STLPort build without iostreams from STLPort (it looks like `n'
+# must always be used along with `p'). Additionally, PREFERRED-RT-OPT can
+# start with `mt-' to indicate that there is a preference for multi-thread
+# builds. Some sample values for PREFERRED-RT-OPT: (nothing), mt, d, mt-d, gdp
+# ... If you want to make sure you have a specific version of Boost
+# (eg, >= 1.33) you *must* invoke BOOST_REQUIRE before this macro.
+AC_DEFUN([BOOST_FIND_LIBS],
+[AC_REQUIRE([BOOST_REQUIRE])dnl
+AC_REQUIRE([_BOOST_FIND_COMPILER_TAG])dnl
+AC_REQUIRE([BOOST_STATIC])dnl
+AC_REQUIRE([_BOOST_GUESS_WHETHER_TO_USE_MT])dnl
+if test x"$boost_cv_inc_path" = xno; then
+ AC_MSG_NOTICE([Boost not available, not searching for the Boost $1 library])
+else
+dnl The else branch is huge and wasn't intended on purpose.
+AC_LANG_PUSH([C++])dnl
+AS_VAR_PUSHDEF([Boost_lib], [boost_cv_lib_$1])dnl
+AS_VAR_PUSHDEF([Boost_lib_LDFLAGS], [boost_cv_lib_$1_LDFLAGS])dnl
+AS_VAR_PUSHDEF([Boost_lib_LDPATH], [boost_cv_lib_$1_LDPATH])dnl
+AS_VAR_PUSHDEF([Boost_lib_LIBS], [boost_cv_lib_$1_LIBS])dnl
+BOOST_FIND_HEADER([$4])
+boost_save_CPPFLAGS=$CPPFLAGS
+CPPFLAGS="$CPPFLAGS $BOOST_CPPFLAGS"
+AC_CACHE_CHECK([for the Boost $1 library], [Boost_lib],
+ [_BOOST_FIND_LIBS($@)])
+case $Boost_lib in #(
+ (yes) _AC_MSG_LOG_CONFTEST
+ AC_DEFINE(AS_TR_CPP([HAVE_BOOST_$1]), [1], [Defined if the Boost $1 library is available])dnl
+ AC_SUBST(AS_TR_CPP([BOOST_$1_LDFLAGS]), [$Boost_lib_LDFLAGS])dnl
+ AC_SUBST(AS_TR_CPP([BOOST_$1_LDPATH]), [$Boost_lib_LDPATH])dnl
+ AC_SUBST([BOOST_LDPATH], [$Boost_lib_LDPATH])dnl
+ AC_SUBST(AS_TR_CPP([BOOST_$1_LIBS]), [$Boost_lib_LIBS])dnl
+ ;;
+esac
+CPPFLAGS=$boost_save_CPPFLAGS
+AS_VAR_POPDEF([Boost_lib])dnl
+AS_VAR_POPDEF([Boost_lib_LDFLAGS])dnl
+AS_VAR_POPDEF([Boost_lib_LDPATH])dnl
+AS_VAR_POPDEF([Boost_lib_LIBS])dnl
+AC_LANG_POP([C++])dnl
+fi
+])
+
+
+# BOOST_FIND_LIB([LIB-NAME],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Backward compatibility wrapper for BOOST_FIND_LIBS.
+AC_DEFUN([BOOST_FIND_LIB],
+[BOOST_FIND_LIBS([$1], $@)])
+
+
+# _BOOST_FIND_LIBS([LIB-NAME], [CANDIDATE-LIB-NAMES],
+# [PREFERRED-RT-OPT], [HEADER-NAME], [CXX-TEST],
+# [CXX-PROLOGUE])
+# --------------------------------------------------------------
+# Real implementation of BOOST_FIND_LIBS: rely on these local macros:
+# Boost_lib, Boost_lib_LDFLAGS, Boost_lib_LDPATH, Boost_lib_LIBS
+#
+# The algorithm is as follows: first look for a given library name
+# according to the user's PREFERRED-RT-OPT. For each library name, we
+# prefer to use the ones that carry the tag (toolset name). Each
+# library is searched through the various standard paths were Boost is
+# usually installed. If we can't find the standard variants, we try
+# to enforce -mt (for instance on MacOSX, libboost_thread.dylib
+# doesn't exist but there's -obviously- libboost_thread-mt.dylib).
+AC_DEFUN([_BOOST_FIND_LIBS],
+[Boost_lib=no
+ case "$3" in #(
+ (mt | mt-) boost_mt=-mt; boost_rtopt=;; #(
+ (mt* | mt-*) boost_mt=-mt; boost_rtopt=`expr "X$3" : 'Xmt-*\(.*\)'`;; #(
+ (*) boost_mt=; boost_rtopt=$3;;
+ esac
+ if test $enable_static_boost = yes; then
+ boost_rtopt="s$boost_rtopt"
+ fi
+ # Find the proper debug variant depending on what we've been asked to find.
+ case $boost_rtopt in #(
+ (*d*) boost_rt_d=$boost_rtopt;; #(
+ (*[[sgpn]]*) # Insert the `d' at the right place (in between `sg' and `pn')
+ boost_rt_d=`echo "$boost_rtopt" | sed 's/\(s*g*\)\(p*n*\)/\1\2/'`;; #(
+ (*) boost_rt_d='-d';;
+ esac
+ # If the PREFERRED-RT-OPT are not empty, prepend a `-'.
+ test -n "$boost_rtopt" && boost_rtopt="-$boost_rtopt"
+ $boost_guess_use_mt && boost_mt=-mt
+ # Look for the abs path the static archive.
+ # $libext is computed by Libtool but let's make sure it's non empty.
+ test -z "$libext" &&
+ AC_MSG_ERROR([the libext variable is empty, did you invoke Libtool?])
+ boost_save_ac_objext=$ac_objext
+ # Generate the test file.
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <$4>
+$6], [$5])])
+dnl Optimization hacks: compiling C++ is slow, especially with Boost. What
+dnl we're trying to do here is guess the right combination of link flags
+dnl (LIBS / LDFLAGS) to use a given library. This can take several
+dnl iterations before it succeeds and is thus *very* slow. So what we do
+dnl instead is that we compile the code first (and thus get an object file,
+dnl typically conftest.o). Then we try various combinations of link flags
+dnl until we succeed to link conftest.o in an executable. The problem is
+dnl that the various TRY_LINK / COMPILE_IFELSE macros of Autoconf always
+dnl remove all the temporary files including conftest.o. So the trick here
+dnl is to temporarily change the value of ac_objext so that conftest.o is
+dnl preserved accross tests. This is obviously fragile and I will burn in
+dnl hell for not respecting Autoconf's documented interfaces, but in the
+dnl mean time, it optimizes the macro by a factor of 5 to 30.
+dnl Another small optimization: the first argument of AC_COMPILE_IFELSE left
+dnl empty because the test file is generated only once above (before we
+dnl start the for loops).
+ AC_COMPILE_IFELSE([],
+ [ac_objext=do_not_rm_me_plz],
+ [AC_MSG_ERROR([cannot compile a test that uses Boost $1])])
+ ac_objext=$boost_save_ac_objext
+ boost_failed_libs=
+# Don't bother to ident the following nested for loops, only the 2
+# innermost ones matter.
+for boost_lib_ in $2; do
+for boost_tag_ in -$boost_cv_lib_tag ''; do
+for boost_ver_ in -$boost_cv_lib_version ''; do
+for boost_mt_ in $boost_mt -mt ''; do
+for boost_rtopt_ in $boost_rtopt '' -d; do
+ for boost_lib in \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_rtopt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_mt_$boost_ver_ \
+ boost_$boost_lib_$boost_tag_$boost_ver_
+ do
+ # Avoid testing twice the same lib
+ case $boost_failed_libs in #(
+ (*@$boost_lib@*) continue;;
+ esac
+ # If with_boost is empty, we'll search in /lib first, which is not quite
+ # right so instead we'll try to a location based on where the headers are.
+ boost_tmp_lib=$with_boost
+ test x"$with_boost" = x && boost_tmp_lib=${boost_cv_inc_path%/include}
+ for boost_ldpath in "$boost_tmp_lib/lib" '' \
+ /opt/local/lib* /usr/local/lib* /opt/lib* /usr/lib* \
+ "$with_boost" C:/Boost/lib /lib*
+ do
+ # Don't waste time with directories that don't exist.
+ if test x"$boost_ldpath" != x && test ! -e "$boost_ldpath"; then
+ continue
+ fi
+ boost_save_LDFLAGS=$LDFLAGS
+ # Are we looking for a static library?
+ case $boost_ldpath:$boost_rtopt_ in #(
+ (*?*:*s*) # Yes (Non empty boost_ldpath + s in rt opt)
+ Boost_lib_LIBS="$boost_ldpath/lib$boost_lib.$libext"
+ test -e "$Boost_lib_LIBS" || continue;; #(
+ (*) # No: use -lboost_foo to find the shared library.
+ Boost_lib_LIBS="-l$boost_lib";;
+ esac
+ boost_save_LIBS=$LIBS
+ LIBS="$Boost_lib_LIBS $LIBS"
+ test x"$boost_ldpath" != x && LDFLAGS="$LDFLAGS -L$boost_ldpath"
+dnl First argument of AC_LINK_IFELSE left empty because the test file is
+dnl generated only once above (before we start the for loops).
+ _BOOST_AC_LINK_IFELSE([],
+ [Boost_lib=yes], [Boost_lib=no])
+ ac_objext=$boost_save_ac_objext
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ if test x"$Boost_lib" = xyes; then
+ # Check or used cached result of whether or not using -R or
+ # -rpath makes sense. Some implementations of ld, such as for
+ # Mac OSX, require -rpath but -R is the flag known to work on
+ # other systems. https://github.com/tsuna/boost.m4/issues/19
+ AC_CACHE_VAL([boost_cv_rpath_link_ldflag],
+ [case $boost_ldpath in
+ '') # Nothing to do.
+ boost_cv_rpath_link_ldflag=
+ boost_rpath_link_ldflag_found=yes;;
+ *)
+ for boost_cv_rpath_link_ldflag in -Wl,-R, -Wl,-rpath,; do
+ LDFLAGS="$boost_save_LDFLAGS -L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ LIBS="$boost_save_LIBS $Boost_lib_LIBS"
+ _BOOST_AC_LINK_IFELSE([],
+ [boost_rpath_link_ldflag_found=yes
+ break],
+ [boost_rpath_link_ldflag_found=no])
+ done
+ ;;
+ esac
+ AS_IF([test "x$boost_rpath_link_ldflag_found" != "xyes"],
+ [AC_MSG_ERROR([Unable to determine whether to use -R or -rpath])])
+ LDFLAGS=$boost_save_LDFLAGS
+ LIBS=$boost_save_LIBS
+ ])
+ test x"$boost_ldpath" != x &&
+ Boost_lib_LDFLAGS="-L$boost_ldpath $boost_cv_rpath_link_ldflag$boost_ldpath"
+ Boost_lib_LDPATH="$boost_ldpath"
+ break 7
+ else
+ boost_failed_libs="$boost_failed_libs@$boost_lib@"
+ fi
+ done
+ done
+done
+done
+done
+done
+done # boost_lib_
+rm -f conftest.$ac_objext
+])
+
+
+
+# --------------------------------------- #
+# Checks for the various Boost libraries. #
+# --------------------------------------- #
+
+# List of boost libraries: http://www.boost.org/libs/libraries.htm
+# The page http://beta.boost.org/doc/libs is useful: it gives the first release
+# version of each library (among other things).
+
+# BOOST_DEFUN(LIBRARY, CODE)
+# --------------------------
+# Define BOOST_<LIBRARY-UPPERCASE> as a macro that runs CODE.
+#
+# Use indir to avoid the warning on underquoted macro name given to AC_DEFUN.
+m4_define([BOOST_DEFUN],
+[m4_indir([AC_DEFUN],
+ m4_toupper([BOOST_$1]),
+[m4_pushdef([BOOST_Library], [$1])dnl
+$2
+m4_popdef([BOOST_Library])dnl
+])
+])
+
+# BOOST_ARRAY()
+# -------------
+# Look for Boost.Array
+BOOST_DEFUN([Array],
+[BOOST_FIND_HEADER([boost/array.hpp])])
+
+
+# BOOST_ASIO()
+# ------------
+# Look for Boost.Asio (new in Boost 1.35).
+BOOST_DEFUN([Asio],
+[AC_REQUIRE([BOOST_SYSTEM])dnl
+BOOST_FIND_HEADER([boost/asio.hpp])])
+
+
+# BOOST_ASSIGN()
+# -------------
+# Look for Boost.Assign
+BOOST_DEFUN([Assign],
+[BOOST_FIND_HEADER([boost/assign.hpp])])
+
+
+# BOOST_BIND()
+# ------------
+# Look for Boost.Bind.
+BOOST_DEFUN([Bind],
+[BOOST_FIND_HEADER([boost/bind.hpp])])
+
+
+# BOOST_CHRONO()
+# --------------
+# Look for Boost.Chrono.
+BOOST_DEFUN([Chrono],
+[# Do we have to check for Boost.System? This link-time dependency was
+# added as of 1.35.0. If we have a version <1.35, we must not attempt to
+# find Boost.System as it didn't exist by then.
+if test $boost_major_version -ge 135; then
+ BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+boost_filesystem_save_LIBS=$LIBS
+boost_filesystem_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([chrono], [$1],
+ [boost/chrono.hpp],
+ [boost::chrono::thread_clock d;])
+if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
+ BOOST_CHRONO_LIBS="$BOOST_CHRONO_LIBS $BOOST_SYSTEM_LIBS"
+fi
+LIBS=$boost_filesystem_save_LIBS
+LDFLAGS=$boost_filesystem_save_LDFLAGS
+])# BOOST_CHRONO
+
+
+# BOOST_CONTEXT([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Context. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+#
+# * This library was introduced in Boost 1.51.0
+# * The signatures of make_fcontext() and jump_fcontext were changed in 1.56.0
+# * A dependency on boost_thread appears in 1.57.0
+BOOST_DEFUN([Context],
+[boost_context_save_LIBS=$LIBS
+ boost_context_save_LDFLAGS=$LDFLAGS
+if test $boost_major_version -ge 157; then
+ BOOST_THREAD([$1])
+ m4_pattern_allow([^BOOST_THREAD_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_THREAD_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_THREAD_LDFLAGS"
+fi
+BOOST_FIND_LIB([context], [$1],
+ [boost/context/all.hpp],[[
+
+// creates a stack
+void * stack_pointer = new void*[4096];
+std::size_t const size = sizeof(void*[4096]);
+
+#if BOOST_VERSION <= 105100
+ctx::make_fcontext(&fc, f);
+return ctx::jump_fcontext(&fcm, &fc, 3) == 6;
+
+#else
+
+fc = ctx::make_fcontext(stack_pointer, size, f);
+return ctx::jump_fcontext(&fcm, fc, 3) == 6;
+
+#endif
+
+
+]],[dnl
+
+#include <boost/version.hpp>
+#if BOOST_VERSION <= 105100
+
+namespace ctx = boost::ctx;
+
+static ctx::fcontext_t fcm, fc;
+
+static void f(intptr_t i) {
+ ctx::jump_fcontext(&fc, &fcm, i * 2);
+}
+
+#elif BOOST_VERSION <= 105500
+
+namespace ctx = boost::context;
+
+// context
+static ctx::fcontext_t fcm, *fc;
+
+// context-function
+static void f(intptr_t i) {
+ ctx::jump_fcontext(fc, &fcm, i * 2);
+}
+
+#else
+
+namespace ctx = boost::context;
+
+// context
+static ctx::fcontext_t fcm, fc;
+
+// context-function
+static void f(intptr_t i) {
+ ctx::jump_fcontext(&fc, fcm, i * 2);
+}
+#endif
+])
+LIBS=$boost_context_save_LIBS
+LDFLAGS=$boost_context_save_LDFLAGS
+])# BOOST_CONTEXT
+
+
+# BOOST_CONVERSION()
+# ------------------
+# Look for Boost.Conversion (cast / lexical_cast)
+BOOST_DEFUN([Conversion],
+[BOOST_FIND_HEADER([boost/cast.hpp])
+BOOST_FIND_HEADER([boost/lexical_cast.hpp])
+])# BOOST_CONVERSION
+
+
+# BOOST_COROUTINE([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Coroutine. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
+# 1.53.0
+BOOST_DEFUN([Coroutine],
+[
+boost_coroutine_save_LIBS=$LIBS
+boost_coroutine_save_LDFLAGS=$LDFLAGS
+# Link-time dependency from coroutine to context
+BOOST_CONTEXT([$1])
+# Starting from Boost 1.55 a dependency on Boost.System is added
+if test $boost_major_version -ge 155; then
+ BOOST_SYSTEM([$1])
+fi
+m4_pattern_allow([^BOOST_(CONTEXT|SYSTEM)_(LIBS|LDFLAGS)])
+LIBS="$LIBS $BOOST_CONTEXT_LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_CONTEXT_LDFLAGS"
+
+# in 1.53 coroutine was a header only library
+if test $boost_major_version -eq 153; then
+ BOOST_FIND_HEADER([boost/coroutine/coroutine.hpp])
+else
+ BOOST_FIND_LIB([coroutine], [$1],
+ [boost/coroutine/coroutine.hpp],
+ [
+ #include <boost/version.hpp>
+ #if BOOST_VERSION <= 105500
+ boost::coroutines::coroutine<int(int)> coro; coro.get();
+ #else
+ boost::coroutines::asymmetric_coroutine<int>::pull_type coro; coro.get();
+ #endif
+ ])
+fi
+# Link-time dependency from coroutine to context, existed only in 1.53, in 1.54
+# coroutine doesn't use context from its headers but from its library.
+if test $boost_major_version -eq 153 || test $enable_static_boost = yes && test $boost_major_version -ge 154; then
+ BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_CONTEXT_LIBS"
+ BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_CONTEXT_LDFLAGS"
+fi
+if test $enable_static_boost = yes && test $boost_major_version -ge 155; then
+ BOOST_COROUTINE_LIBS="$BOOST_COROUTINE_LIBS $BOOST_SYSTEM_LIBS"
+ BOOST_COROUTINE_LDFLAGS="$BOOST_COROUTINE_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+fi
+LIBS=$boost_coroutine_save_LIBS
+LDFLAGS=$boost_coroutine_save_LDFLAGS
+])# BOOST_COROUTINE
+
+
+# BOOST_CRC()
+# -----------
+# Look for Boost.CRC
+BOOST_DEFUN([CRC],
+[BOOST_FIND_HEADER([boost/crc.hpp])
+])# BOOST_CRC
+
+
+# BOOST_DATE_TIME([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Date_Time. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Date_Time],
+[BOOST_FIND_LIB([date_time], [$1],
+ [boost/date_time/posix_time/posix_time.hpp],
+ [boost::posix_time::ptime t;])
+])# BOOST_DATE_TIME
+
+
+# BOOST_FILESYSTEM([PREFERRED-RT-OPT])
+# ------------------------------------
+# Look for Boost.Filesystem. For the documentation of PREFERRED-RT-OPT, see
+# the documentation of BOOST_FIND_LIB above.
+# Do not check for boost/filesystem.hpp because this file was introduced in
+# 1.34.
+BOOST_DEFUN([Filesystem],
+[# Do we have to check for Boost.System? This link-time dependency was
+# added as of 1.35.0. If we have a version <1.35, we must not attempt to
+# find Boost.System as it didn't exist by then.
+if test $boost_major_version -ge 135; then
+ BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+boost_filesystem_save_LIBS=$LIBS
+boost_filesystem_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([filesystem], [$1],
+ [boost/filesystem/path.hpp], [boost::filesystem::path p;])
+if test $enable_static_boost = yes && test $boost_major_version -ge 135; then
+ BOOST_FILESYSTEM_LIBS="$BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
+fi
+LIBS=$boost_filesystem_save_LIBS
+LDFLAGS=$boost_filesystem_save_LDFLAGS
+])# BOOST_FILESYSTEM
+
+
+# BOOST_FLYWEIGHT()
+# -----------------
+# Look for Boost.Flyweight.
+BOOST_DEFUN([Flyweight],
+[dnl There's a hidden dependency on pthreads.
+AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl
+BOOST_FIND_HEADER([boost/flyweight.hpp])
+AC_SUBST([BOOST_FLYWEIGHT_LIBS], [$boost_cv_pthread_flag])
+])
+
+
+# BOOST_FOREACH()
+# ---------------
+# Look for Boost.Foreach.
+BOOST_DEFUN([Foreach],
+[BOOST_FIND_HEADER([boost/foreach.hpp])])
+
+
+# BOOST_FORMAT()
+# --------------
+# Look for Boost.Format.
+# Note: we can't check for boost/format/format_fwd.hpp because the header isn't
+# standalone. It can't be compiled because it triggers the following error:
+# boost/format/detail/config_macros.hpp:88: error: 'locale' in namespace 'std'
+# does not name a type
+BOOST_DEFUN([Format],
+[BOOST_FIND_HEADER([boost/format.hpp])])
+
+
+# BOOST_FUNCTION()
+# ----------------
+# Look for Boost.Function
+BOOST_DEFUN([Function],
+[BOOST_FIND_HEADER([boost/function.hpp])])
+
+
+# BOOST_GEOMETRY()
+# ----------------
+# Look for Boost.Geometry (new since 1.47.0).
+BOOST_DEFUN([Geometry],
+[BOOST_FIND_HEADER([boost/geometry.hpp])
+])# BOOST_GEOMETRY
+
+
+# BOOST_GRAPH([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost.Graphs. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Graph],
+[boost_graph_save_LIBS=$LIBS
+boost_graph_save_LDFLAGS=$LDFLAGS
+# Link-time dependency from graph to regex was added as of 1.40.0.
+if test $boost_major_version -ge 140; then
+ BOOST_REGEX([$1])
+ m4_pattern_allow([^BOOST_REGEX_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_REGEX_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_REGEX_LDFLAGS"
+fi
+BOOST_FIND_LIB([graph], [$1],
+ [boost/graph/adjacency_list.hpp], [boost::adjacency_list<> g;])
+LIBS=$boost_graph_save_LIBS
+LDFLAGS=$boost_graph_save_LDFLAGS
+])# BOOST_GRAPH
+
+
+# BOOST_IOSTREAMS([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.IOStreams. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([IOStreams],
+[BOOST_FIND_LIB([iostreams], [$1],
+ [boost/iostreams/device/file_descriptor.hpp],
+ [boost::iostreams::file_descriptor fd; fd.close();])
+])# BOOST_IOSTREAMS
+
+
+# BOOST_HASH()
+# ------------
+# Look for Boost.Functional/Hash
+BOOST_DEFUN([Hash],
+[BOOST_FIND_HEADER([boost/functional/hash.hpp])])
+
+
+# BOOST_LAMBDA()
+# --------------
+# Look for Boost.Lambda
+BOOST_DEFUN([Lambda],
+[BOOST_FIND_HEADER([boost/lambda/lambda.hpp])])
+
+
+# BOOST_LOCALE()
+# --------------
+# Look for Boost.Locale
+BOOST_DEFUN([Locale],
+[
+boost_locale_save_LIBS=$LIBS
+boost_locale_save_LDFLAGS=$LDFLAGS
+# require SYSTEM for boost-1.50.0 and up
+if test $boost_major_version -ge 150; then
+ BOOST_SYSTEM([$1])
+ m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+ LIBS="$LIBS $BOOST_SYSTEM_LIBS"
+ LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+fi # end of the Boost.System check.
+BOOST_FIND_LIB([locale], [$1],
+ [boost/locale.hpp],
+ [[boost::locale::generator gen; std::locale::global(gen(""));]])
+LIBS=$boost_locale_save_LIBS
+LDFLAGS=$boost_locale_save_LDFLAGS
+])# BOOST_LOCALE
+
+# BOOST_LOG([PREFERRED-RT-OPT])
+# -----------------------------
+# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Log],
+[boost_log_save_LIBS=$LIBS
+boost_log_save_LDFLAGS=$LDFLAGS
+BOOST_SYSTEM([$1])
+BOOST_FILESYSTEM([$1])
+BOOST_DATE_TIME([$1])
+m4_pattern_allow([^BOOST_(SYSTEM|FILESYSTEM|DATE_TIME)_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_DATE_TIME_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_SYSTEM_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_DATE_TIME_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+BOOST_FIND_LIB([log], [$1],
+ [boost/log/core/core.hpp],
+ [boost::log::attribute a; a.get_value();])
+LIBS=$boost_log_save_LIBS
+LDFLAGS=$boost_log_save_LDFLAGS
+])# BOOST_LOG
+
+
+# BOOST_LOG_SETUP([PREFERRED-RT-OPT])
+# -----------------------------------
+# Look for Boost.Log. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Log_Setup],
+[boost_log_setup_save_LIBS=$LIBS
+boost_log_setup_save_LDFLAGS=$LDFLAGS
+BOOST_LOG([$1])
+m4_pattern_allow([^BOOST_LOG_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_LOG_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_LOG_LDFLAGS"
+BOOST_FIND_LIB([log_setup], [$1],
+ [boost/log/utility/setup/from_settings.hpp],
+ [boost::log::basic_settings<char> bs; bs.empty();])
+LIBS=$boost_log_setup_save_LIBS
+LDFLAGS=$boost_log_setup_save_LDFLAGS
+])# BOOST_LOG_SETUP
+
+
+# BOOST_MATH()
+# ------------
+# Look for Boost.Math
+# TODO: This library isn't header-only but it comes in multiple different
+# flavors that don't play well with BOOST_FIND_LIB (e.g, libboost_math_c99,
+# libboost_math_c99f, libboost_math_c99l, libboost_math_tr1,
+# libboost_math_tr1f, libboost_math_tr1l). This macro must be fixed to do the
+# right thing anyway.
+BOOST_DEFUN([Math],
+[BOOST_FIND_HEADER([boost/math/special_functions.hpp])])
+
+
+# BOOST_MPI([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost MPI. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. Uses MPICXX variable if it is
+# set, otherwise tries CXX
+#
+BOOST_DEFUN([MPI],
+[boost_save_CXX=${CXX}
+boost_save_CXXCPP=${CXXCPP}
+if test x"${MPICXX}" != x; then
+ CXX=${MPICXX}
+ CXXCPP="${MPICXX} -E"
+fi
+BOOST_FIND_LIB([mpi], [$1],
+ [boost/mpi.hpp],
+ [int argc = 0;
+ char **argv = 0;
+ boost::mpi::environment env(argc,argv);])
+CXX=${boost_save_CXX}
+CXXCPP=${boost_save_CXXCPP}
+])# BOOST_MPI
+
+
+# BOOST_MULTIARRAY()
+# ------------------
+# Look for Boost.MultiArray
+BOOST_DEFUN([MultiArray],
+[BOOST_FIND_HEADER([boost/multi_array.hpp])])
+
+
+# BOOST_NUMERIC_UBLAS()
+# --------------------------
+# Look for Boost.NumericUblas (Basic Linear Algebra)
+BOOST_DEFUN([Numeric_Ublas],
+[BOOST_FIND_HEADER([boost/numeric/ublas/vector.hpp])
+])# BOOST_NUMERIC_UBLAS
+
+
+# BOOST_NUMERIC_CONVERSION()
+# --------------------------
+# Look for Boost.NumericConversion (policy-based numeric conversion)
+BOOST_DEFUN([Numeric_Conversion],
+[BOOST_FIND_HEADER([boost/numeric/conversion/converter.hpp])
+])# BOOST_NUMERIC_CONVERSION
+
+
+# BOOST_OPTIONAL()
+# ----------------
+# Look for Boost.Optional
+BOOST_DEFUN([Optional],
+[BOOST_FIND_HEADER([boost/optional.hpp])])
+
+
+# BOOST_PREPROCESSOR()
+# --------------------
+# Look for Boost.Preprocessor
+BOOST_DEFUN([Preprocessor],
+[BOOST_FIND_HEADER([boost/preprocessor/repeat.hpp])])
+
+
+# BOOST_RANGE()
+# --------------------
+# Look for Boost.Range
+BOOST_DEFUN([Range],
+[BOOST_FIND_HEADER([boost/range/adaptors.hpp])])
+
+# BOOST_UNORDERED()
+# -----------------
+# Look for Boost.Unordered
+BOOST_DEFUN([Unordered],
+[BOOST_FIND_HEADER([boost/unordered_map.hpp])])
+
+
+# BOOST_UUID()
+# ------------
+# Look for Boost.Uuid
+BOOST_DEFUN([Uuid],
+[BOOST_FIND_HEADER([boost/uuid/uuid.hpp])])
+
+
+# BOOST_PROGRAM_OPTIONS([PREFERRED-RT-OPT])
+# -----------------------------------------
+# Look for Boost.Program_options. For the documentation of PREFERRED-RT-OPT,
+# see the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Program_Options],
+[BOOST_FIND_LIB([program_options], [$1],
+ [boost/program_options.hpp],
+ [boost::program_options::options_description d("test");])
+])# BOOST_PROGRAM_OPTIONS
+
+
+
+# _BOOST_PYTHON_CONFIG(VARIABLE, FLAG)
+# ------------------------------------
+# Save VARIABLE, and define it via `python-config --FLAG`.
+# Substitute BOOST_PYTHON_VARIABLE.
+m4_define([_BOOST_PYTHON_CONFIG],
+[AC_SUBST([BOOST_PYTHON_$1],
+ [`python-config --$2 2>/dev/null`])dnl
+boost_python_save_$1=$$1
+$1="$$1 $BOOST_PYTHON_$1"])
+
+
+# BOOST_PYTHON([PREFERRED-RT-OPT])
+# --------------------------------
+# Look for Boost.Python. For the documentation of PREFERRED-RT-OPT,
+# see the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Python],
+[_BOOST_PYTHON_CONFIG([CPPFLAGS], [includes])
+_BOOST_PYTHON_CONFIG([LDFLAGS], [ldflags])
+_BOOST_PYTHON_CONFIG([LIBS], [libs])
+m4_pattern_allow([^BOOST_PYTHON_MODULE$])dnl
+BOOST_FIND_LIBS([python], [python python3], [$1],
+ [boost/python.hpp],
+ [], [BOOST_PYTHON_MODULE(empty) {}])
+CPPFLAGS=$boost_python_save_CPPFLAGS
+LDFLAGS=$boost_python_save_LDFLAGS
+LIBS=$boost_python_save_LIBS
+])# BOOST_PYTHON
+
+
+# BOOST_REF()
+# -----------
+# Look for Boost.Ref
+BOOST_DEFUN([Ref],
+[BOOST_FIND_HEADER([boost/ref.hpp])])
+
+
+# BOOST_REGEX([PREFERRED-RT-OPT])
+# -------------------------------
+# Look for Boost.Regex. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Regex],
+[BOOST_FIND_LIB([regex], [$1],
+ [boost/regex.hpp],
+ [boost::regex exp("*"); boost::regex_match("foo", exp);])
+])# BOOST_REGEX
+
+
+# BOOST_SERIALIZATION([PREFERRED-RT-OPT])
+# ---------------------------------------
+# Look for Boost.Serialization. For the documentation of PREFERRED-RT-OPT, see
+# the documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Serialization],
+[BOOST_FIND_LIB([serialization], [$1],
+ [boost/archive/text_oarchive.hpp],
+ [std::ostream* o = 0; // Cheap way to get an ostream...
+ boost::archive::text_oarchive t(*o);])
+])# BOOST_SERIALIZATION
+
+
+# BOOST_SIGNALS([PREFERRED-RT-OPT])
+# ---------------------------------
+# Look for Boost.Signals. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Signals],
+[BOOST_FIND_LIB([signals], [$1],
+ [boost/signal.hpp],
+ [boost::signal<void ()> s;])
+])# BOOST_SIGNALS
+
+
+# BOOST_SIGNALS2()
+# ----------------
+# Look for Boost.Signals2 (new since 1.39.0).
+BOOST_DEFUN([Signals2],
+[BOOST_FIND_HEADER([boost/signals2.hpp])
+])# BOOST_SIGNALS2
+
+
+# BOOST_SMART_PTR()
+# -----------------
+# Look for Boost.SmartPtr
+BOOST_DEFUN([Smart_Ptr],
+[BOOST_FIND_HEADER([boost/scoped_ptr.hpp])
+BOOST_FIND_HEADER([boost/shared_ptr.hpp])
+])
+
+
+# BOOST_STATICASSERT()
+# --------------------
+# Look for Boost.StaticAssert
+BOOST_DEFUN([StaticAssert],
+[BOOST_FIND_HEADER([boost/static_assert.hpp])])
+
+
+# BOOST_STRING_ALGO()
+# -------------------
+# Look for Boost.StringAlgo
+BOOST_DEFUN([String_Algo],
+[BOOST_FIND_HEADER([boost/algorithm/string.hpp])
+])
+
+
+# BOOST_SYSTEM([PREFERRED-RT-OPT])
+# --------------------------------
+# Look for Boost.System. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above. This library was introduced in Boost
+# 1.35.0.
+BOOST_DEFUN([System],
+[BOOST_FIND_LIB([system], [$1],
+ [boost/system/error_code.hpp],
+ [boost::system::error_code e; e.clear();])
+])# BOOST_SYSTEM
+
+
+# BOOST_TEST([PREFERRED-RT-OPT])
+# ------------------------------
+# Look for Boost.Test. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Test],
+[m4_pattern_allow([^BOOST_CHECK$])dnl
+BOOST_FIND_LIB([unit_test_framework], [$1],
+ [boost/test/unit_test.hpp], [BOOST_CHECK(2 == 2);],
+ [using boost::unit_test::test_suite;
+ test_suite* init_unit_test_suite(int argc, char ** argv)
+ { return NULL; }])
+])# BOOST_TEST
+
+
+# BOOST_THREAD([PREFERRED-RT-OPT])
+# ---------------------------------
+# Look for Boost.Thread. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Thread],
+[dnl Having the pthread flag is required at least on GCC3 where
+dnl boost/thread.hpp would complain if we try to compile without
+dnl -pthread on GNU/Linux.
+AC_REQUIRE([_BOOST_PTHREAD_FLAG])dnl
+boost_thread_save_LIBS=$LIBS
+boost_thread_save_LDFLAGS=$LDFLAGS
+boost_thread_save_CPPFLAGS=$CPPFLAGS
+# Link-time dependency from thread to system was added as of 1.49.0.
+if test $boost_major_version -ge 149; then
+BOOST_SYSTEM([$1])
+fi # end of the Boost.System check.
+m4_pattern_allow([^BOOST_SYSTEM_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS"
+CPPFLAGS="$CPPFLAGS $boost_cv_pthread_flag"
+
+# When compiling for the Windows platform, the threads library is named
+# differently. This suffix doesn't exist in new versions of Boost, or
+# possibly new versions of GCC on mingw I am assuming it's Boost's change for
+# now and I am setting version to 1.48, for lack of knowledge as to when this
+# change occurred.
+if test $boost_major_version -lt 148; then
+ case $host_os in
+ (*mingw*) boost_thread_lib_ext=_win32;;
+ esac
+fi
+BOOST_FIND_LIBS([thread], [thread$boost_thread_lib_ext],
+ [$1],
+ [boost/thread.hpp], [boost::thread t; boost::mutex m;])
+
+case $host_os in
+ (*mingw*) boost_thread_w32_socket_link=-lws2_32;;
+esac
+
+BOOST_THREAD_LIBS="$BOOST_THREAD_LIBS $BOOST_SYSTEM_LIBS $boost_cv_pthread_flag $boost_thread_w32_socket_link"
+BOOST_THREAD_LDFLAGS="$BOOST_SYSTEM_LDFLAGS"
+BOOST_CPPFLAGS="$BOOST_CPPFLAGS $boost_cv_pthread_flag"
+LIBS=$boost_thread_save_LIBS
+LDFLAGS=$boost_thread_save_LDFLAGS
+CPPFLAGS=$boost_thread_save_CPPFLAGS
+])# BOOST_THREAD
+
+AU_ALIAS([BOOST_THREADS], [BOOST_THREAD])
+
+
+# BOOST_TOKENIZER()
+# -----------------
+# Look for Boost.Tokenizer
+BOOST_DEFUN([Tokenizer],
+[BOOST_FIND_HEADER([boost/tokenizer.hpp])])
+
+
+# BOOST_TRIBOOL()
+# ---------------
+# Look for Boost.Tribool
+BOOST_DEFUN([Tribool],
+[BOOST_FIND_HEADER([boost/logic/tribool_fwd.hpp])
+BOOST_FIND_HEADER([boost/logic/tribool.hpp])
+])
+
+
+# BOOST_TUPLE()
+# -------------
+# Look for Boost.Tuple
+BOOST_DEFUN([Tuple],
+[BOOST_FIND_HEADER([boost/tuple/tuple.hpp])])
+
+
+# BOOST_TYPETRAITS()
+# --------------------
+# Look for Boost.TypeTraits
+BOOST_DEFUN([TypeTraits],
+[BOOST_FIND_HEADER([boost/type_traits.hpp])])
+
+
+# BOOST_UTILITY()
+# ---------------
+# Look for Boost.Utility (noncopyable, result_of, base-from-member idiom,
+# etc.)
+BOOST_DEFUN([Utility],
+[BOOST_FIND_HEADER([boost/utility.hpp])])
+
+
+# BOOST_VARIANT()
+# ---------------
+# Look for Boost.Variant.
+BOOST_DEFUN([Variant],
+[BOOST_FIND_HEADER([boost/variant/variant_fwd.hpp])
+BOOST_FIND_HEADER([boost/variant.hpp])])
+
+
+# BOOST_POINTER_CONTAINER()
+# ------------------------
+# Look for Boost.PointerContainer
+BOOST_DEFUN([Pointer_Container],
+[BOOST_FIND_HEADER([boost/ptr_container/ptr_deque.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_list.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_vector.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_array.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_set.hpp])
+BOOST_FIND_HEADER([boost/ptr_container/ptr_map.hpp])
+])# BOOST_POINTER_CONTAINER
+
+
+# BOOST_WAVE([PREFERRED-RT-OPT])
+# ------------------------------
+# NOTE: If you intend to use Wave/Spirit with thread support, make sure you
+# call BOOST_THREAD first.
+# Look for Boost.Wave. For the documentation of PREFERRED-RT-OPT, see the
+# documentation of BOOST_FIND_LIB above.
+BOOST_DEFUN([Wave],
+[AC_REQUIRE([BOOST_FILESYSTEM])dnl
+AC_REQUIRE([BOOST_DATE_TIME])dnl
+boost_wave_save_LIBS=$LIBS
+boost_wave_save_LDFLAGS=$LDFLAGS
+m4_pattern_allow([^BOOST_((FILE)?SYSTEM|DATE_TIME|THREAD)_(LIBS|LDFLAGS)$])dnl
+LIBS="$LIBS $BOOST_SYSTEM_LIBS $BOOST_FILESYSTEM_LIBS $BOOST_DATE_TIME_LIBS \
+$BOOST_THREAD_LIBS"
+LDFLAGS="$LDFLAGS $BOOST_SYSTEM_LDFLAGS $BOOST_FILESYSTEM_LDFLAGS \
+$BOOST_DATE_TIME_LDFLAGS $BOOST_THREAD_LDFLAGS"
+BOOST_FIND_LIB([wave], [$1],
+ [boost/wave.hpp],
+ [boost::wave::token_id id; get_token_name(id);])
+LIBS=$boost_wave_save_LIBS
+LDFLAGS=$boost_wave_save_LDFLAGS
+])# BOOST_WAVE
+
+
+# BOOST_XPRESSIVE()
+# -----------------
+# Look for Boost.Xpressive (new since 1.36.0).
+BOOST_DEFUN([Xpressive],
+[BOOST_FIND_HEADER([boost/xpressive/xpressive.hpp])])
+
+
+# ----------------- #
+# Internal helpers. #
+# ----------------- #
+
+
+# _BOOST_PTHREAD_FLAG()
+# ---------------------
+# Internal helper for BOOST_THREAD. Computes boost_cv_pthread_flag
+# which must be used in CPPFLAGS and LIBS.
+#
+# Yes, we *need* to put the -pthread thing in CPPFLAGS because with GCC3,
+# boost/thread.hpp will trigger a #error if -pthread isn't used:
+# boost/config/requires_threads.hpp:47:5: #error "Compiler threading support
+# is not turned on. Please set the correct command line options for
+# threading: -pthread (Linux), -pthreads (Solaris) or -mthreads (Mingw32)"
+#
+# Based on ACX_PTHREAD: http://autoconf-archive.cryp.to/acx_pthread.html
+AC_DEFUN([_BOOST_PTHREAD_FLAG],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_LANG_PUSH([C++])dnl
+AC_CACHE_CHECK([for the flags needed to use pthreads], [boost_cv_pthread_flag],
+[ boost_cv_pthread_flag=
+ # The ordering *is* (sometimes) important. Some notes on the
+ # individual items follow:
+ # (none): in case threads are in libc; should be tried before -Kthread and
+ # other compiler flags to prevent continual compiler warnings
+ # -lpthreads: AIX (must check this before -lpthread)
+ # -Kthread: Sequent (threads in libc, but -Kthread needed for pthread.h)
+ # -kthread: FreeBSD kernel threads (preferred to -pthread since SMP-able)
+ # -llthread: LinuxThreads port on FreeBSD (also preferred to -pthread)
+ # -pthread: GNU Linux/GCC (kernel threads), BSD/GCC (userland threads)
+ # -pthreads: Solaris/GCC
+ # -mthreads: MinGW32/GCC, Lynx/GCC
+ # -mt: Sun Workshop C (may only link SunOS threads [-lthread], but it
+ # doesn't hurt to check since this sometimes defines pthreads too;
+ # also defines -D_REENTRANT)
+ # ... -mt is also the pthreads flag for HP/aCC
+ # -lpthread: GNU Linux, etc.
+ # --thread-safe: KAI C++
+ case $host_os in #(
+ *solaris*)
+ # On Solaris (at least, for some versions), libc contains stubbed
+ # (non-functional) versions of the pthreads routines, so link-based
+ # tests will erroneously succeed. (We need to link with -pthreads/-mt/
+ # -lpthread.) (The stubs are missing pthread_cleanup_push, or rather
+ # a function called by this macro, so we could check for that, but
+ # who knows whether they'll stub that too in a future libc.) So,
+ # we'll just look for -pthreads and -lpthread first:
+ boost_pthread_flags="-pthreads -lpthread -mt -pthread";; #(
+ *)
+ boost_pthread_flags="-lpthreads -Kthread -kthread -llthread -pthread \
+ -pthreads -mthreads -lpthread --thread-safe -mt";;
+ esac
+ # Generate the test file.
+ AC_LANG_CONFTEST([AC_LANG_PROGRAM([#include <pthread.h>],
+ [pthread_t th; pthread_join(th, 0);
+ pthread_attr_init(0); pthread_cleanup_push(0, 0);
+ pthread_create(0,0,0,0); pthread_cleanup_pop(0);])])
+ for boost_pthread_flag in '' $boost_pthread_flags; do
+ boost_pthread_ok=false
+dnl Re-use the test file already generated.
+ boost_pthreads__save_LIBS=$LIBS
+ LIBS="$LIBS $boost_pthread_flag"
+ AC_LINK_IFELSE([],
+ [if grep ".*$boost_pthread_flag" conftest.err; then
+ echo "This flag seems to have triggered warnings" >&AS_MESSAGE_LOG_FD
+ else
+ boost_pthread_ok=:; boost_cv_pthread_flag=$boost_pthread_flag
+ fi])
+ LIBS=$boost_pthreads__save_LIBS
+ $boost_pthread_ok && break
+ done
+])
+AC_LANG_POP([C++])dnl
+])# _BOOST_PTHREAD_FLAG
+
+
+# _BOOST_gcc_test(MAJOR, MINOR)
+# -----------------------------
+# Internal helper for _BOOST_FIND_COMPILER_TAG.
+m4_define([_BOOST_gcc_test],
+["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC @ gcc$1$2"])dnl
+
+# _BOOST_mingw_test(MAJOR, MINOR)
+# -----------------------------
+# Internal helper for _BOOST_FIND_COMPILER_TAG.
+m4_define([_BOOST_mingw_test],
+["defined __GNUC__ && __GNUC__ == $1 && __GNUC_MINOR__ == $2 && !defined __ICC && \
+ (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw$1$2"])dnl
+
+
+# _BOOST_FIND_COMPILER_TAG()
+# --------------------------
+# Internal. When Boost is installed without --layout=system, each library
+# filename will hold a suffix that encodes the compiler used during the
+# build. The Boost build system seems to call this a `tag'.
+AC_DEFUN([_BOOST_FIND_COMPILER_TAG],
+[AC_REQUIRE([AC_PROG_CXX])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_CACHE_CHECK([for the toolset name used by Boost for $CXX],
+ [boost_cv_lib_tag],
+[boost_cv_lib_tag=unknown
+if test x$boost_cv_inc_path != xno; then
+ AC_LANG_PUSH([C++])dnl
+ # The following tests are mostly inspired by boost/config/auto_link.hpp
+ # The list is sorted to most recent/common to oldest compiler (in order
+ # to increase the likelihood of finding the right compiler with the
+ # least number of compilation attempt).
+ # Beware that some tests are sensible to the order (for instance, we must
+ # look for MinGW before looking for GCC3).
+ # I used one compilation test per compiler with a #error to recognize
+ # each compiler so that it works even when cross-compiling (let me know
+ # if you know a better approach).
+ # Known missing tags (known from Boost's tools/build/v2/tools/common.jam):
+ # como, edg, kcc, bck, mp, sw, tru, xlc
+ # I'm not sure about my test for `il' (be careful: Intel's ICC pre-defines
+ # the same defines as GCC's).
+ for i in \
+ _BOOST_mingw_test(7, 1) \
+ _BOOST_gcc_test(7, 1) \
+ _BOOST_mingw_test(7, 0) \
+ _BOOST_gcc_test(7, 0) \
+ _BOOST_mingw_test(6, 3) \
+ _BOOST_gcc_test(6, 3) \
+ _BOOST_mingw_test(6, 2) \
+ _BOOST_gcc_test(6, 2) \
+ _BOOST_mingw_test(6, 1) \
+ _BOOST_gcc_test(6, 1) \
+ _BOOST_mingw_test(6, 0) \
+ _BOOST_gcc_test(6, 0) \
+ _BOOST_mingw_test(5, 4) \
+ _BOOST_gcc_test(5, 4) \
+ _BOOST_mingw_test(5, 3) \
+ _BOOST_gcc_test(5, 3) \
+ _BOOST_mingw_test(5, 2) \
+ _BOOST_gcc_test(5, 2) \
+ _BOOST_mingw_test(5, 1) \
+ _BOOST_gcc_test(5, 1) \
+ _BOOST_mingw_test(5, 0) \
+ _BOOST_gcc_test(5, 0) \
+ _BOOST_mingw_test(4, 10) \
+ _BOOST_gcc_test(4, 10) \
+ _BOOST_mingw_test(4, 9) \
+ _BOOST_gcc_test(4, 9) \
+ _BOOST_mingw_test(4, 8) \
+ _BOOST_gcc_test(4, 8) \
+ _BOOST_mingw_test(4, 7) \
+ _BOOST_gcc_test(4, 7) \
+ _BOOST_mingw_test(4, 6) \
+ _BOOST_gcc_test(4, 6) \
+ _BOOST_mingw_test(4, 5) \
+ _BOOST_gcc_test(4, 5) \
+ _BOOST_mingw_test(4, 4) \
+ _BOOST_gcc_test(4, 4) \
+ _BOOST_mingw_test(4, 3) \
+ _BOOST_gcc_test(4, 3) \
+ _BOOST_mingw_test(4, 2) \
+ _BOOST_gcc_test(4, 2) \
+ _BOOST_mingw_test(4, 1) \
+ _BOOST_gcc_test(4, 1) \
+ _BOOST_mingw_test(4, 0) \
+ _BOOST_gcc_test(4, 0) \
+ "defined __GNUC__ && __GNUC__ == 3 && !defined __ICC \
+ && (defined WIN32 || defined WINNT || defined _WIN32 || defined __WIN32 \
+ || defined __WIN32__ || defined __WINNT || defined __WINNT__) @ mgw" \
+ _BOOST_gcc_test(3, 4) \
+ _BOOST_gcc_test(3, 3) \
+ "defined _MSC_VER && _MSC_VER >= 1500 @ vc90" \
+ "defined _MSC_VER && _MSC_VER == 1400 @ vc80" \
+ _BOOST_gcc_test(3, 2) \
+ "defined _MSC_VER && _MSC_VER == 1310 @ vc71" \
+ _BOOST_gcc_test(3, 1) \
+ _BOOST_gcc_test(3, 0) \
+ "defined __BORLANDC__ @ bcb" \
+ "defined __ICC && (defined __unix || defined __unix__) @ il" \
+ "defined __ICL @ iw" \
+ "defined _MSC_VER && _MSC_VER == 1300 @ vc7" \
+ _BOOST_gcc_test(2, 95) \
+ "defined __MWERKS__ && __MWERKS__ <= 0x32FF @ cw9" \
+ "defined _MSC_VER && _MSC_VER < 1300 && !defined UNDER_CE @ vc6" \
+ "defined _MSC_VER && _MSC_VER < 1300 && defined UNDER_CE @ evc4" \
+ "defined __MWERKS__ && __MWERKS__ <= 0x31FF @ cw8"
+ do
+ boost_tag_test=`expr "X$i" : 'X\([[^@]]*\) @ '`
+ boost_tag=`expr "X$i" : 'X[[^@]]* @ \(.*\)'`
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if $boost_tag_test
+/* OK */
+#else
+# error $boost_tag_test
+#endif
+]])], [boost_cv_lib_tag=$boost_tag; break], [])
+ done
+AC_LANG_POP([C++])dnl
+ case $boost_cv_lib_tag in #(
+ # Some newer (>= 1.35?) versions of Boost seem to only use "gcc" as opposed
+ # to "gcc41" for instance.
+ *-gcc | *'-gcc ') :;; #( Don't re-add -gcc: it's already in there.
+ gcc*)
+ boost_tag_x=
+ case $host_os in #(
+ darwin*)
+ if test $boost_major_version -ge 136; then
+ # The `x' added in r46793 of Boost.
+ boost_tag_x=x
+ fi;;
+ esac
+ # We can specify multiple tags in this variable because it's used by
+ # BOOST_FIND_LIB that does a `for tag in -$boost_cv_lib_tag' ...
+ boost_cv_lib_tag="$boost_tag_x$boost_cv_lib_tag -${boost_tag_x}gcc"
+ ;; #(
+ unknown)
+ AC_MSG_WARN([[could not figure out which toolset name to use for $CXX]])
+ boost_cv_lib_tag=
+ ;;
+ esac
+fi])dnl end of AC_CACHE_CHECK
+])# _BOOST_FIND_COMPILER_TAG
+
+
+# _BOOST_GUESS_WHETHER_TO_USE_MT()
+# --------------------------------
+# Compile a small test to try to guess whether we should favor MT (Multi
+# Thread) flavors of Boost. Sets boost_guess_use_mt accordingly.
+AC_DEFUN([_BOOST_GUESS_WHETHER_TO_USE_MT],
+[# Check whether we do better use `mt' even though we weren't ask to.
+AC_LANG_PUSH([C++])dnl
+AC_COMPILE_IFELSE([AC_LANG_PROGRAM([[
+#if defined _REENTRANT || defined _MT || defined __MT__
+/* use -mt */
+#else
+# error MT not needed
+#endif
+]])], [boost_guess_use_mt=:], [boost_guess_use_mt=false])
+AC_LANG_POP([C++])dnl
+])
+
+# _BOOST_AC_LINK_IFELSE(PROGRAM, [ACTION-IF-TRUE], [ACTION-IF-FALSE])
+# -------------------------------------------------------------------
+# Fork of _AC_LINK_IFELSE that preserves conftest.o across calls. Fragile,
+# will break when Autoconf changes its internals. Requires that you manually
+# rm -f conftest.$ac_objext in between to really different tests, otherwise
+# you will try to link a conftest.o left behind by a previous test.
+# Used to aggressively optimize BOOST_FIND_LIB (see the big comment in this
+# macro).
+#
+# Don't use "break" in the actions, as it would short-circuit some code
+# this macro runs after the actions.
+m4_define([_BOOST_AC_LINK_IFELSE],
+[m4_ifvaln([$1], [AC_LANG_CONFTEST([$1])])dnl
+rm -f conftest$ac_exeext
+boost_save_ac_ext=$ac_ext
+boost_use_source=:
+# If we already have a .o, re-use it. We change $ac_ext so that $ac_link
+# tries to link the existing object file instead of compiling from source.
+test -f conftest.$ac_objext && ac_ext=$ac_objext && boost_use_source=false &&
+ _AS_ECHO_LOG([re-using the existing conftest.$ac_objext])
+AS_IF([_AC_DO_STDERR($ac_link) && {
+ test -z "$ac_[]_AC_LANG_ABBREV[]_werror_flag" ||
+ test ! -s conftest.err
+ } && test -s conftest$ac_exeext && {
+ test "$cross_compiling" = yes ||
+ $as_executable_p conftest$ac_exeext
+dnl FIXME: use AS_TEST_X instead when 2.61 is widespread enough.
+ }],
+ [$2],
+ [if $boost_use_source; then
+ _AC_MSG_LOG_CONFTEST
+ fi
+ $3])
+ac_objext=$boost_save_ac_objext
+ac_ext=$boost_save_ac_ext
+dnl Delete also the IPA/IPO (Inter Procedural Analysis/Optimization)
+dnl information created by the PGI compiler (conftest_ipa8_conftest.oo),
+dnl as it would interfere with the next link command.
+rm -f core conftest.err conftest_ipa8_conftest.oo \
+ conftest$ac_exeext m4_ifval([$1], [conftest.$ac_ext])[]dnl
+])# _BOOST_AC_LINK_IFELSE
+
+# Local Variables:
+# mode: autoconf
+# End:
--- /dev/null
+# libtool.m4 - Configure libtool for the host system. -*-Autoconf-*-
+#
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+m4_define([_LT_COPYING], [dnl
+# Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2004, 2005,
+# 2006, 2007, 2008, 2009, 2010, 2011 Free Software
+# Foundation, Inc.
+# Written by Gordon Matzigkeit, 1996
+#
+# This file is part of GNU Libtool.
+#
+# GNU Libtool is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of
+# the License, or (at your option) any later version.
+#
+# As a special exception to the GNU General Public License,
+# if you distribute this file as part of a program or library that
+# is built using GNU Libtool, you may include this file under the
+# same distribution terms that you use for the rest of that program.
+#
+# GNU Libtool is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GNU Libtool; see the file COPYING. If not, a copy
+# can be downloaded from http://www.gnu.org/licenses/gpl.html, or
+# obtained by writing to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+])
+
+# serial 57 LT_INIT
+
+
+# LT_PREREQ(VERSION)
+# ------------------
+# Complain and exit if this libtool version is less that VERSION.
+m4_defun([LT_PREREQ],
+[m4_if(m4_version_compare(m4_defn([LT_PACKAGE_VERSION]), [$1]), -1,
+ [m4_default([$3],
+ [m4_fatal([Libtool version $1 or higher is required],
+ 63)])],
+ [$2])])
+
+
+# _LT_CHECK_BUILDDIR
+# ------------------
+# Complain if the absolute build directory name contains unusual characters
+m4_defun([_LT_CHECK_BUILDDIR],
+[case `pwd` in
+ *\ * | *\ *)
+ AC_MSG_WARN([Libtool does not cope well with whitespace in `pwd`]) ;;
+esac
+])
+
+
+# LT_INIT([OPTIONS])
+# ------------------
+AC_DEFUN([LT_INIT],
+[AC_PREREQ([2.58])dnl We use AC_INCLUDES_DEFAULT
+AC_REQUIRE([AC_CONFIG_AUX_DIR_DEFAULT])dnl
+AC_BEFORE([$0], [LT_LANG])dnl
+AC_BEFORE([$0], [LT_OUTPUT])dnl
+AC_BEFORE([$0], [LTDL_INIT])dnl
+m4_require([_LT_CHECK_BUILDDIR])dnl
+
+dnl Autoconf doesn't catch unexpanded LT_ macros by default:
+m4_pattern_forbid([^_?LT_[A-Z_]+$])dnl
+m4_pattern_allow([^(_LT_EOF|LT_DLGLOBAL|LT_DLLAZY_OR_NOW|LT_MULTI_MODULE)$])dnl
+dnl aclocal doesn't pull ltoptions.m4, ltsugar.m4, or ltversion.m4
+dnl unless we require an AC_DEFUNed macro:
+AC_REQUIRE([LTOPTIONS_VERSION])dnl
+AC_REQUIRE([LTSUGAR_VERSION])dnl
+AC_REQUIRE([LTVERSION_VERSION])dnl
+AC_REQUIRE([LTOBSOLETE_VERSION])dnl
+m4_require([_LT_PROG_LTMAIN])dnl
+
+_LT_SHELL_INIT([SHELL=${CONFIG_SHELL-/bin/sh}])
+
+dnl Parse OPTIONS
+_LT_SET_OPTIONS([$0], [$1])
+
+# This can be used to rebuild libtool when needed
+LIBTOOL_DEPS="$ltmain"
+
+# Always use our own libtool.
+LIBTOOL='$(SHELL) $(top_builddir)/libtool'
+AC_SUBST(LIBTOOL)dnl
+
+_LT_SETUP
+
+# Only expand once:
+m4_define([LT_INIT])
+])# LT_INIT
+
+# Old names:
+AU_ALIAS([AC_PROG_LIBTOOL], [LT_INIT])
+AU_ALIAS([AM_PROG_LIBTOOL], [LT_INIT])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PROG_LIBTOOL], [])
+dnl AC_DEFUN([AM_PROG_LIBTOOL], [])
+
+
+# _LT_CC_BASENAME(CC)
+# -------------------
+# Calculate cc_basename. Skip known compiler wrappers and cross-prefix.
+m4_defun([_LT_CC_BASENAME],
+[for cc_temp in $1""; do
+ case $cc_temp in
+ compile | *[[\\/]]compile | ccache | *[[\\/]]ccache ) ;;
+ distcc | *[[\\/]]distcc | purify | *[[\\/]]purify ) ;;
+ \-*) ;;
+ *) break;;
+ esac
+done
+cc_basename=`$ECHO "$cc_temp" | $SED "s%.*/%%; s%^$host_alias-%%"`
+])
+
+
+# _LT_FILEUTILS_DEFAULTS
+# ----------------------
+# It is okay to use these file commands and assume they have been set
+# sensibly after `m4_require([_LT_FILEUTILS_DEFAULTS])'.
+m4_defun([_LT_FILEUTILS_DEFAULTS],
+[: ${CP="cp -f"}
+: ${MV="mv -f"}
+: ${RM="rm -f"}
+])# _LT_FILEUTILS_DEFAULTS
+
+
+# _LT_SETUP
+# ---------
+m4_defun([_LT_SETUP],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_REQUIRE([_LT_PREPARE_SED_QUOTE_VARS])dnl
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])dnl
+
+_LT_DECL([], [PATH_SEPARATOR], [1], [The PATH separator for the build system])dnl
+dnl
+_LT_DECL([], [host_alias], [0], [The host system])dnl
+_LT_DECL([], [host], [0])dnl
+_LT_DECL([], [host_os], [0])dnl
+dnl
+_LT_DECL([], [build_alias], [0], [The build system])dnl
+_LT_DECL([], [build], [0])dnl
+_LT_DECL([], [build_os], [0])dnl
+dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+dnl
+AC_REQUIRE([AC_PROG_LN_S])dnl
+test -z "$LN_S" && LN_S="ln -s"
+_LT_DECL([], [LN_S], [1], [Whether we need soft or hard links])dnl
+dnl
+AC_REQUIRE([LT_CMD_MAX_LEN])dnl
+_LT_DECL([objext], [ac_objext], [0], [Object file suffix (normally "o")])dnl
+_LT_DECL([], [exeext], [0], [Executable file suffix (normally "")])dnl
+dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+m4_require([_LT_PATH_CONVERSION_FUNCTIONS])dnl
+m4_require([_LT_CMD_RELOAD])dnl
+m4_require([_LT_CHECK_MAGIC_METHOD])dnl
+m4_require([_LT_CHECK_SHAREDLIB_FROM_LINKLIB])dnl
+m4_require([_LT_CMD_OLD_ARCHIVE])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_WITH_SYSROOT])dnl
+
+_LT_CONFIG_LIBTOOL_INIT([
+# See if we are running on zsh, and set the options which allow our
+# commands through without removal of \ escapes INIT.
+if test -n "\${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+])
+if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+fi
+
+_LT_CHECK_OBJDIR
+
+m4_require([_LT_TAG_COMPILER])dnl
+
+case $host_os in
+aix3*)
+ # AIX sometimes has problems with the GCC collect2 program. For some
+ # reason, if we set the COLLECT_NAMES environment variable, the problems
+ # vanish in a puff of smoke.
+ if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+ fi
+ ;;
+esac
+
+# Global variables:
+ofile=libtool
+can_build_shared=yes
+
+# All known linkers require a `.a' archive for static linking (except MSVC,
+# which needs '.lib').
+libext=a
+
+with_gnu_ld="$lt_cv_prog_gnu_ld"
+
+old_CC="$CC"
+old_CFLAGS="$CFLAGS"
+
+# Set sane defaults for various variables
+test -z "$CC" && CC=cc
+test -z "$LTCC" && LTCC=$CC
+test -z "$LTCFLAGS" && LTCFLAGS=$CFLAGS
+test -z "$LD" && LD=ld
+test -z "$ac_objext" && ac_objext=o
+
+_LT_CC_BASENAME([$compiler])
+
+# Only perform the check for file, if the check method requires it
+test -z "$MAGIC_CMD" && MAGIC_CMD=file
+case $deplibs_check_method in
+file_magic*)
+ if test "$file_magic_cmd" = '$MAGIC_CMD'; then
+ _LT_PATH_MAGIC
+ fi
+ ;;
+esac
+
+# Use C for the default configuration in the libtool script
+LT_SUPPORTED_TAG([CC])
+_LT_LANG_C_CONFIG
+_LT_LANG_DEFAULT_CONFIG
+_LT_CONFIG_COMMANDS
+])# _LT_SETUP
+
+
+# _LT_PREPARE_SED_QUOTE_VARS
+# --------------------------
+# Define a few sed substitution that help us do robust quoting.
+m4_defun([_LT_PREPARE_SED_QUOTE_VARS],
+[# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\([["`$\\]]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\([["`\\]]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+])
+
+# _LT_PROG_LTMAIN
+# ---------------
+# Note that this code is called both from `configure', and `config.status'
+# now that we use AC_CONFIG_COMMANDS to generate libtool. Notably,
+# `config.status' has no value for ac_aux_dir unless we are using Automake,
+# so we pass a copy along to make sure it has a sensible value anyway.
+m4_defun([_LT_PROG_LTMAIN],
+[m4_ifdef([AC_REQUIRE_AUX_FILE], [AC_REQUIRE_AUX_FILE([ltmain.sh])])dnl
+_LT_CONFIG_LIBTOOL_INIT([ac_aux_dir='$ac_aux_dir'])
+ltmain="$ac_aux_dir/ltmain.sh"
+])# _LT_PROG_LTMAIN
+
+
+## ------------------------------------- ##
+## Accumulate code for creating libtool. ##
+## ------------------------------------- ##
+
+# So that we can recreate a full libtool script including additional
+# tags, we accumulate the chunks of code to send to AC_CONFIG_COMMANDS
+# in macros and then make a single call at the end using the `libtool'
+# label.
+
+
+# _LT_CONFIG_LIBTOOL_INIT([INIT-COMMANDS])
+# ----------------------------------------
+# Register INIT-COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL_INIT],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_INIT],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_INIT])
+
+
+# _LT_CONFIG_LIBTOOL([COMMANDS])
+# ------------------------------
+# Register COMMANDS to be passed to AC_CONFIG_COMMANDS later.
+m4_define([_LT_CONFIG_LIBTOOL],
+[m4_ifval([$1],
+ [m4_append([_LT_OUTPUT_LIBTOOL_COMMANDS],
+ [$1
+])])])
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS])
+
+
+# _LT_CONFIG_SAVE_COMMANDS([COMMANDS], [INIT_COMMANDS])
+# -----------------------------------------------------
+m4_defun([_LT_CONFIG_SAVE_COMMANDS],
+[_LT_CONFIG_LIBTOOL([$1])
+_LT_CONFIG_LIBTOOL_INIT([$2])
+])
+
+
+# _LT_FORMAT_COMMENT([COMMENT])
+# -----------------------------
+# Add leading comment marks to the start of each line, and a trailing
+# full-stop to the whole comment if one is not present already.
+m4_define([_LT_FORMAT_COMMENT],
+[m4_ifval([$1], [
+m4_bpatsubst([m4_bpatsubst([$1], [^ *], [# ])],
+ [['`$\]], [\\\&])]m4_bmatch([$1], [[!?.]$], [], [.])
+)])
+
+
+
+## ------------------------ ##
+## FIXME: Eliminate VARNAME ##
+## ------------------------ ##
+
+
+# _LT_DECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION], [IS-TAGGED?])
+# -------------------------------------------------------------------
+# CONFIGNAME is the name given to the value in the libtool script.
+# VARNAME is the (base) name used in the configure script.
+# VALUE may be 0, 1 or 2 for a computed quote escaped value based on
+# VARNAME. Any other value will be used directly.
+m4_define([_LT_DECL],
+[lt_if_append_uniq([lt_decl_varnames], [$2], [, ],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [libtool_name],
+ [m4_ifval([$1], [$1], [$2])])
+ lt_dict_add_subkey([lt_decl_dict], [$2], [value], [$3])
+ m4_ifval([$4],
+ [lt_dict_add_subkey([lt_decl_dict], [$2], [description], [$4])])
+ lt_dict_add_subkey([lt_decl_dict], [$2],
+ [tagged?], [m4_ifval([$5], [yes], [no])])])
+])
+
+
+# _LT_TAGDECL([CONFIGNAME], VARNAME, VALUE, [DESCRIPTION])
+# --------------------------------------------------------
+m4_define([_LT_TAGDECL], [_LT_DECL([$1], [$2], [$3], [$4], [yes])])
+
+
+# lt_decl_tag_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_tag_varnames],
+[_lt_decl_filter([tagged?], [yes], $@)])
+
+
+# _lt_decl_filter(SUBKEY, VALUE, [SEPARATOR], [VARNAME1..])
+# ---------------------------------------------------------
+m4_define([_lt_decl_filter],
+[m4_case([$#],
+ [0], [m4_fatal([$0: too few arguments: $#])],
+ [1], [m4_fatal([$0: too few arguments: $#: $1])],
+ [2], [lt_dict_filter([lt_decl_dict], [$1], [$2], [], lt_decl_varnames)],
+ [3], [lt_dict_filter([lt_decl_dict], [$1], [$2], [$3], lt_decl_varnames)],
+ [lt_dict_filter([lt_decl_dict], $@)])[]dnl
+])
+
+
+# lt_decl_quote_varnames([SEPARATOR], [VARNAME1...])
+# --------------------------------------------------
+m4_define([lt_decl_quote_varnames],
+[_lt_decl_filter([value], [1], $@)])
+
+
+# lt_decl_dquote_varnames([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_dquote_varnames],
+[_lt_decl_filter([value], [2], $@)])
+
+
+# lt_decl_varnames_tagged([SEPARATOR], [VARNAME1...])
+# ---------------------------------------------------
+m4_define([lt_decl_varnames_tagged],
+[m4_assert([$# <= 2])dnl
+_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_ifval([$2], [[$2]], [m4_dquote(lt_decl_tag_varnames)]),
+ m4_split(m4_normalize(m4_quote(_LT_TAGS)), [ ]))])
+m4_define([_lt_decl_varnames_tagged],
+[m4_ifval([$3], [lt_combine([$1], [$2], [_], $3)])])
+
+
+# lt_decl_all_varnames([SEPARATOR], [VARNAME1...])
+# ------------------------------------------------
+m4_define([lt_decl_all_varnames],
+[_$0(m4_quote(m4_default([$1], [[, ]])),
+ m4_if([$2], [],
+ m4_quote(lt_decl_varnames),
+ m4_quote(m4_shift($@))))[]dnl
+])
+m4_define([_lt_decl_all_varnames],
+[lt_join($@, lt_decl_varnames_tagged([$1],
+ lt_decl_tag_varnames([[, ]], m4_shift($@))))dnl
+])
+
+
+# _LT_CONFIG_STATUS_DECLARE([VARNAME])
+# ------------------------------------
+# Quote a variable value, and forward it to `config.status' so that its
+# declaration there will have the same value as in `configure'. VARNAME
+# must have a single quote delimited value for this to work.
+m4_define([_LT_CONFIG_STATUS_DECLARE],
+[$1='`$ECHO "$][$1" | $SED "$delay_single_quote_subst"`'])
+
+
+# _LT_CONFIG_STATUS_DECLARATIONS
+# ------------------------------
+# We delimit libtool config variables with single quotes, so when
+# we write them to config.status, we have to be sure to quote all
+# embedded single quotes properly. In configure, this macro expands
+# each variable declared with _LT_DECL (and _LT_TAGDECL) into:
+#
+# <var>='`$ECHO "$<var>" | $SED "$delay_single_quote_subst"`'
+m4_defun([_LT_CONFIG_STATUS_DECLARATIONS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_all_varnames),
+ [m4_n([_LT_CONFIG_STATUS_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAGS
+# ----------------
+# Output comment and list of tags supported by the script
+m4_defun([_LT_LIBTOOL_TAGS],
+[_LT_FORMAT_COMMENT([The names of the tagged configurations supported by this script])dnl
+available_tags="_LT_TAGS"dnl
+])
+
+
+# _LT_LIBTOOL_DECLARE(VARNAME, [TAG])
+# -----------------------------------
+# Extract the dictionary values for VARNAME (optionally with TAG) and
+# expand to a commented shell variable setting:
+#
+# # Some comment about what VAR is for.
+# visible_name=$lt_internal_name
+m4_define([_LT_LIBTOOL_DECLARE],
+[_LT_FORMAT_COMMENT(m4_quote(lt_dict_fetch([lt_decl_dict], [$1],
+ [description])))[]dnl
+m4_pushdef([_libtool_name],
+ m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [libtool_name])))[]dnl
+m4_case(m4_quote(lt_dict_fetch([lt_decl_dict], [$1], [value])),
+ [0], [_libtool_name=[$]$1],
+ [1], [_libtool_name=$lt_[]$1],
+ [2], [_libtool_name=$lt_[]$1],
+ [_libtool_name=lt_dict_fetch([lt_decl_dict], [$1], [value])])[]dnl
+m4_ifval([$2], [_$2])[]m4_popdef([_libtool_name])[]dnl
+])
+
+
+# _LT_LIBTOOL_CONFIG_VARS
+# -----------------------
+# Produce commented declarations of non-tagged libtool config variables
+# suitable for insertion in the LIBTOOL CONFIG section of the `libtool'
+# script. Tagged libtool config variables (even for the LIBTOOL CONFIG
+# section) are produced by _LT_LIBTOOL_TAG_VARS.
+m4_defun([_LT_LIBTOOL_CONFIG_VARS],
+[m4_foreach([_lt_var],
+ m4_quote(_lt_decl_filter([tagged?], [no], [], lt_decl_varnames)),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var)])])])
+
+
+# _LT_LIBTOOL_TAG_VARS(TAG)
+# -------------------------
+m4_define([_LT_LIBTOOL_TAG_VARS],
+[m4_foreach([_lt_var], m4_quote(lt_decl_tag_varnames),
+ [m4_n([_LT_LIBTOOL_DECLARE(_lt_var, [$1])])])])
+
+
+# _LT_TAGVAR(VARNAME, [TAGNAME])
+# ------------------------------
+m4_define([_LT_TAGVAR], [m4_ifval([$2], [$1_$2], [$1])])
+
+
+# _LT_CONFIG_COMMANDS
+# -------------------
+# Send accumulated output to $CONFIG_STATUS. Thanks to the lists of
+# variables for single and double quote escaping we saved from calls
+# to _LT_DECL, we can put quote escaped variables declarations
+# into `config.status', and then the shell code to quote escape them in
+# for loops in `config.status'. Finally, any additional code accumulated
+# from calls to _LT_CONFIG_LIBTOOL_INIT is expanded.
+m4_defun([_LT_CONFIG_COMMANDS],
+[AC_PROVIDE_IFELSE([LT_OUTPUT],
+ dnl If the libtool generation code has been placed in $CONFIG_LT,
+ dnl instead of duplicating it all over again into config.status,
+ dnl then we will have config.status run $CONFIG_LT later, so it
+ dnl needs to know what name is stored there:
+ [AC_CONFIG_COMMANDS([libtool],
+ [$SHELL $CONFIG_LT || AS_EXIT(1)], [CONFIG_LT='$CONFIG_LT'])],
+ dnl If the libtool generation code is destined for config.status,
+ dnl expand the accumulated commands and init code now:
+ [AC_CONFIG_COMMANDS([libtool],
+ [_LT_OUTPUT_LIBTOOL_COMMANDS], [_LT_OUTPUT_LIBTOOL_COMMANDS_INIT])])
+])#_LT_CONFIG_COMMANDS
+
+
+# Initialize.
+m4_define([_LT_OUTPUT_LIBTOOL_COMMANDS_INIT],
+[
+
+# The HP-UX ksh and POSIX shell print the target directory to stdout
+# if CDPATH is set.
+(unset CDPATH) >/dev/null 2>&1 && unset CDPATH
+
+sed_quote_subst='$sed_quote_subst'
+double_quote_subst='$double_quote_subst'
+delay_variable_subst='$delay_variable_subst'
+_LT_CONFIG_STATUS_DECLARATIONS
+LTCC='$LTCC'
+LTCFLAGS='$LTCFLAGS'
+compiler='$compiler_DEFAULT'
+
+# A function that is used when there is no print builtin or printf.
+func_fallback_echo ()
+{
+ eval 'cat <<_LTECHO_EOF
+\$[]1
+_LTECHO_EOF'
+}
+
+# Quote evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_quote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED \\"\\\$sed_quote_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+# Double-quote double-evaled strings.
+for var in lt_decl_all_varnames([[ \
+]], lt_decl_dquote_varnames); do
+ case \`eval \\\\\$ECHO \\\\""\\\\\$\$var"\\\\"\` in
+ *[[\\\\\\\`\\"\\\$]]*)
+ eval "lt_\$var=\\\\\\"\\\`\\\$ECHO \\"\\\$\$var\\" | \\\$SED -e \\"\\\$double_quote_subst\\" -e \\"\\\$sed_quote_subst\\" -e \\"\\\$delay_variable_subst\\"\\\`\\\\\\""
+ ;;
+ *)
+ eval "lt_\$var=\\\\\\"\\\$\$var\\\\\\""
+ ;;
+ esac
+done
+
+_LT_OUTPUT_LIBTOOL_INIT
+])
+
+# _LT_GENERATED_FILE_INIT(FILE, [COMMENT])
+# ------------------------------------
+# Generate a child script FILE with all initialization necessary to
+# reuse the environment learned by the parent script, and make the
+# file executable. If COMMENT is supplied, it is inserted after the
+# `#!' sequence but before initialization text begins. After this
+# macro, additional text can be appended to FILE to form the body of
+# the child script. The macro ends with non-zero status if the
+# file could not be fully written (such as if the disk is full).
+m4_ifdef([AS_INIT_GENERATED],
+[m4_defun([_LT_GENERATED_FILE_INIT],[AS_INIT_GENERATED($@)])],
+[m4_defun([_LT_GENERATED_FILE_INIT],
+[m4_require([AS_PREPARE])]dnl
+[m4_pushdef([AS_MESSAGE_LOG_FD])]dnl
+[lt_write_fail=0
+cat >$1 <<_ASEOF || lt_write_fail=1
+#! $SHELL
+# Generated by $as_me.
+$2
+SHELL=\${CONFIG_SHELL-$SHELL}
+export SHELL
+_ASEOF
+cat >>$1 <<\_ASEOF || lt_write_fail=1
+AS_SHELL_SANITIZE
+_AS_PREPARE
+exec AS_MESSAGE_FD>&1
+_ASEOF
+test $lt_write_fail = 0 && chmod +x $1[]dnl
+m4_popdef([AS_MESSAGE_LOG_FD])])])# _LT_GENERATED_FILE_INIT
+
+# LT_OUTPUT
+# ---------
+# This macro allows early generation of the libtool script (before
+# AC_OUTPUT is called), incase it is used in configure for compilation
+# tests.
+AC_DEFUN([LT_OUTPUT],
+[: ${CONFIG_LT=./config.lt}
+AC_MSG_NOTICE([creating $CONFIG_LT])
+_LT_GENERATED_FILE_INIT(["$CONFIG_LT"],
+[# Run this file to recreate a libtool stub with the current configuration.])
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+lt_cl_silent=false
+exec AS_MESSAGE_LOG_FD>>config.log
+{
+ echo
+ AS_BOX([Running $as_me.])
+} >&AS_MESSAGE_LOG_FD
+
+lt_cl_help="\
+\`$as_me' creates a local libtool stub from the current configuration,
+for use in further configure time tests before the real libtool is
+generated.
+
+Usage: $[0] [[OPTIONS]]
+
+ -h, --help print this help, then exit
+ -V, --version print version number, then exit
+ -q, --quiet do not print progress messages
+ -d, --debug don't remove temporary files
+
+Report bugs to <bug-libtool@gnu.org>."
+
+lt_cl_version="\
+m4_ifset([AC_PACKAGE_NAME], [AC_PACKAGE_NAME ])config.lt[]dnl
+m4_ifset([AC_PACKAGE_VERSION], [ AC_PACKAGE_VERSION])
+configured by $[0], generated by m4_PACKAGE_STRING.
+
+Copyright (C) 2011 Free Software Foundation, Inc.
+This config.lt script is free software; the Free Software Foundation
+gives unlimited permision to copy, distribute and modify it."
+
+while test $[#] != 0
+do
+ case $[1] in
+ --version | --v* | -V )
+ echo "$lt_cl_version"; exit 0 ;;
+ --help | --h* | -h )
+ echo "$lt_cl_help"; exit 0 ;;
+ --debug | --d* | -d )
+ debug=: ;;
+ --quiet | --q* | --silent | --s* | -q )
+ lt_cl_silent=: ;;
+
+ -*) AC_MSG_ERROR([unrecognized option: $[1]
+Try \`$[0] --help' for more information.]) ;;
+
+ *) AC_MSG_ERROR([unrecognized argument: $[1]
+Try \`$[0] --help' for more information.]) ;;
+ esac
+ shift
+done
+
+if $lt_cl_silent; then
+ exec AS_MESSAGE_FD>/dev/null
+fi
+_LTEOF
+
+cat >>"$CONFIG_LT" <<_LTEOF
+_LT_OUTPUT_LIBTOOL_COMMANDS_INIT
+_LTEOF
+
+cat >>"$CONFIG_LT" <<\_LTEOF
+AC_MSG_NOTICE([creating $ofile])
+_LT_OUTPUT_LIBTOOL_COMMANDS
+AS_EXIT(0)
+_LTEOF
+chmod +x "$CONFIG_LT"
+
+# configure is writing to config.log, but config.lt does its own redirection,
+# appending to config.log, which fails on DOS, as config.log is still kept
+# open by configure. Here we exec the FD to /dev/null, effectively closing
+# config.log, so it can be properly (re)opened and appended to by config.lt.
+lt_cl_success=:
+test "$silent" = yes &&
+ lt_config_lt_args="$lt_config_lt_args --quiet"
+exec AS_MESSAGE_LOG_FD>/dev/null
+$SHELL "$CONFIG_LT" $lt_config_lt_args || lt_cl_success=false
+exec AS_MESSAGE_LOG_FD>>config.log
+$lt_cl_success || AS_EXIT(1)
+])# LT_OUTPUT
+
+
+# _LT_CONFIG(TAG)
+# ---------------
+# If TAG is the built-in tag, create an initial libtool script with a
+# default configuration from the untagged config vars. Otherwise add code
+# to config.status for appending the configuration named by TAG from the
+# matching tagged config vars.
+m4_defun([_LT_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_CONFIG_SAVE_COMMANDS([
+ m4_define([_LT_TAG], m4_if([$1], [], [C], [$1]))dnl
+ m4_if(_LT_TAG, [C], [
+ # See if we are running on zsh, and set the options which allow our
+ # commands through without removal of \ escapes.
+ if test -n "${ZSH_VERSION+set}" ; then
+ setopt NO_GLOB_SUBST
+ fi
+
+ cfgfile="${ofile}T"
+ trap "$RM \"$cfgfile\"; exit 1" 1 2 15
+ $RM "$cfgfile"
+
+ cat <<_LT_EOF >> "$cfgfile"
+#! $SHELL
+
+# `$ECHO "$ofile" | sed 's%^.*/%%'` - Provide generalized library-building support services.
+# Generated automatically by $as_me ($PACKAGE$TIMESTAMP) $VERSION
+# Libtool was configured on host `(hostname || uname -n) 2>/dev/null | sed 1q`:
+# NOTE: Changes made to this file will be lost: look at ltmain.sh.
+#
+_LT_COPYING
+_LT_LIBTOOL_TAGS
+
+# ### BEGIN LIBTOOL CONFIG
+_LT_LIBTOOL_CONFIG_VARS
+_LT_LIBTOOL_TAG_VARS
+# ### END LIBTOOL CONFIG
+
+_LT_EOF
+
+ case $host_os in
+ aix3*)
+ cat <<\_LT_EOF >> "$cfgfile"
+# AIX sometimes has problems with the GCC collect2 program. For some
+# reason, if we set the COLLECT_NAMES environment variable, the problems
+# vanish in a puff of smoke.
+if test "X${COLLECT_NAMES+set}" != Xset; then
+ COLLECT_NAMES=
+ export COLLECT_NAMES
+fi
+_LT_EOF
+ ;;
+ esac
+
+ _LT_PROG_LTMAIN
+
+ # We use sed instead of cat because bash on DJGPP gets confused if
+ # if finds mixed CR/LF and LF-only lines. Since sed operates in
+ # text mode, it properly converts lines to CR/LF. This bash problem
+ # is reportedly fixed, but why not run on old versions too?
+ sed '$q' "$ltmain" >> "$cfgfile" \
+ || (rm -f "$cfgfile"; exit 1)
+
+ _LT_PROG_REPLACE_SHELLFNS
+
+ mv -f "$cfgfile" "$ofile" ||
+ (rm -f "$ofile" && cp "$cfgfile" "$ofile" && rm -f "$cfgfile")
+ chmod +x "$ofile"
+],
+[cat <<_LT_EOF >> "$ofile"
+
+dnl Unfortunately we have to use $1 here, since _LT_TAG is not expanded
+dnl in a comment (ie after a #).
+# ### BEGIN LIBTOOL TAG CONFIG: $1
+_LT_LIBTOOL_TAG_VARS(_LT_TAG)
+# ### END LIBTOOL TAG CONFIG: $1
+_LT_EOF
+])dnl /m4_if
+],
+[m4_if([$1], [], [
+ PACKAGE='$PACKAGE'
+ VERSION='$VERSION'
+ TIMESTAMP='$TIMESTAMP'
+ RM='$RM'
+ ofile='$ofile'], [])
+])dnl /_LT_CONFIG_SAVE_COMMANDS
+])# _LT_CONFIG
+
+
+# LT_SUPPORTED_TAG(TAG)
+# ---------------------
+# Trace this macro to discover what tags are supported by the libtool
+# --tag option, using:
+# autoconf --trace 'LT_SUPPORTED_TAG:$1'
+AC_DEFUN([LT_SUPPORTED_TAG], [])
+
+
+# C support is built-in for now
+m4_define([_LT_LANG_C_enabled], [])
+m4_define([_LT_TAGS], [])
+
+
+# LT_LANG(LANG)
+# -------------
+# Enable libtool support for the given language if not already enabled.
+AC_DEFUN([LT_LANG],
+[AC_BEFORE([$0], [LT_OUTPUT])dnl
+m4_case([$1],
+ [C], [_LT_LANG(C)],
+ [C++], [_LT_LANG(CXX)],
+ [Go], [_LT_LANG(GO)],
+ [Java], [_LT_LANG(GCJ)],
+ [Fortran 77], [_LT_LANG(F77)],
+ [Fortran], [_LT_LANG(FC)],
+ [Windows Resource], [_LT_LANG(RC)],
+ [m4_ifdef([_LT_LANG_]$1[_CONFIG],
+ [_LT_LANG($1)],
+ [m4_fatal([$0: unsupported language: "$1"])])])dnl
+])# LT_LANG
+
+
+# _LT_LANG(LANGNAME)
+# ------------------
+m4_defun([_LT_LANG],
+[m4_ifdef([_LT_LANG_]$1[_enabled], [],
+ [LT_SUPPORTED_TAG([$1])dnl
+ m4_append([_LT_TAGS], [$1 ])dnl
+ m4_define([_LT_LANG_]$1[_enabled], [])dnl
+ _LT_LANG_$1_CONFIG($1)])dnl
+])# _LT_LANG
+
+
+m4_ifndef([AC_PROG_GO], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_GO. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+m4_defun([AC_PROG_GO],
+[AC_LANG_PUSH(Go)dnl
+AC_ARG_VAR([GOC], [Go compiler command])dnl
+AC_ARG_VAR([GOFLAGS], [Go compiler flags])dnl
+_AC_ARG_VAR_LDFLAGS()dnl
+AC_CHECK_TOOL(GOC, gccgo)
+if test -z "$GOC"; then
+ if test -n "$ac_tool_prefix"; then
+ AC_CHECK_PROG(GOC, [${ac_tool_prefix}gccgo], [${ac_tool_prefix}gccgo])
+ fi
+fi
+if test -z "$GOC"; then
+ AC_CHECK_PROG(GOC, gccgo, gccgo, false)
+fi
+])#m4_defun
+])#m4_ifndef
+
+
+# _LT_LANG_DEFAULT_CONFIG
+# -----------------------
+m4_defun([_LT_LANG_DEFAULT_CONFIG],
+[AC_PROVIDE_IFELSE([AC_PROG_CXX],
+ [LT_LANG(CXX)],
+ [m4_define([AC_PROG_CXX], defn([AC_PROG_CXX])[LT_LANG(CXX)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_F77],
+ [LT_LANG(F77)],
+ [m4_define([AC_PROG_F77], defn([AC_PROG_F77])[LT_LANG(F77)])])
+
+AC_PROVIDE_IFELSE([AC_PROG_FC],
+ [LT_LANG(FC)],
+ [m4_define([AC_PROG_FC], defn([AC_PROG_FC])[LT_LANG(FC)])])
+
+dnl The call to [A][M_PROG_GCJ] is quoted like that to stop aclocal
+dnl pulling things in needlessly.
+AC_PROVIDE_IFELSE([AC_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([A][M_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [AC_PROVIDE_IFELSE([LT_PROG_GCJ],
+ [LT_LANG(GCJ)],
+ [m4_ifdef([AC_PROG_GCJ],
+ [m4_define([AC_PROG_GCJ], defn([AC_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([A][M_PROG_GCJ],
+ [m4_define([A][M_PROG_GCJ], defn([A][M_PROG_GCJ])[LT_LANG(GCJ)])])
+ m4_ifdef([LT_PROG_GCJ],
+ [m4_define([LT_PROG_GCJ], defn([LT_PROG_GCJ])[LT_LANG(GCJ)])])])])])
+
+AC_PROVIDE_IFELSE([AC_PROG_GO],
+ [LT_LANG(GO)],
+ [m4_define([AC_PROG_GO], defn([AC_PROG_GO])[LT_LANG(GO)])])
+
+AC_PROVIDE_IFELSE([LT_PROG_RC],
+ [LT_LANG(RC)],
+ [m4_define([LT_PROG_RC], defn([LT_PROG_RC])[LT_LANG(RC)])])
+])# _LT_LANG_DEFAULT_CONFIG
+
+# Obsolete macros:
+AU_DEFUN([AC_LIBTOOL_CXX], [LT_LANG(C++)])
+AU_DEFUN([AC_LIBTOOL_F77], [LT_LANG(Fortran 77)])
+AU_DEFUN([AC_LIBTOOL_FC], [LT_LANG(Fortran)])
+AU_DEFUN([AC_LIBTOOL_GCJ], [LT_LANG(Java)])
+AU_DEFUN([AC_LIBTOOL_RC], [LT_LANG(Windows Resource)])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_CXX], [])
+dnl AC_DEFUN([AC_LIBTOOL_F77], [])
+dnl AC_DEFUN([AC_LIBTOOL_FC], [])
+dnl AC_DEFUN([AC_LIBTOOL_GCJ], [])
+dnl AC_DEFUN([AC_LIBTOOL_RC], [])
+
+
+# _LT_TAG_COMPILER
+# ----------------
+m4_defun([_LT_TAG_COMPILER],
+[AC_REQUIRE([AC_PROG_CC])dnl
+
+_LT_DECL([LTCC], [CC], [1], [A C compiler])dnl
+_LT_DECL([LTCFLAGS], [CFLAGS], [1], [LTCC compiler flags])dnl
+_LT_TAGDECL([CC], [compiler], [1], [A language specific compiler])dnl
+_LT_TAGDECL([with_gcc], [GCC], [0], [Is the compiler the GNU compiler?])dnl
+
+# If no C compiler was specified, use CC.
+LTCC=${LTCC-"$CC"}
+
+# If no C compiler flags were specified, use CFLAGS.
+LTCFLAGS=${LTCFLAGS-"$CFLAGS"}
+
+# Allow CC to be a program name with arguments.
+compiler=$CC
+])# _LT_TAG_COMPILER
+
+
+# _LT_COMPILER_BOILERPLATE
+# ------------------------
+# Check for compiler boilerplate output or warnings with
+# the simple compiler test code.
+m4_defun([_LT_COMPILER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_compile_test_code" >conftest.$ac_ext
+eval "$ac_compile" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_compiler_boilerplate=`cat conftest.err`
+$RM conftest*
+])# _LT_COMPILER_BOILERPLATE
+
+
+# _LT_LINKER_BOILERPLATE
+# ----------------------
+# Check for linker boilerplate output or warnings with
+# the simple link test code.
+m4_defun([_LT_LINKER_BOILERPLATE],
+[m4_require([_LT_DECL_SED])dnl
+ac_outfile=conftest.$ac_objext
+echo "$lt_simple_link_test_code" >conftest.$ac_ext
+eval "$ac_link" 2>&1 >/dev/null | $SED '/^$/d; /^ *+/d' >conftest.err
+_lt_linker_boilerplate=`cat conftest.err`
+$RM -r conftest*
+])# _LT_LINKER_BOILERPLATE
+
+# _LT_REQUIRED_DARWIN_CHECKS
+# -------------------------
+m4_defun_once([_LT_REQUIRED_DARWIN_CHECKS],[
+ case $host_os in
+ rhapsody* | darwin*)
+ AC_CHECK_TOOL([DSYMUTIL], [dsymutil], [:])
+ AC_CHECK_TOOL([NMEDIT], [nmedit], [:])
+ AC_CHECK_TOOL([LIPO], [lipo], [:])
+ AC_CHECK_TOOL([OTOOL], [otool], [:])
+ AC_CHECK_TOOL([OTOOL64], [otool64], [:])
+ _LT_DECL([], [DSYMUTIL], [1],
+ [Tool to manipulate archived DWARF debug symbol files on Mac OS X])
+ _LT_DECL([], [NMEDIT], [1],
+ [Tool to change global to local symbols on Mac OS X])
+ _LT_DECL([], [LIPO], [1],
+ [Tool to manipulate fat objects and archives on Mac OS X])
+ _LT_DECL([], [OTOOL], [1],
+ [ldd/readelf like tool for Mach-O binaries on Mac OS X])
+ _LT_DECL([], [OTOOL64], [1],
+ [ldd/readelf like tool for 64 bit Mach-O binaries on Mac OS X 10.4])
+
+ AC_CACHE_CHECK([for -single_module linker flag],[lt_cv_apple_cc_single_mod],
+ [lt_cv_apple_cc_single_mod=no
+ if test -z "${LT_MULTI_MODULE}"; then
+ # By default we will add the -single_module flag. You can override
+ # by either setting the environment variable LT_MULTI_MODULE
+ # non-empty at configure time, or by adding -multi_module to the
+ # link flags.
+ rm -rf libconftest.dylib*
+ echo "int foo(void){return 1;}" > conftest.c
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+ -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+ _lt_result=$?
+ # If there is a non-empty error log, and "single_module"
+ # appears in it, assume the flag caused a linker warning
+ if test -s conftest.err && $GREP single_module conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ # Otherwise, if the output was created with a 0 exit code from
+ # the compiler, it worked.
+ elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+ lt_cv_apple_cc_single_mod=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -rf libconftest.dylib*
+ rm -f conftest.*
+ fi])
+
+ AC_CACHE_CHECK([for -exported_symbols_list linker flag],
+ [lt_cv_ld_exported_symbols_list],
+ [lt_cv_ld_exported_symbols_list=no
+ save_LDFLAGS=$LDFLAGS
+ echo "_main" > conftest.sym
+ LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [lt_cv_ld_exported_symbols_list=yes],
+ [lt_cv_ld_exported_symbols_list=no])
+ LDFLAGS="$save_LDFLAGS"
+ ])
+
+ AC_CACHE_CHECK([for -force_load linker flag],[lt_cv_ld_force_load],
+ [lt_cv_ld_force_load=no
+ cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&AS_MESSAGE_LOG_FD
+ echo "$AR cru libconftest.a conftest.o" >&AS_MESSAGE_LOG_FD
+ $AR cru libconftest.a conftest.o 2>&AS_MESSAGE_LOG_FD
+ echo "$RANLIB libconftest.a" >&AS_MESSAGE_LOG_FD
+ $RANLIB libconftest.a 2>&AS_MESSAGE_LOG_FD
+ cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+ echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&AS_MESSAGE_LOG_FD
+ $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+ _lt_result=$?
+ if test -s conftest.err && $GREP force_load conftest.err; then
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+ lt_cv_ld_force_load=yes
+ else
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ fi
+ rm -f conftest.err libconftest.a conftest conftest.c
+ rm -rf conftest.dSYM
+ ])
+ case $host_os in
+ rhapsody* | darwin1.[[012]])
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+ darwin1.*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ darwin*) # darwin 5.x on
+ # if running on 10.5 or later, the deployment target defaults
+ # to the OS version, if on x86, and 10.4, the deployment
+ # target defaults to 10.4. Don't you love it?
+ case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+ 10.0,*86*-darwin8*|10.0,*-darwin[[91]]*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ 10.[[012]]*)
+ _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+ 10.*)
+ _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+ esac
+ ;;
+ esac
+ if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+ _lt_dar_single_mod='$single_module'
+ fi
+ if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+ _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+ else
+ _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+ fi
+ if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+ _lt_dsymutil='~$DSYMUTIL $lib || :'
+ else
+ _lt_dsymutil=
+ fi
+ ;;
+ esac
+])
+
+
+# _LT_DARWIN_LINKER_FEATURES([TAG])
+# ---------------------------------
+# Checks for linker and compiler features on darwin
+m4_defun([_LT_DARWIN_LINKER_FEATURES],
+[
+ m4_require([_LT_REQUIRED_DARWIN_CHECKS])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_automatic, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ if test "$lt_cv_ld_force_load" = "yes"; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience ${wl}-force_load,$conv\"; done; func_echo_all \"$new_convenience\"`'
+ m4_case([$1], [F77], [_LT_TAGVAR(compiler_needs_object, $1)=yes],
+ [FC], [_LT_TAGVAR(compiler_needs_object, $1)=yes])
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=''
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)="$_lt_dar_allow_undefined"
+ case $cc_basename in
+ ifort*) _lt_dar_can_shared=yes ;;
+ *) _lt_dar_can_shared=$GCC ;;
+ esac
+ if test "$_lt_dar_can_shared" = "yes"; then
+ output_verbose_link_cmd=func_echo_all
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring $_lt_dar_single_mod${_lt_dsymutil}"
+ _LT_TAGVAR(module_cmds, $1)="\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \$libobjs \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring ${_lt_dar_single_mod}${_lt_dar_export_syms}${_lt_dsymutil}"
+ _LT_TAGVAR(module_expsym_cmds, $1)="sed -e 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC \$allow_undefined_flag -o \$lib -bundle \$libobjs \$deplibs \$compiler_flags${_lt_dar_export_syms}${_lt_dsymutil}"
+ m4_if([$1], [CXX],
+[ if test "$lt_cv_apple_cc_single_mod" != "yes"; then
+ _LT_TAGVAR(archive_cmds, $1)="\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dsymutil}"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="sed 's,^,_,' < \$export_symbols > \$output_objdir/\${libname}-symbols.expsym~\$CC -r -keep_private_externs -nostdlib -o \${lib}-master.o \$libobjs~\$CC -dynamiclib \$allow_undefined_flag -o \$lib \${lib}-master.o \$deplibs \$compiler_flags -install_name \$rpath/\$soname \$verstring${_lt_dar_export_syms}${_lt_dsymutil}"
+ fi
+],[])
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+])
+
+# _LT_SYS_MODULE_PATH_AIX([TAGNAME])
+# ----------------------------------
+# Links a minimal program and checks the executable
+# for the system default hardcoded library path. In most cases,
+# this is /usr/lib:/lib, but when the MPI compilers are used
+# the location of the communication and MPI libs are included too.
+# If we don't find anything, use the default library path according
+# to the aix ld manual.
+# Store the results from the different compilers for each TAGNAME.
+# Allow to override them for all tags through lt_cv_aix_libpath.
+m4_defun([_LT_SYS_MODULE_PATH_AIX],
+[m4_require([_LT_DECL_SED])dnl
+if test "${lt_cv_aix_libpath+set}" = set; then
+ aix_libpath=$lt_cv_aix_libpath
+else
+ AC_CACHE_VAL([_LT_TAGVAR([lt_cv_aix_libpath_], [$1])],
+ [AC_LINK_IFELSE([AC_LANG_PROGRAM],[
+ lt_aix_libpath_sed='[
+ /Import File Strings/,/^$/ {
+ /^0/ {
+ s/^0 *\([^ ]*\) *$/\1/
+ p
+ }
+ }]'
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -H conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ # Check for a 64-bit object if we didn't find anything.
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])=`dump -HX64 conftest$ac_exeext 2>/dev/null | $SED -n -e "$lt_aix_libpath_sed"`
+ fi],[])
+ if test -z "$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])"; then
+ _LT_TAGVAR([lt_cv_aix_libpath_], [$1])="/usr/lib:/lib"
+ fi
+ ])
+ aix_libpath=$_LT_TAGVAR([lt_cv_aix_libpath_], [$1])
+fi
+])# _LT_SYS_MODULE_PATH_AIX
+
+
+# _LT_SHELL_INIT(ARG)
+# -------------------
+m4_define([_LT_SHELL_INIT],
+[m4_divert_text([M4SH-INIT], [$1
+])])# _LT_SHELL_INIT
+
+
+
+# _LT_PROG_ECHO_BACKSLASH
+# -----------------------
+# Find how we can fake an echo command that does not interpret backslash.
+# In particular, with Autoconf 2.60 or later we add some code to the start
+# of the generated configure script which will find a shell with a builtin
+# printf (which we can use as an echo command).
+m4_defun([_LT_PROG_ECHO_BACKSLASH],
+[ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+AC_MSG_CHECKING([how to print strings])
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+ test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+ ECHO='printf %s\n'
+else
+ # Use this function as a fallback that always works.
+ func_fallback_echo ()
+ {
+ eval 'cat <<_LTECHO_EOF
+$[]1
+_LTECHO_EOF'
+ }
+ ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+ $ECHO "$*"
+}
+
+case "$ECHO" in
+ printf*) AC_MSG_RESULT([printf]) ;;
+ print*) AC_MSG_RESULT([print -r]) ;;
+ *) AC_MSG_RESULT([cat]) ;;
+esac
+
+m4_ifdef([_AS_DETECT_SUGGESTED],
+[_AS_DETECT_SUGGESTED([
+ test -n "${ZSH_VERSION+set}${BASH_VERSION+set}" || (
+ ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+ PATH=/empty FPATH=/empty; export PATH FPATH
+ test "X`printf %s $ECHO`" = "X$ECHO" \
+ || test "X`print -r -- $ECHO`" = "X$ECHO" )])])
+
+_LT_DECL([], [SHELL], [1], [Shell to use when invoking shell scripts])
+_LT_DECL([], [ECHO], [1], [An echo program that protects backslashes])
+])# _LT_PROG_ECHO_BACKSLASH
+
+
+# _LT_WITH_SYSROOT
+# ----------------
+AC_DEFUN([_LT_WITH_SYSROOT],
+[AC_MSG_CHECKING([for sysroot])
+AC_ARG_WITH([sysroot],
+[ --with-sysroot[=DIR] Search for dependent libraries within DIR
+ (or the compiler's sysroot if not specified).],
+[], [with_sysroot=no])
+
+dnl lt_sysroot will always be passed unquoted. We quote it here
+dnl in case the user passed a directory name.
+lt_sysroot=
+case ${with_sysroot} in #(
+ yes)
+ if test "$GCC" = yes; then
+ lt_sysroot=`$CC --print-sysroot 2>/dev/null`
+ fi
+ ;; #(
+ /*)
+ lt_sysroot=`echo "$with_sysroot" | sed -e "$sed_quote_subst"`
+ ;; #(
+ no|'')
+ ;; #(
+ *)
+ AC_MSG_RESULT([${with_sysroot}])
+ AC_MSG_ERROR([The sysroot must be an absolute path.])
+ ;;
+esac
+
+ AC_MSG_RESULT([${lt_sysroot:-no}])
+_LT_DECL([], [lt_sysroot], [0], [The root where to search for ]dnl
+[dependent libraries, and in which our libraries should be installed.])])
+
+# _LT_ENABLE_LOCK
+# ---------------
+m4_defun([_LT_ENABLE_LOCK],
+[AC_ARG_ENABLE([libtool-lock],
+ [AS_HELP_STRING([--disable-libtool-lock],
+ [avoid locking (might break parallel builds)])])
+test "x$enable_libtool_lock" != xno && enable_libtool_lock=yes
+
+# Some flags need to be propagated to the compiler or linker for good
+# libtool support.
+case $host in
+ia64-*-hpux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *ELF-32*)
+ HPUX_IA64_MODE="32"
+ ;;
+ *ELF-64*)
+ HPUX_IA64_MODE="64"
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+*-*-irix6*)
+ # Find out which ABI we are using.
+ echo '[#]line '$LINENO' "configure"' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -melf32bsmip"
+ ;;
+ *N32*)
+ LD="${LD-ld} -melf32bmipn32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -melf64bmip"
+ ;;
+ esac
+ else
+ case `/usr/bin/file conftest.$ac_objext` in
+ *32-bit*)
+ LD="${LD-ld} -32"
+ ;;
+ *N32*)
+ LD="${LD-ld} -n32"
+ ;;
+ *64-bit*)
+ LD="${LD-ld} -64"
+ ;;
+ esac
+ fi
+ fi
+ rm -rf conftest*
+ ;;
+
+x86_64-*kfreebsd*-gnu|x86_64-*linux*|powerpc*-*linux*| \
+s390*-*linux*|s390*-*tpf*|sparc*-*linux*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *32-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_i386_fbsd"
+ ;;
+ x86_64-*linux*)
+ case `/usr/bin/file conftest.o` in
+ *x86-64*)
+ LD="${LD-ld} -m elf32_x86_64"
+ ;;
+ *)
+ LD="${LD-ld} -m elf_i386"
+ ;;
+ esac
+ ;;
+ powerpc64le-*)
+ LD="${LD-ld} -m elf32lppclinux"
+ ;;
+ powerpc64-*)
+ LD="${LD-ld} -m elf32ppclinux"
+ ;;
+ s390x-*linux*)
+ LD="${LD-ld} -m elf_s390"
+ ;;
+ sparc64-*linux*)
+ LD="${LD-ld} -m elf32_sparc"
+ ;;
+ esac
+ ;;
+ *64-bit*)
+ case $host in
+ x86_64-*kfreebsd*-gnu)
+ LD="${LD-ld} -m elf_x86_64_fbsd"
+ ;;
+ x86_64-*linux*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ powerpcle-*)
+ LD="${LD-ld} -m elf64lppc"
+ ;;
+ powerpc-*)
+ LD="${LD-ld} -m elf64ppc"
+ ;;
+ s390*-*linux*|s390*-*tpf*)
+ LD="${LD-ld} -m elf64_s390"
+ ;;
+ sparc*-*linux*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+
+*-*-sco3.2v5*)
+ # On SCO OpenServer 5, we need -belf to get full-featured binaries.
+ SAVE_CFLAGS="$CFLAGS"
+ CFLAGS="$CFLAGS -belf"
+ AC_CACHE_CHECK([whether the C compiler needs -belf], lt_cv_cc_needs_belf,
+ [AC_LANG_PUSH(C)
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([[]],[[]])],[lt_cv_cc_needs_belf=yes],[lt_cv_cc_needs_belf=no])
+ AC_LANG_POP])
+ if test x"$lt_cv_cc_needs_belf" != x"yes"; then
+ # this is probably gcc 2.8.0, egcs 1.0 or newer; no need for -belf
+ CFLAGS="$SAVE_CFLAGS"
+ fi
+ ;;
+*-*solaris*)
+ # Find out which ABI we are using.
+ echo 'int i;' > conftest.$ac_ext
+ if AC_TRY_EVAL(ac_compile); then
+ case `/usr/bin/file conftest.o` in
+ *64-bit*)
+ case $lt_cv_prog_gnu_ld in
+ yes*)
+ case $host in
+ i?86-*-solaris*)
+ LD="${LD-ld} -m elf_x86_64"
+ ;;
+ sparc*-*-solaris*)
+ LD="${LD-ld} -m elf64_sparc"
+ ;;
+ esac
+ # GNU ld 2.21 introduced _sol2 emulations. Use them if available.
+ if ${LD-ld} -V | grep _sol2 >/dev/null 2>&1; then
+ LD="${LD-ld}_sol2"
+ fi
+ ;;
+ *)
+ if ${LD-ld} -64 -r -o conftest2.o conftest.o >/dev/null 2>&1; then
+ LD="${LD-ld} -64"
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ rm -rf conftest*
+ ;;
+esac
+
+need_locks="$enable_libtool_lock"
+])# _LT_ENABLE_LOCK
+
+
+# _LT_PROG_AR
+# -----------
+m4_defun([_LT_PROG_AR],
+[AC_CHECK_TOOLS(AR, [ar], false)
+: ${AR=ar}
+: ${AR_FLAGS=cru}
+_LT_DECL([], [AR], [1], [The archiver])
+_LT_DECL([], [AR_FLAGS], [1], [Flags to create an archive])
+
+AC_CACHE_CHECK([for archiver @FILE support], [lt_cv_ar_at_file],
+ [lt_cv_ar_at_file=no
+ AC_COMPILE_IFELSE([AC_LANG_PROGRAM],
+ [echo conftest.$ac_objext > conftest.lst
+ lt_ar_try='$AR $AR_FLAGS libconftest.a @conftest.lst >&AS_MESSAGE_LOG_FD'
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -eq 0; then
+ # Ensure the archiver fails upon bogus file names.
+ rm -f conftest.$ac_objext libconftest.a
+ AC_TRY_EVAL([lt_ar_try])
+ if test "$ac_status" -ne 0; then
+ lt_cv_ar_at_file=@
+ fi
+ fi
+ rm -f conftest.* libconftest.a
+ ])
+ ])
+
+if test "x$lt_cv_ar_at_file" = xno; then
+ archiver_list_spec=
+else
+ archiver_list_spec=$lt_cv_ar_at_file
+fi
+_LT_DECL([], [archiver_list_spec], [1],
+ [How to feed a file listing to the archiver])
+])# _LT_PROG_AR
+
+
+# _LT_CMD_OLD_ARCHIVE
+# -------------------
+m4_defun([_LT_CMD_OLD_ARCHIVE],
+[_LT_PROG_AR
+
+AC_CHECK_TOOL(STRIP, strip, :)
+test -z "$STRIP" && STRIP=:
+_LT_DECL([], [STRIP], [1], [A symbol stripping program])
+
+AC_CHECK_TOOL(RANLIB, ranlib, :)
+test -z "$RANLIB" && RANLIB=:
+_LT_DECL([], [RANLIB], [1],
+ [Commands used to install an old-style archive])
+
+# Determine commands to create old-style static archives.
+old_archive_cmds='$AR $AR_FLAGS $oldlib$oldobjs'
+old_postinstall_cmds='chmod 644 $oldlib'
+old_postuninstall_cmds=
+
+if test -n "$RANLIB"; then
+ case $host_os in
+ openbsd*)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB -t \$tool_oldlib"
+ ;;
+ *)
+ old_postinstall_cmds="$old_postinstall_cmds~\$RANLIB \$tool_oldlib"
+ ;;
+ esac
+ old_archive_cmds="$old_archive_cmds~\$RANLIB \$tool_oldlib"
+fi
+
+case $host_os in
+ darwin*)
+ lock_old_archive_extraction=yes ;;
+ *)
+ lock_old_archive_extraction=no ;;
+esac
+_LT_DECL([], [old_postinstall_cmds], [2])
+_LT_DECL([], [old_postuninstall_cmds], [2])
+_LT_TAGDECL([], [old_archive_cmds], [2],
+ [Commands used to build an old-style archive])
+_LT_DECL([], [lock_old_archive_extraction], [0],
+ [Whether to use a lock for old archive extraction])
+])# _LT_CMD_OLD_ARCHIVE
+
+
+# _LT_COMPILER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [OUTPUT-FILE], [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------------------
+# Check whether the given compiler option works
+AC_DEFUN([_LT_COMPILER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ m4_if([$4], , [ac_outfile=conftest.$ac_objext], [ac_outfile=$4])
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+ lt_compiler_flag="$3"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ # The option is referenced via a variable to avoid confusing sed.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>conftest.err)
+ ac_status=$?
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s "$ac_outfile"; then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings other than the usual output.
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' >conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if test ! -s conftest.er2 || diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ fi
+ $RM conftest*
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$5], , :, [$5])
+else
+ m4_if([$6], , :, [$6])
+fi
+])# _LT_COMPILER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_COMPILER_OPTION], [_LT_COMPILER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_COMPILER_OPTION], [])
+
+
+# _LT_LINKER_OPTION(MESSAGE, VARIABLE-NAME, FLAGS,
+# [ACTION-SUCCESS], [ACTION-FAILURE])
+# ----------------------------------------------------
+# Check whether the given linker option works
+AC_DEFUN([_LT_LINKER_OPTION],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_SED])dnl
+AC_CACHE_CHECK([$1], [$2],
+ [$2=no
+ save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS $3"
+ echo "$lt_simple_link_test_code" > conftest.$ac_ext
+ if (eval $ac_link 2>conftest.err) && test -s conftest$ac_exeext; then
+ # The linker can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ if test -s conftest.err; then
+ # Append any errors to the config.log.
+ cat conftest.err 1>&AS_MESSAGE_LOG_FD
+ $ECHO "$_lt_linker_boilerplate" | $SED '/^$/d' > conftest.exp
+ $SED '/^$/d; /^ *+/d' conftest.err >conftest.er2
+ if diff conftest.exp conftest.er2 >/dev/null; then
+ $2=yes
+ fi
+ else
+ $2=yes
+ fi
+ fi
+ $RM -r conftest*
+ LDFLAGS="$save_LDFLAGS"
+])
+
+if test x"[$]$2" = xyes; then
+ m4_if([$4], , :, [$4])
+else
+ m4_if([$5], , :, [$5])
+fi
+])# _LT_LINKER_OPTION
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_LINKER_OPTION], [_LT_LINKER_OPTION])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_LINKER_OPTION], [])
+
+
+# LT_CMD_MAX_LEN
+#---------------
+AC_DEFUN([LT_CMD_MAX_LEN],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+# find the maximum length of command line arguments
+AC_MSG_CHECKING([the maximum length of command line arguments])
+AC_CACHE_VAL([lt_cv_sys_max_cmd_len], [dnl
+ i=0
+ teststring="ABCD"
+
+ case $build_os in
+ msdosdjgpp*)
+ # On DJGPP, this test can blow up pretty badly due to problems in libc
+ # (any single argument exceeding 2000 bytes causes a buffer overrun
+ # during glob expansion). Even if it were fixed, the result of this
+ # check would be larger than it should be.
+ lt_cv_sys_max_cmd_len=12288; # 12K is about right
+ ;;
+
+ gnu*)
+ # Under GNU Hurd, this test is not required because there is
+ # no limit to the length of command line arguments.
+ # Libtool will interpret -1 as no limit whatsoever
+ lt_cv_sys_max_cmd_len=-1;
+ ;;
+
+ cygwin* | mingw* | cegcc*)
+ # On Win9x/ME, this test blows up -- it succeeds, but takes
+ # about 5 minutes as the teststring grows exponentially.
+ # Worse, since 9x/ME are not pre-emptively multitasking,
+ # you end up with a "frozen" computer, even though with patience
+ # the test eventually succeeds (with a max line length of 256k).
+ # Instead, let's just punt: use the minimum linelength reported by
+ # all of the supported platforms: 8192 (on NT/2K/XP).
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ mint*)
+ # On MiNT this can take a long time and run out of memory.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ amigaos*)
+ # On AmigaOS with pdksh, this test takes hours, literally.
+ # So we just punt and use a minimum line length of 8192.
+ lt_cv_sys_max_cmd_len=8192;
+ ;;
+
+ netbsd* | freebsd* | openbsd* | darwin* | dragonfly*)
+ # This has been around since 386BSD, at least. Likely further.
+ if test -x /sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/sbin/sysctl -n kern.argmax`
+ elif test -x /usr/sbin/sysctl; then
+ lt_cv_sys_max_cmd_len=`/usr/sbin/sysctl -n kern.argmax`
+ else
+ lt_cv_sys_max_cmd_len=65536 # usable default for all BSDs
+ fi
+ # And add a safety zone
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ ;;
+
+ interix*)
+ # We know the value 262144 and hardcode it with a safety zone (like BSD)
+ lt_cv_sys_max_cmd_len=196608
+ ;;
+
+ os2*)
+ # The test takes a long time on OS/2.
+ lt_cv_sys_max_cmd_len=8192
+ ;;
+
+ osf*)
+ # Dr. Hans Ekkehard Plesser reports seeing a kernel panic running configure
+ # due to this test when exec_disable_arg_limit is 1 on Tru64. It is not
+ # nice to cause kernel panics so lets avoid the loop below.
+ # First set a reasonable default.
+ lt_cv_sys_max_cmd_len=16384
+ #
+ if test -x /sbin/sysconfig; then
+ case `/sbin/sysconfig -q proc exec_disable_arg_limit` in
+ *1*) lt_cv_sys_max_cmd_len=-1 ;;
+ esac
+ fi
+ ;;
+ sco3.2v5*)
+ lt_cv_sys_max_cmd_len=102400
+ ;;
+ sysv5* | sco5v6* | sysv4.2uw2*)
+ kargmax=`grep ARG_MAX /etc/conf/cf.d/stune 2>/dev/null`
+ if test -n "$kargmax"; then
+ lt_cv_sys_max_cmd_len=`echo $kargmax | sed 's/.*[[ ]]//'`
+ else
+ lt_cv_sys_max_cmd_len=32768
+ fi
+ ;;
+ *)
+ lt_cv_sys_max_cmd_len=`(getconf ARG_MAX) 2> /dev/null`
+ if test -n "$lt_cv_sys_max_cmd_len" && \
+ test undefined != "$lt_cv_sys_max_cmd_len"; then
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 4`
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \* 3`
+ else
+ # Make teststring a little bigger before we do anything with it.
+ # a 1K string should be a reasonable start.
+ for i in 1 2 3 4 5 6 7 8 ; do
+ teststring=$teststring$teststring
+ done
+ SHELL=${SHELL-${CONFIG_SHELL-/bin/sh}}
+ # If test is not a shell built-in, we'll probably end up computing a
+ # maximum length that is only half of the actual maximum length, but
+ # we can't tell.
+ while { test "X"`env echo "$teststring$teststring" 2>/dev/null` \
+ = "X$teststring$teststring"; } >/dev/null 2>&1 &&
+ test $i != 17 # 1/2 MB should be enough
+ do
+ i=`expr $i + 1`
+ teststring=$teststring$teststring
+ done
+ # Only check the string length outside the loop.
+ lt_cv_sys_max_cmd_len=`expr "X$teststring" : ".*" 2>&1`
+ teststring=
+ # Add a significant safety factor because C++ compilers can tack on
+ # massive amounts of additional arguments before passing them to the
+ # linker. It appears as though 1/2 is a usable value.
+ lt_cv_sys_max_cmd_len=`expr $lt_cv_sys_max_cmd_len \/ 2`
+ fi
+ ;;
+ esac
+])
+if test -n $lt_cv_sys_max_cmd_len ; then
+ AC_MSG_RESULT($lt_cv_sys_max_cmd_len)
+else
+ AC_MSG_RESULT(none)
+fi
+max_cmd_len=$lt_cv_sys_max_cmd_len
+_LT_DECL([], [max_cmd_len], [0],
+ [What is the maximum length of a command?])
+])# LT_CMD_MAX_LEN
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_SYS_MAX_CMD_LEN], [LT_CMD_MAX_LEN])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_SYS_MAX_CMD_LEN], [])
+
+
+# _LT_HEADER_DLFCN
+# ----------------
+m4_defun([_LT_HEADER_DLFCN],
+[AC_CHECK_HEADERS([dlfcn.h], [], [], [AC_INCLUDES_DEFAULT])dnl
+])# _LT_HEADER_DLFCN
+
+
+# _LT_TRY_DLOPEN_SELF (ACTION-IF-TRUE, ACTION-IF-TRUE-W-USCORE,
+# ACTION-IF-FALSE, ACTION-IF-CROSS-COMPILING)
+# ----------------------------------------------------------------
+m4_defun([_LT_TRY_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "$cross_compiling" = yes; then :
+ [$4]
+else
+ lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
+ lt_status=$lt_dlunknown
+ cat > conftest.$ac_ext <<_LT_EOF
+[#line $LINENO "configure"
+#include "confdefs.h"
+
+#if HAVE_DLFCN_H
+#include <dlfcn.h>
+#endif
+
+#include <stdio.h>
+
+#ifdef RTLD_GLOBAL
+# define LT_DLGLOBAL RTLD_GLOBAL
+#else
+# ifdef DL_GLOBAL
+# define LT_DLGLOBAL DL_GLOBAL
+# else
+# define LT_DLGLOBAL 0
+# endif
+#endif
+
+/* We may have to define LT_DLLAZY_OR_NOW in the command line if we
+ find out it does not work in some platform. */
+#ifndef LT_DLLAZY_OR_NOW
+# ifdef RTLD_LAZY
+# define LT_DLLAZY_OR_NOW RTLD_LAZY
+# else
+# ifdef DL_LAZY
+# define LT_DLLAZY_OR_NOW DL_LAZY
+# else
+# ifdef RTLD_NOW
+# define LT_DLLAZY_OR_NOW RTLD_NOW
+# else
+# ifdef DL_NOW
+# define LT_DLLAZY_OR_NOW DL_NOW
+# else
+# define LT_DLLAZY_OR_NOW 0
+# endif
+# endif
+# endif
+# endif
+#endif
+
+/* When -fvisbility=hidden is used, assume the code has been annotated
+ correspondingly for the symbols needed. */
+#if defined(__GNUC__) && (((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ > 3))
+int fnord () __attribute__((visibility("default")));
+#endif
+
+int fnord () { return 42; }
+int main ()
+{
+ void *self = dlopen (0, LT_DLGLOBAL|LT_DLLAZY_OR_NOW);
+ int status = $lt_dlunknown;
+
+ if (self)
+ {
+ if (dlsym (self,"fnord")) status = $lt_dlno_uscore;
+ else
+ {
+ if (dlsym( self,"_fnord")) status = $lt_dlneed_uscore;
+ else puts (dlerror ());
+ }
+ /* dlclose (self); */
+ }
+ else
+ puts (dlerror ());
+
+ return status;
+}]
+_LT_EOF
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext} 2>/dev/null; then
+ (./conftest; exit; ) >&AS_MESSAGE_LOG_FD 2>/dev/null
+ lt_status=$?
+ case x$lt_status in
+ x$lt_dlno_uscore) $1 ;;
+ x$lt_dlneed_uscore) $2 ;;
+ x$lt_dlunknown|x*) $3 ;;
+ esac
+ else :
+ # compilation failed
+ $3
+ fi
+fi
+rm -fr conftest*
+])# _LT_TRY_DLOPEN_SELF
+
+
+# LT_SYS_DLOPEN_SELF
+# ------------------
+AC_DEFUN([LT_SYS_DLOPEN_SELF],
+[m4_require([_LT_HEADER_DLFCN])dnl
+if test "x$enable_dlopen" != xyes; then
+ enable_dlopen=unknown
+ enable_dlopen_self=unknown
+ enable_dlopen_self_static=unknown
+else
+ lt_cv_dlopen=no
+ lt_cv_dlopen_libs=
+
+ case $host_os in
+ beos*)
+ lt_cv_dlopen="load_add_on"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ;;
+
+ mingw* | pw32* | cegcc*)
+ lt_cv_dlopen="LoadLibrary"
+ lt_cv_dlopen_libs=
+ ;;
+
+ cygwin*)
+ lt_cv_dlopen="dlopen"
+ lt_cv_dlopen_libs=
+ ;;
+
+ darwin*)
+ # if libdl is installed we need to link against it
+ AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],[
+ lt_cv_dlopen="dyld"
+ lt_cv_dlopen_libs=
+ lt_cv_dlopen_self=yes
+ ])
+ ;;
+
+ *)
+ AC_CHECK_FUNC([shl_load],
+ [lt_cv_dlopen="shl_load"],
+ [AC_CHECK_LIB([dld], [shl_load],
+ [lt_cv_dlopen="shl_load" lt_cv_dlopen_libs="-ldld"],
+ [AC_CHECK_FUNC([dlopen],
+ [lt_cv_dlopen="dlopen"],
+ [AC_CHECK_LIB([dl], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-ldl"],
+ [AC_CHECK_LIB([svld], [dlopen],
+ [lt_cv_dlopen="dlopen" lt_cv_dlopen_libs="-lsvld"],
+ [AC_CHECK_LIB([dld], [dld_link],
+ [lt_cv_dlopen="dld_link" lt_cv_dlopen_libs="-ldld"])
+ ])
+ ])
+ ])
+ ])
+ ])
+ ;;
+ esac
+
+ if test "x$lt_cv_dlopen" != xno; then
+ enable_dlopen=yes
+ else
+ enable_dlopen=no
+ fi
+
+ case $lt_cv_dlopen in
+ dlopen)
+ save_CPPFLAGS="$CPPFLAGS"
+ test "x$ac_cv_header_dlfcn_h" = xyes && CPPFLAGS="$CPPFLAGS -DHAVE_DLFCN_H"
+
+ save_LDFLAGS="$LDFLAGS"
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $export_dynamic_flag_spec\"
+
+ save_LIBS="$LIBS"
+ LIBS="$lt_cv_dlopen_libs $LIBS"
+
+ AC_CACHE_CHECK([whether a program can dlopen itself],
+ lt_cv_dlopen_self, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self=yes, lt_cv_dlopen_self=yes,
+ lt_cv_dlopen_self=no, lt_cv_dlopen_self=cross)
+ ])
+
+ if test "x$lt_cv_dlopen_self" = xyes; then
+ wl=$lt_prog_compiler_wl eval LDFLAGS=\"\$LDFLAGS $lt_prog_compiler_static\"
+ AC_CACHE_CHECK([whether a statically linked program can dlopen itself],
+ lt_cv_dlopen_self_static, [dnl
+ _LT_TRY_DLOPEN_SELF(
+ lt_cv_dlopen_self_static=yes, lt_cv_dlopen_self_static=yes,
+ lt_cv_dlopen_self_static=no, lt_cv_dlopen_self_static=cross)
+ ])
+ fi
+
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+ ;;
+ esac
+
+ case $lt_cv_dlopen_self in
+ yes|no) enable_dlopen_self=$lt_cv_dlopen_self ;;
+ *) enable_dlopen_self=unknown ;;
+ esac
+
+ case $lt_cv_dlopen_self_static in
+ yes|no) enable_dlopen_self_static=$lt_cv_dlopen_self_static ;;
+ *) enable_dlopen_self_static=unknown ;;
+ esac
+fi
+_LT_DECL([dlopen_support], [enable_dlopen], [0],
+ [Whether dlopen is supported])
+_LT_DECL([dlopen_self], [enable_dlopen_self], [0],
+ [Whether dlopen of programs is supported])
+_LT_DECL([dlopen_self_static], [enable_dlopen_self_static], [0],
+ [Whether dlopen of statically linked programs is supported])
+])# LT_SYS_DLOPEN_SELF
+
+# Old name:
+AU_ALIAS([AC_LIBTOOL_DLOPEN_SELF], [LT_SYS_DLOPEN_SELF])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN_SELF], [])
+
+
+# _LT_COMPILER_C_O([TAGNAME])
+# ---------------------------
+# Check to see if options -c and -o are simultaneously supported by compiler.
+# This macro does not hard code the compiler like AC_PROG_CC_C_O.
+m4_defun([_LT_COMPILER_C_O],
+[m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_CACHE_CHECK([if $compiler supports -c -o file.$ac_objext],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=no
+ $RM -r conftest 2>/dev/null
+ mkdir conftest
+ cd conftest
+ mkdir out
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ lt_compiler_flag="-o out/conftest2.$ac_objext"
+ # Insert the option either (1) after the last *FLAGS variable, or
+ # (2) before a word containing "conftest.", or (3) at the end.
+ # Note that $ac_compile itself does not contain backslashes and begins
+ # with a dollar sign (not a hyphen), so the echo should work correctly.
+ lt_compile=`echo "$ac_compile" | $SED \
+ -e 's:.*FLAGS}\{0,1\} :&$lt_compiler_flag :; t' \
+ -e 's: [[^ ]]*conftest\.: $lt_compiler_flag&:; t' \
+ -e 's:$: $lt_compiler_flag:'`
+ (eval echo "\"\$as_me:$LINENO: $lt_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$lt_compile" 2>out/conftest.err)
+ ac_status=$?
+ cat out/conftest.err >&AS_MESSAGE_LOG_FD
+ echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+ if (exit $ac_status) && test -s out/conftest2.$ac_objext
+ then
+ # The compiler can only warn and ignore the option if not recognized
+ # So say no if there are warnings
+ $ECHO "$_lt_compiler_boilerplate" | $SED '/^$/d' > out/conftest.exp
+ $SED '/^$/d; /^ *+/d' out/conftest.err >out/conftest.er2
+ if test ! -s out/conftest.er2 || diff out/conftest.exp out/conftest.er2 >/dev/null; then
+ _LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+ fi
+ fi
+ chmod u+w . 2>&AS_MESSAGE_LOG_FD
+ $RM conftest*
+ # SGI C++ compiler will create directory out/ii_files/ for
+ # template instantiation
+ test -d out/ii_files && $RM out/ii_files/* && rmdir out/ii_files
+ $RM out/* && rmdir out
+ cd ..
+ $RM -r conftest
+ $RM conftest*
+])
+_LT_TAGDECL([compiler_c_o], [lt_cv_prog_compiler_c_o], [1],
+ [Does compiler simultaneously support -c and -o options?])
+])# _LT_COMPILER_C_O
+
+
+# _LT_COMPILER_FILE_LOCKS([TAGNAME])
+# ----------------------------------
+# Check to see if we can do hard links to lock some files if needed
+m4_defun([_LT_COMPILER_FILE_LOCKS],
+[m4_require([_LT_ENABLE_LOCK])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+_LT_COMPILER_C_O([$1])
+
+hard_links="nottested"
+if test "$_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)" = no && test "$need_locks" != no; then
+ # do not overwrite the value of need_locks provided by the user
+ AC_MSG_CHECKING([if we can lock with hard links])
+ hard_links=yes
+ $RM conftest*
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ touch conftest.a
+ ln conftest.a conftest.b 2>&5 || hard_links=no
+ ln conftest.a conftest.b 2>/dev/null && hard_links=no
+ AC_MSG_RESULT([$hard_links])
+ if test "$hard_links" = no; then
+ AC_MSG_WARN([`$CC' does not support `-c -o', so `make -j' may be unsafe])
+ need_locks=warn
+ fi
+else
+ need_locks=no
+fi
+_LT_DECL([], [need_locks], [1], [Must we lock files when doing compilation?])
+])# _LT_COMPILER_FILE_LOCKS
+
+
+# _LT_CHECK_OBJDIR
+# ----------------
+m4_defun([_LT_CHECK_OBJDIR],
+[AC_CACHE_CHECK([for objdir], [lt_cv_objdir],
+[rm -f .libs 2>/dev/null
+mkdir .libs 2>/dev/null
+if test -d .libs; then
+ lt_cv_objdir=.libs
+else
+ # MS-DOS does not allow filenames that begin with a dot.
+ lt_cv_objdir=_libs
+fi
+rmdir .libs 2>/dev/null])
+objdir=$lt_cv_objdir
+_LT_DECL([], [objdir], [0],
+ [The name of the directory that contains temporary libtool files])dnl
+m4_pattern_allow([LT_OBJDIR])dnl
+AC_DEFINE_UNQUOTED(LT_OBJDIR, "$lt_cv_objdir/",
+ [Define to the sub-directory in which libtool stores uninstalled libraries.])
+])# _LT_CHECK_OBJDIR
+
+
+# _LT_LINKER_HARDCODE_LIBPATH([TAGNAME])
+# --------------------------------------
+# Check hardcoding attributes.
+m4_defun([_LT_LINKER_HARDCODE_LIBPATH],
+[AC_MSG_CHECKING([how to hardcode library paths into programs])
+_LT_TAGVAR(hardcode_action, $1)=
+if test -n "$_LT_TAGVAR(hardcode_libdir_flag_spec, $1)" ||
+ test -n "$_LT_TAGVAR(runpath_var, $1)" ||
+ test "X$_LT_TAGVAR(hardcode_automatic, $1)" = "Xyes" ; then
+
+ # We can hardcode non-existent directories.
+ if test "$_LT_TAGVAR(hardcode_direct, $1)" != no &&
+ # If the only mechanism to avoid hardcoding is shlibpath_var, we
+ # have to relink, otherwise we might link with an installed library
+ # when we should be linking with a yet-to-be-installed one
+ ## test "$_LT_TAGVAR(hardcode_shlibpath_var, $1)" != no &&
+ test "$_LT_TAGVAR(hardcode_minus_L, $1)" != no; then
+ # Linking always hardcodes the temporary library directory.
+ _LT_TAGVAR(hardcode_action, $1)=relink
+ else
+ # We can link without hardcoding, and we can hardcode nonexisting dirs.
+ _LT_TAGVAR(hardcode_action, $1)=immediate
+ fi
+else
+ # We cannot hardcode anything, or else we can only hardcode existing
+ # directories.
+ _LT_TAGVAR(hardcode_action, $1)=unsupported
+fi
+AC_MSG_RESULT([$_LT_TAGVAR(hardcode_action, $1)])
+
+if test "$_LT_TAGVAR(hardcode_action, $1)" = relink ||
+ test "$_LT_TAGVAR(inherit_rpath, $1)" = yes; then
+ # Fast installation is not supported
+ enable_fast_install=no
+elif test "$shlibpath_overrides_runpath" = yes ||
+ test "$enable_shared" = no; then
+ # Fast installation is not necessary
+ enable_fast_install=needless
+fi
+_LT_TAGDECL([], [hardcode_action], [0],
+ [How to hardcode a shared library path into an executable])
+])# _LT_LINKER_HARDCODE_LIBPATH
+
+
+# _LT_CMD_STRIPLIB
+# ----------------
+m4_defun([_LT_CMD_STRIPLIB],
+[m4_require([_LT_DECL_EGREP])
+striplib=
+old_striplib=
+AC_MSG_CHECKING([whether stripping libraries is possible])
+if test -n "$STRIP" && $STRIP -V 2>&1 | $GREP "GNU strip" >/dev/null; then
+ test -z "$old_striplib" && old_striplib="$STRIP --strip-debug"
+ test -z "$striplib" && striplib="$STRIP --strip-unneeded"
+ AC_MSG_RESULT([yes])
+else
+# FIXME - insert some real tests, host_os isn't really good enough
+ case $host_os in
+ darwin*)
+ if test -n "$STRIP" ; then
+ striplib="$STRIP -x"
+ old_striplib="$STRIP -S"
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ fi
+ ;;
+ *)
+ AC_MSG_RESULT([no])
+ ;;
+ esac
+fi
+_LT_DECL([], [old_striplib], [1], [Commands to strip libraries])
+_LT_DECL([], [striplib], [1])
+])# _LT_CMD_STRIPLIB
+
+
+# _LT_SYS_DYNAMIC_LINKER([TAG])
+# -----------------------------
+# PORTME Fill in your ld.so characteristics
+m4_defun([_LT_SYS_DYNAMIC_LINKER],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_OBJDUMP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CHECK_SHELL_FEATURES])dnl
+AC_MSG_CHECKING([dynamic linker characteristics])
+m4_if([$1],
+ [], [
+if test "$GCC" = yes; then
+ case $host_os in
+ darwin*) lt_awk_arg="/^libraries:/,/LR/" ;;
+ *) lt_awk_arg="/^libraries:/" ;;
+ esac
+ case $host_os in
+ mingw* | cegcc*) lt_sed_strip_eq="s,=\([[A-Za-z]]:\),\1,g" ;;
+ *) lt_sed_strip_eq="s,=/,/,g" ;;
+ esac
+ lt_search_path_spec=`$CC -print-search-dirs | awk $lt_awk_arg | $SED -e "s/^libraries://" -e $lt_sed_strip_eq`
+ case $lt_search_path_spec in
+ *\;*)
+ # if the path contains ";" then we assume it to be the separator
+ # otherwise default to the standard path separator (i.e. ":") - it is
+ # assumed that no part of a normal pathname contains ";" but that should
+ # okay in the real world where ";" in dirpaths is itself problematic.
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED 's/;/ /g'`
+ ;;
+ *)
+ lt_search_path_spec=`$ECHO "$lt_search_path_spec" | $SED "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ esac
+ # Ok, now we have the path, separated by spaces, we can step through it
+ # and add multilib dir if necessary.
+ lt_tmp_lt_search_path_spec=
+ lt_multi_os_dir=`$CC $CPPFLAGS $CFLAGS $LDFLAGS -print-multi-os-directory 2>/dev/null`
+ for lt_sys_path in $lt_search_path_spec; do
+ if test -d "$lt_sys_path/$lt_multi_os_dir"; then
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path/$lt_multi_os_dir"
+ else
+ test -d "$lt_sys_path" && \
+ lt_tmp_lt_search_path_spec="$lt_tmp_lt_search_path_spec $lt_sys_path"
+ fi
+ done
+ lt_search_path_spec=`$ECHO "$lt_tmp_lt_search_path_spec" | awk '
+BEGIN {RS=" "; FS="/|\n";} {
+ lt_foo="";
+ lt_count=0;
+ for (lt_i = NF; lt_i > 0; lt_i--) {
+ if ($lt_i != "" && $lt_i != ".") {
+ if ($lt_i == "..") {
+ lt_count++;
+ } else {
+ if (lt_count == 0) {
+ lt_foo="/" $lt_i lt_foo;
+ } else {
+ lt_count--;
+ }
+ }
+ }
+ }
+ if (lt_foo != "") { lt_freq[[lt_foo]]++; }
+ if (lt_freq[[lt_foo]] == 1) { print lt_foo; }
+}'`
+ # AWK program above erroneously prepends '/' to C:/dos/paths
+ # for these hosts.
+ case $host_os in
+ mingw* | cegcc*) lt_search_path_spec=`$ECHO "$lt_search_path_spec" |\
+ $SED 's,/\([[A-Za-z]]:\),\1,g'` ;;
+ esac
+ sys_lib_search_path_spec=`$ECHO "$lt_search_path_spec" | $lt_NL2SP`
+else
+ sys_lib_search_path_spec="/lib /usr/lib /usr/local/lib"
+fi])
+library_names_spec=
+libname_spec='lib$name'
+soname_spec=
+shrext_cmds=".so"
+postinstall_cmds=
+postuninstall_cmds=
+finish_cmds=
+finish_eval=
+shlibpath_var=
+shlibpath_overrides_runpath=unknown
+version_type=none
+dynamic_linker="$host_os ld.so"
+sys_lib_dlsearch_path_spec="/lib /usr/lib"
+need_lib_prefix=unknown
+hardcode_into_libs=no
+
+# when you set need_version to no, make sure it does not cause -set_version
+# flags to be left without arguments
+need_version=unknown
+
+case $host_os in
+aix3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname.a'
+ shlibpath_var=LIBPATH
+
+ # AIX 3 has no versioning support, so we append a major version to the name.
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+
+aix[[4-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ hardcode_into_libs=yes
+ if test "$host_cpu" = ia64; then
+ # AIX 5 supports IA64
+ library_names_spec='${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext}$versuffix $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ else
+ # With GCC up to 2.95.x, collect2 would create an import file
+ # for dependence libraries. The import file would start with
+ # the line `#! .'. This would cause the generated library to
+ # depend on `.', always an invalid library. This was fixed in
+ # development snapshots of GCC prior to 3.0.
+ case $host_os in
+ aix4 | aix4.[[01]] | aix4.[[01]].*)
+ if { echo '#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 97)'
+ echo ' yes '
+ echo '#endif'; } | ${CC} -E - | $GREP yes > /dev/null; then
+ :
+ else
+ can_build_shared=no
+ fi
+ ;;
+ esac
+ # AIX (on Power*) has no versioning support, so currently we can not hardcode correct
+ # soname into executable. Probably we can add versioning support to
+ # collect2, so additional links can be useful in future.
+ if test "$aix_use_runtimelinking" = yes; then
+ # If using run time linking (on AIX 4.2 or later) use lib<name>.so
+ # instead of lib<name>.a to let people know that these are not
+ # typical AIX shared libraries.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ else
+ # We preserve .a as extension for shared libraries through AIX4.2
+ # and later when we are not doing run time linking.
+ library_names_spec='${libname}${release}.a $libname.a'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ fi
+ shlibpath_var=LIBPATH
+ fi
+ ;;
+
+amigaos*)
+ case $host_cpu in
+ powerpc)
+ # Since July 2007 AmigaOS4 officially supports .so libraries.
+ # When compiling the executable, add -use-dynld -Lsobjs: to the compileline.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ ;;
+ m68k)
+ library_names_spec='$libname.ixlibrary $libname.a'
+ # Create ${libname}_ixlibrary.a entries in /sys/libs.
+ finish_eval='for lib in `ls $libdir/*.ixlibrary 2>/dev/null`; do libname=`func_echo_all "$lib" | $SED '\''s%^.*/\([[^/]]*\)\.ixlibrary$%\1%'\''`; test $RM /sys/libs/${libname}_ixlibrary.a; $show "cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a"; cd /sys/libs && $LN_S $lib ${libname}_ixlibrary.a || exit 1; done'
+ ;;
+ esac
+ ;;
+
+beos*)
+ library_names_spec='${libname}${shared_ext}'
+ dynamic_linker="$host_os ld.so"
+ shlibpath_var=LIBRARY_PATH
+ ;;
+
+bsdi[[45]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/shlib /usr/lib /usr/X11/lib /usr/contrib/lib /lib /usr/local/lib"
+ sys_lib_dlsearch_path_spec="/shlib /usr/lib /usr/local/lib"
+ # the default ld.so.conf also contains /usr/contrib/lib and
+ # /usr/X11R6/lib (/usr/X11 is a link to /usr/X11R6), but let us allow
+ # libtool to hard-code these into programs
+ ;;
+
+cygwin* | mingw* | pw32* | cegcc*)
+ version_type=windows
+ shrext_cmds=".dll"
+ need_version=no
+ need_lib_prefix=no
+
+ case $GCC,$cc_basename in
+ yes,*)
+ # gcc
+ library_names_spec='$libname.dll.a'
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname~
+ chmod a+x \$dldir/$dlname~
+ if test -n '\''$stripme'\'' && test -n '\''$striplib'\''; then
+ eval '\''$striplib \$dldir/$dlname'\'' || exit \$?;
+ fi'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+
+ case $host_os in
+ cygwin*)
+ # Cygwin DLLs use 'cyg' prefix rather than 'lib'
+ soname_spec='`echo ${libname} | sed -e 's/^lib/cyg/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/lib/w32api"])
+ ;;
+ mingw* | cegcc*)
+ # MinGW DLLs use traditional 'lib' prefix
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ pw32*)
+ # pw32 DLLs use 'pw' prefix rather than 'lib'
+ library_names_spec='`echo ${libname} | sed -e 's/^lib/pw/'``echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ ;;
+ esac
+ dynamic_linker='Win32 ld.exe'
+ ;;
+
+ *,cl*)
+ # Native MSVC
+ libname_spec='$name'
+ soname_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext}'
+ library_names_spec='${libname}.dll.lib'
+
+ case $build_os in
+ mingw*)
+ sys_lib_search_path_spec=
+ lt_save_ifs=$IFS
+ IFS=';'
+ for lt_path in $LIB
+ do
+ IFS=$lt_save_ifs
+ # Let DOS variable expansion print the short 8.3 style file name.
+ lt_path=`cd "$lt_path" 2>/dev/null && cmd //C "for %i in (".") do @echo %~si"`
+ sys_lib_search_path_spec="$sys_lib_search_path_spec $lt_path"
+ done
+ IFS=$lt_save_ifs
+ # Convert to MSYS style.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | sed -e 's|\\\\|/|g' -e 's| \\([[a-zA-Z]]\\):| /\\1|g' -e 's|^ ||'`
+ ;;
+ cygwin*)
+ # Convert to unix form, then to dos form, then back to unix form
+ # but this time dos style (no spaces!) so that the unix form looks
+ # like /cygdrive/c/PROGRA~1:/cygdr...
+ sys_lib_search_path_spec=`cygpath --path --unix "$LIB"`
+ sys_lib_search_path_spec=`cygpath --path --dos "$sys_lib_search_path_spec" 2>/dev/null`
+ sys_lib_search_path_spec=`cygpath --path --unix "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ ;;
+ *)
+ sys_lib_search_path_spec="$LIB"
+ if $ECHO "$sys_lib_search_path_spec" | [$GREP ';[c-zC-Z]:/' >/dev/null]; then
+ # It is most probably a Windows format PATH.
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e 's/;/ /g'`
+ else
+ sys_lib_search_path_spec=`$ECHO "$sys_lib_search_path_spec" | $SED -e "s/$PATH_SEPARATOR/ /g"`
+ fi
+ # FIXME: find the short name or the path components, as spaces are
+ # common. (e.g. "Program Files" -> "PROGRA~1")
+ ;;
+ esac
+
+ # DLL is installed to $(libdir)/../bin by postinstall_cmds
+ postinstall_cmds='base_file=`basename \${file}`~
+ dlpath=`$SHELL 2>&1 -c '\''. $dir/'\''\${base_file}'\''i; echo \$dlname'\''`~
+ dldir=$destdir/`dirname \$dlpath`~
+ test -d \$dldir || mkdir -p \$dldir~
+ $install_prog $dir/$dlname \$dldir/$dlname'
+ postuninstall_cmds='dldll=`$SHELL 2>&1 -c '\''. $file; echo \$dlname'\''`~
+ dlpath=$dir/\$dldll~
+ $RM \$dlpath'
+ shlibpath_overrides_runpath=yes
+ dynamic_linker='Win32 link.exe'
+ ;;
+
+ *)
+ # Assume MSVC wrapper
+ library_names_spec='${libname}`echo ${release} | $SED -e 's/[[.]]/-/g'`${versuffix}${shared_ext} $libname.lib'
+ dynamic_linker='Win32 ld.exe'
+ ;;
+ esac
+ # FIXME: first we should search . and the directory the executable is in
+ shlibpath_var=PATH
+ ;;
+
+darwin* | rhapsody*)
+ dynamic_linker="$host_os dyld"
+ version_type=darwin
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${major}$shared_ext ${libname}$shared_ext'
+ soname_spec='${libname}${release}${major}$shared_ext'
+ shlibpath_overrides_runpath=yes
+ shlibpath_var=DYLD_LIBRARY_PATH
+ shrext_cmds='`test .$module = .yes && echo .so || echo .dylib`'
+m4_if([$1], [],[
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /usr/local/lib"])
+ sys_lib_dlsearch_path_spec='/usr/local/lib /lib /usr/lib'
+ ;;
+
+dgux*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname$shared_ext'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+freebsd* | dragonfly*)
+ # DragonFly does not have aout. When/if they implement a new
+ # versioning mechanism, adjust this.
+ if test -x /usr/bin/objformat; then
+ objformat=`/usr/bin/objformat`
+ else
+ case $host_os in
+ freebsd[[23]].*) objformat=aout ;;
+ *) objformat=elf ;;
+ esac
+ fi
+ version_type=freebsd-$objformat
+ case $version_type in
+ freebsd-elf*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ need_version=no
+ need_lib_prefix=no
+ ;;
+ freebsd-*)
+ library_names_spec='${libname}${release}${shared_ext}$versuffix $libname${shared_ext}$versuffix'
+ need_version=yes
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_os in
+ freebsd2.*)
+ shlibpath_overrides_runpath=yes
+ ;;
+ freebsd3.[[01]]* | freebsdelf3.[[01]]*)
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ freebsd3.[[2-9]]* | freebsdelf3.[[2-9]]* | \
+ freebsd4.[[0-5]] | freebsdelf4.[[0-5]] | freebsd4.1.1 | freebsdelf4.1.1)
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+ *) # from 4.6 on, and DragonFly
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+ esac
+ ;;
+
+haiku*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ dynamic_linker="$host_os runtime_loader"
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ sys_lib_dlsearch_path_spec='/boot/home/config/lib /boot/common/lib /boot/system/lib'
+ hardcode_into_libs=yes
+ ;;
+
+hpux9* | hpux10* | hpux11*)
+ # Give a soname corresponding to the major version so that dld.sl refuses to
+ # link against other versions.
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ case $host_cpu in
+ ia64*)
+ shrext_cmds='.so'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.so"
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ if test "X$HPUX_IA64_MODE" = X32; then
+ sys_lib_search_path_spec="/usr/lib/hpux32 /usr/local/lib/hpux32 /usr/local/lib"
+ else
+ sys_lib_search_path_spec="/usr/lib/hpux64 /usr/local/lib/hpux64"
+ fi
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ hppa*64*)
+ shrext_cmds='.sl'
+ hardcode_into_libs=yes
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=LD_LIBRARY_PATH # How should we handle SHLIB_PATH
+ shlibpath_overrides_runpath=yes # Unless +noenvvar is specified.
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ sys_lib_search_path_spec="/usr/lib/pa20_64 /usr/ccs/lib/pa20_64"
+ sys_lib_dlsearch_path_spec=$sys_lib_search_path_spec
+ ;;
+ *)
+ shrext_cmds='.sl'
+ dynamic_linker="$host_os dld.sl"
+ shlibpath_var=SHLIB_PATH
+ shlibpath_overrides_runpath=no # +s is required to enable SHLIB_PATH
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ ;;
+ esac
+ # HP-UX runs *really* slowly unless shared libraries are mode 555, ...
+ postinstall_cmds='chmod 555 $lib'
+ # or fails outright, so override atomically:
+ install_override_mode=555
+ ;;
+
+interix[[3-9]]*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='Interix 3.x ld.so.1 (PE, like ELF)'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $host_os in
+ nonstopux*) version_type=nonstopux ;;
+ *)
+ if test "$lt_cv_prog_gnu_ld" = yes; then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ else
+ version_type=irix
+ fi ;;
+ esac
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${release}${shared_ext} $libname${shared_ext}'
+ case $host_os in
+ irix5* | nonstopux*)
+ libsuff= shlibsuff=
+ ;;
+ *)
+ case $LD in # libtool.m4 will add one of these switches to LD
+ *-32|*"-32 "|*-melf32bsmip|*"-melf32bsmip ")
+ libsuff= shlibsuff= libmagic=32-bit;;
+ *-n32|*"-n32 "|*-melf32bmipn32|*"-melf32bmipn32 ")
+ libsuff=32 shlibsuff=N32 libmagic=N32;;
+ *-64|*"-64 "|*-melf64bmip|*"-melf64bmip ")
+ libsuff=64 shlibsuff=64 libmagic=64-bit;;
+ *) libsuff= shlibsuff= libmagic=never-match;;
+ esac
+ ;;
+ esac
+ shlibpath_var=LD_LIBRARY${shlibsuff}_PATH
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec="/usr/lib${libsuff} /lib${libsuff} /usr/local/lib${libsuff}"
+ sys_lib_dlsearch_path_spec="/usr/lib${libsuff} /lib${libsuff}"
+ hardcode_into_libs=yes
+ ;;
+
+# No shared lib support for Linux oldld, aout, or coff.
+linux*oldld* | linux*aout* | linux*coff*)
+ dynamic_linker=no
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -n $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+
+ # Some binutils ld are patched to set DT_RUNPATH
+ AC_CACHE_VAL([lt_cv_shlibpath_overrides_runpath],
+ [lt_cv_shlibpath_overrides_runpath=no
+ save_LDFLAGS=$LDFLAGS
+ save_libdir=$libdir
+ eval "libdir=/foo; wl=\"$_LT_TAGVAR(lt_prog_compiler_wl, $1)\"; \
+ LDFLAGS=\"\$LDFLAGS $_LT_TAGVAR(hardcode_libdir_flag_spec, $1)\""
+ AC_LINK_IFELSE([AC_LANG_PROGRAM([],[])],
+ [AS_IF([ ($OBJDUMP -p conftest$ac_exeext) 2>/dev/null | grep "RUNPATH.*$libdir" >/dev/null],
+ [lt_cv_shlibpath_overrides_runpath=yes])])
+ LDFLAGS=$save_LDFLAGS
+ libdir=$save_libdir
+ ])
+ shlibpath_overrides_runpath=$lt_cv_shlibpath_overrides_runpath
+
+ # This implies no fast_install, which is unacceptable.
+ # Some rework will be needed to allow for fast_install
+ # before this can be enabled.
+ hardcode_into_libs=yes
+
+ # Append ld.so.conf contents to the search path
+ if test -f /etc/ld.so.conf; then
+ lt_ld_extra=`awk '/^include / { system(sprintf("cd /etc; cat %s 2>/dev/null", \[$]2)); skip = 1; } { if (!skip) print \[$]0; skip = 0; }' < /etc/ld.so.conf | $SED -e 's/#.*//;/^[ ]*hwcap[ ]/d;s/[:, ]/ /g;s/=[^=]*$//;s/=[^= ]* / /g;s/"//g;/^$/d' | tr '\n' ' '`
+ sys_lib_dlsearch_path_spec="/lib /usr/lib $lt_ld_extra"
+ fi
+
+ # We used to test for /lib/ld.so.1 and disable shared libraries on
+ # powerpc, because MkLinux only supported shared libraries with the
+ # GNU dynamic linker. Since this was broken with cross compilers,
+ # most powerpc-linux boxes support dynamic linking these days and
+ # people can always --disable-shared, the test was removed, and we
+ # assume the GNU/Linux dynamic linker is in use.
+ dynamic_linker='GNU/Linux ld.so'
+ ;;
+
+netbsdelf*-gnu)
+ version_type=linux
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='NetBSD ld.elf_so'
+ ;;
+
+netbsd*)
+ version_type=sunos
+ need_lib_prefix=no
+ need_version=no
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ dynamic_linker='NetBSD (a.out) ld.so'
+ else
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major ${libname}${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ dynamic_linker='NetBSD ld.elf_so'
+ fi
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ ;;
+
+newsos6)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ ;;
+
+*nto* | *qnx*)
+ version_type=qnx
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ dynamic_linker='ldqnx.so'
+ ;;
+
+openbsd*)
+ version_type=sunos
+ sys_lib_dlsearch_path_spec="/usr/lib"
+ need_lib_prefix=no
+ # Some older versions of OpenBSD (3.3 at least) *do* need versioned libs.
+ case $host_os in
+ openbsd3.3 | openbsd3.3.*) need_version=yes ;;
+ *) need_version=no ;;
+ esac
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/sbin" ldconfig -m $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ case $host_os in
+ openbsd2.[[89]] | openbsd2.[[89]].*)
+ shlibpath_overrides_runpath=no
+ ;;
+ *)
+ shlibpath_overrides_runpath=yes
+ ;;
+ esac
+ else
+ shlibpath_overrides_runpath=yes
+ fi
+ ;;
+
+os2*)
+ libname_spec='$name'
+ shrext_cmds=".dll"
+ need_lib_prefix=no
+ library_names_spec='$libname${shared_ext} $libname.a'
+ dynamic_linker='OS/2 ld.exe'
+ shlibpath_var=LIBPATH
+ ;;
+
+osf3* | osf4* | osf5*)
+ version_type=osf
+ need_lib_prefix=no
+ need_version=no
+ soname_spec='${libname}${release}${shared_ext}$major'
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ sys_lib_search_path_spec="/usr/shlib /usr/ccs/lib /usr/lib/cmplrs/cc /usr/lib /usr/local/lib /var/shlib"
+ sys_lib_dlsearch_path_spec="$sys_lib_search_path_spec"
+ ;;
+
+rdos*)
+ dynamic_linker=no
+ ;;
+
+solaris*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ # ldd complains unless libraries are executable
+ postinstall_cmds='chmod +x $lib'
+ ;;
+
+sunos4*)
+ version_type=sunos
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${shared_ext}$versuffix'
+ finish_cmds='PATH="\$PATH:/usr/etc" ldconfig $libdir'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ if test "$with_gnu_ld" = yes; then
+ need_lib_prefix=no
+ fi
+ need_version=yes
+ ;;
+
+sysv4 | sysv4.3*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ case $host_vendor in
+ sni)
+ shlibpath_overrides_runpath=no
+ need_lib_prefix=no
+ runpath_var=LD_RUN_PATH
+ ;;
+ siemens)
+ need_lib_prefix=no
+ ;;
+ motorola)
+ need_lib_prefix=no
+ need_version=no
+ shlibpath_overrides_runpath=no
+ sys_lib_search_path_spec='/lib /usr/lib /usr/ccs/lib'
+ ;;
+ esac
+ ;;
+
+sysv4*MP*)
+ if test -d /usr/nec ;then
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='$libname${shared_ext}.$versuffix $libname${shared_ext}.$major $libname${shared_ext}'
+ soname_spec='$libname${shared_ext}.$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ fi
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ version_type=freebsd-elf
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext} $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=yes
+ hardcode_into_libs=yes
+ if test "$with_gnu_ld" = yes; then
+ sys_lib_search_path_spec='/usr/local/lib /usr/gnu/lib /usr/ccs/lib /usr/lib /lib'
+ else
+ sys_lib_search_path_spec='/usr/ccs/lib /usr/lib'
+ case $host_os in
+ sco3.2v5*)
+ sys_lib_search_path_spec="$sys_lib_search_path_spec /lib"
+ ;;
+ esac
+ fi
+ sys_lib_dlsearch_path_spec='/usr/lib'
+ ;;
+
+tpf*)
+ # TPF is a cross-target only. Preferred cross-host = GNU/Linux.
+ version_type=linux # correct to gnu/linux during the next big refactor
+ need_lib_prefix=no
+ need_version=no
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ shlibpath_var=LD_LIBRARY_PATH
+ shlibpath_overrides_runpath=no
+ hardcode_into_libs=yes
+ ;;
+
+uts4*)
+ version_type=linux # correct to gnu/linux during the next big refactor
+ library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}$major $libname${shared_ext}'
+ soname_spec='${libname}${release}${shared_ext}$major'
+ shlibpath_var=LD_LIBRARY_PATH
+ ;;
+
+*)
+ dynamic_linker=no
+ ;;
+esac
+AC_MSG_RESULT([$dynamic_linker])
+test "$dynamic_linker" = no && can_build_shared=no
+
+variables_saved_for_relink="PATH $shlibpath_var $runpath_var"
+if test "$GCC" = yes; then
+ variables_saved_for_relink="$variables_saved_for_relink GCC_EXEC_PREFIX COMPILER_PATH LIBRARY_PATH"
+fi
+
+if test "${lt_cv_sys_lib_search_path_spec+set}" = set; then
+ sys_lib_search_path_spec="$lt_cv_sys_lib_search_path_spec"
+fi
+if test "${lt_cv_sys_lib_dlsearch_path_spec+set}" = set; then
+ sys_lib_dlsearch_path_spec="$lt_cv_sys_lib_dlsearch_path_spec"
+fi
+
+_LT_DECL([], [variables_saved_for_relink], [1],
+ [Variables whose values should be saved in libtool wrapper scripts and
+ restored at link time])
+_LT_DECL([], [need_lib_prefix], [0],
+ [Do we need the "lib" prefix for modules?])
+_LT_DECL([], [need_version], [0], [Do we need a version for libraries?])
+_LT_DECL([], [version_type], [0], [Library versioning type])
+_LT_DECL([], [runpath_var], [0], [Shared library runtime path variable])
+_LT_DECL([], [shlibpath_var], [0],[Shared library path variable])
+_LT_DECL([], [shlibpath_overrides_runpath], [0],
+ [Is shlibpath searched before the hard-coded library search path?])
+_LT_DECL([], [libname_spec], [1], [Format of library name prefix])
+_LT_DECL([], [library_names_spec], [1],
+ [[List of archive names. First name is the real one, the rest are links.
+ The last name is the one that the linker finds with -lNAME]])
+_LT_DECL([], [soname_spec], [1],
+ [[The coded name of the library, if different from the real name]])
+_LT_DECL([], [install_override_mode], [1],
+ [Permission mode override for installation of shared libraries])
+_LT_DECL([], [postinstall_cmds], [2],
+ [Command to use after installation of a shared archive])
+_LT_DECL([], [postuninstall_cmds], [2],
+ [Command to use after uninstallation of a shared archive])
+_LT_DECL([], [finish_cmds], [2],
+ [Commands used to finish a libtool library installation in a directory])
+_LT_DECL([], [finish_eval], [1],
+ [[As "finish_cmds", except a single script fragment to be evaled but
+ not shown]])
+_LT_DECL([], [hardcode_into_libs], [0],
+ [Whether we should hardcode library paths into libraries])
+_LT_DECL([], [sys_lib_search_path_spec], [2],
+ [Compile-time system search path for libraries])
+_LT_DECL([], [sys_lib_dlsearch_path_spec], [2],
+ [Run-time system search path for libraries])
+])# _LT_SYS_DYNAMIC_LINKER
+
+
+# _LT_PATH_TOOL_PREFIX(TOOL)
+# --------------------------
+# find a file program which can recognize shared library
+AC_DEFUN([_LT_PATH_TOOL_PREFIX],
+[m4_require([_LT_DECL_EGREP])dnl
+AC_MSG_CHECKING([for $1])
+AC_CACHE_VAL(lt_cv_path_MAGIC_CMD,
+[case $MAGIC_CMD in
+[[\\/*] | ?:[\\/]*])
+ lt_cv_path_MAGIC_CMD="$MAGIC_CMD" # Let the user override the test with a path.
+ ;;
+*)
+ lt_save_MAGIC_CMD="$MAGIC_CMD"
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+dnl $ac_dummy forces splitting on constant user-supplied paths.
+dnl POSIX.2 word splitting is done only on the output of word expansions,
+dnl not every word. This closes a longstanding sh security hole.
+ ac_dummy="m4_if([$2], , $PATH, [$2])"
+ for ac_dir in $ac_dummy; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f $ac_dir/$1; then
+ lt_cv_path_MAGIC_CMD="$ac_dir/$1"
+ if test -n "$file_magic_test_file"; then
+ case $deplibs_check_method in
+ "file_magic "*)
+ file_magic_regex=`expr "$deplibs_check_method" : "file_magic \(.*\)"`
+ MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+ if eval $file_magic_cmd \$file_magic_test_file 2> /dev/null |
+ $EGREP "$file_magic_regex" > /dev/null; then
+ :
+ else
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the command libtool uses to detect shared libraries,
+*** $file_magic_cmd, produces output that libtool cannot recognize.
+*** The result is that libtool may fail to recognize shared libraries
+*** as such. This will affect the creation of libtool libraries that
+*** depend on shared libraries, but programs linked with such libtool
+*** libraries will work regardless of this problem. Nevertheless, you
+*** may want to report the problem to your system manager and/or to
+*** bug-libtool@gnu.org
+
+_LT_EOF
+ fi ;;
+ esac
+ fi
+ break
+ fi
+ done
+ IFS="$lt_save_ifs"
+ MAGIC_CMD="$lt_save_MAGIC_CMD"
+ ;;
+esac])
+MAGIC_CMD="$lt_cv_path_MAGIC_CMD"
+if test -n "$MAGIC_CMD"; then
+ AC_MSG_RESULT($MAGIC_CMD)
+else
+ AC_MSG_RESULT(no)
+fi
+_LT_DECL([], [MAGIC_CMD], [0],
+ [Used to examine libraries when file_magic_cmd begins with "file"])dnl
+])# _LT_PATH_TOOL_PREFIX
+
+# Old name:
+AU_ALIAS([AC_PATH_TOOL_PREFIX], [_LT_PATH_TOOL_PREFIX])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_PATH_TOOL_PREFIX], [])
+
+
+# _LT_PATH_MAGIC
+# --------------
+# find a file program which can recognize a shared library
+m4_defun([_LT_PATH_MAGIC],
+[_LT_PATH_TOOL_PREFIX(${ac_tool_prefix}file, /usr/bin$PATH_SEPARATOR$PATH)
+if test -z "$lt_cv_path_MAGIC_CMD"; then
+ if test -n "$ac_tool_prefix"; then
+ _LT_PATH_TOOL_PREFIX(file, /usr/bin$PATH_SEPARATOR$PATH)
+ else
+ MAGIC_CMD=:
+ fi
+fi
+])# _LT_PATH_MAGIC
+
+
+# LT_PATH_LD
+# ----------
+# find the pathname to the GNU or non-GNU linker
+AC_DEFUN([LT_PATH_LD],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PROG_ECHO_BACKSLASH])dnl
+
+AC_ARG_WITH([gnu-ld],
+ [AS_HELP_STRING([--with-gnu-ld],
+ [assume the C compiler uses GNU ld @<:@default=no@:>@])],
+ [test "$withval" = no || with_gnu_ld=yes],
+ [with_gnu_ld=no])dnl
+
+ac_prog=ld
+if test "$GCC" = yes; then
+ # Check if gcc -print-prog-name=ld gives a path.
+ AC_MSG_CHECKING([for ld used by $CC])
+ case $host in
+ *-*-mingw*)
+ # gcc leaves a trailing carriage return which upsets mingw
+ ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+ *)
+ ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+ esac
+ case $ac_prog in
+ # Accept absolute paths.
+ [[\\/]]* | ?:[[\\/]]*)
+ re_direlt='/[[^/]][[^/]]*/\.\./'
+ # Canonicalize the pathname of ld
+ ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+ while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+ ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+ done
+ test -z "$LD" && LD="$ac_prog"
+ ;;
+ "")
+ # If it fails, then pretend we aren't using GCC.
+ ac_prog=ld
+ ;;
+ *)
+ # If it is relative, then search for the first ld in PATH.
+ with_gnu_ld=unknown
+ ;;
+ esac
+elif test "$with_gnu_ld" = yes; then
+ AC_MSG_CHECKING([for GNU ld])
+else
+ AC_MSG_CHECKING([for non-GNU ld])
+fi
+AC_CACHE_VAL(lt_cv_path_LD,
+[if test -z "$LD"; then
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+ lt_cv_path_LD="$ac_dir/$ac_prog"
+ # Check to see if the program is GNU ld. I'd rather use --version,
+ # but apparently some variants of GNU ld only accept -v.
+ # Break only if it was the GNU/non-GNU ld that we prefer.
+ case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+ *GNU* | *'with BFD'*)
+ test "$with_gnu_ld" != no && break
+ ;;
+ *)
+ test "$with_gnu_ld" != yes && break
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+else
+ lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi])
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+ AC_MSG_RESULT($LD)
+else
+ AC_MSG_RESULT(no)
+fi
+test -z "$LD" && AC_MSG_ERROR([no acceptable ld found in \$PATH])
+_LT_PATH_LD_GNU
+AC_SUBST([LD])
+
+_LT_TAGDECL([], [LD], [1], [The linker used to build libraries])
+])# LT_PATH_LD
+
+# Old names:
+AU_ALIAS([AM_PROG_LD], [LT_PATH_LD])
+AU_ALIAS([AC_PROG_LD], [LT_PATH_LD])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_LD], [])
+dnl AC_DEFUN([AC_PROG_LD], [])
+
+
+# _LT_PATH_LD_GNU
+#- --------------
+m4_defun([_LT_PATH_LD_GNU],
+[AC_CACHE_CHECK([if the linker ($LD) is GNU ld], lt_cv_prog_gnu_ld,
+[# I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+ lt_cv_prog_gnu_ld=yes
+ ;;
+*)
+ lt_cv_prog_gnu_ld=no
+ ;;
+esac])
+with_gnu_ld=$lt_cv_prog_gnu_ld
+])# _LT_PATH_LD_GNU
+
+
+# _LT_CMD_RELOAD
+# --------------
+# find reload flag for linker
+# -- PORTME Some linkers may need a different reload flag.
+m4_defun([_LT_CMD_RELOAD],
+[AC_CACHE_CHECK([for $LD option to reload object files],
+ lt_cv_ld_reload_flag,
+ [lt_cv_ld_reload_flag='-r'])
+reload_flag=$lt_cv_ld_reload_flag
+case $reload_flag in
+"" | " "*) ;;
+*) reload_flag=" $reload_flag" ;;
+esac
+reload_cmds='$LD$reload_flag -o $output$reload_objs'
+case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ if test "$GCC" != yes; then
+ reload_cmds=false
+ fi
+ ;;
+ darwin*)
+ if test "$GCC" = yes; then
+ reload_cmds='$LTCC $LTCFLAGS -nostdlib ${wl}-r -o $output$reload_objs'
+ else
+ reload_cmds='$LD$reload_flag -o $output$reload_objs'
+ fi
+ ;;
+esac
+_LT_TAGDECL([], [reload_flag], [1], [How to create reloadable object files])dnl
+_LT_TAGDECL([], [reload_cmds], [2])dnl
+])# _LT_CMD_RELOAD
+
+
+# _LT_CHECK_MAGIC_METHOD
+# ----------------------
+# how to check for library dependencies
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_MAGIC_METHOD],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+AC_CACHE_CHECK([how to recognize dependent libraries],
+lt_cv_deplibs_check_method,
+[lt_cv_file_magic_cmd='$MAGIC_CMD'
+lt_cv_file_magic_test_file=
+lt_cv_deplibs_check_method='unknown'
+# Need to set the preceding variable on all platforms that support
+# interlibrary dependencies.
+# 'none' -- dependencies not supported.
+# `unknown' -- same as none, but documents that we really don't know.
+# 'pass_all' -- all dependencies passed with no checks.
+# 'test_compile' -- check by making test program.
+# 'file_magic [[regex]]' -- check by looking for files in library path
+# which responds to the $file_magic_cmd with a given extended regex.
+# If you have `file' or equivalent on your system and you're not sure
+# whether `pass_all' will *always* work, you probably want this one.
+
+case $host_os in
+aix[[4-9]]*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+beos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+bsdi[[45]]*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib)'
+ lt_cv_file_magic_cmd='/usr/bin/file -L'
+ lt_cv_file_magic_test_file=/shlib/libc.so
+ ;;
+
+cygwin*)
+ # func_win32_libid is a shell function defined in ltmain.sh
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ ;;
+
+mingw* | pw32*)
+ # Base MSYS/MinGW do not provide the 'file' command needed by
+ # func_win32_libid shell function, so use a weaker test based on 'objdump',
+ # unless we find 'file', for example because we are cross-compiling.
+ # func_win32_libid assumes BSD nm, so disallow it if using MS dumpbin.
+ if ( test "$lt_cv_nm_interface" = "BSD nm" && file / ) >/dev/null 2>&1; then
+ lt_cv_deplibs_check_method='file_magic ^x86 archive import|^x86 DLL'
+ lt_cv_file_magic_cmd='func_win32_libid'
+ else
+ # Keep this pattern in sync with the one in func_win32_libid.
+ lt_cv_deplibs_check_method='file_magic file format (pei*-i386(.*architecture: i386)?|pe-arm-wince|pe-x86-64)'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ fi
+ ;;
+
+cegcc*)
+ # use the weaker test based on 'objdump'. See mingw*.
+ lt_cv_deplibs_check_method='file_magic file format pe-arm-.*little(.*architecture: arm)?'
+ lt_cv_file_magic_cmd='$OBJDUMP -f'
+ ;;
+
+darwin* | rhapsody*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+freebsd* | dragonfly*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ case $host_cpu in
+ i*86 )
+ # Not sure whether the presence of OpenBSD here was a mistake.
+ # Let's accept both of them until this is cleared up.
+ lt_cv_deplibs_check_method='file_magic (FreeBSD|OpenBSD|DragonFly)/i[[3-9]]86 (compact )?demand paged shared library'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so.*`
+ ;;
+ esac
+ else
+ lt_cv_deplibs_check_method=pass_all
+ fi
+ ;;
+
+haiku*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+hpux10.20* | hpux11*)
+ lt_cv_file_magic_cmd=/usr/bin/file
+ case $host_cpu in
+ ia64*)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|ELF-[[0-9]][[0-9]]) shared object file - IA64'
+ lt_cv_file_magic_test_file=/usr/lib/hpux32/libc.so
+ ;;
+ hppa*64*)
+ [lt_cv_deplibs_check_method='file_magic (s[0-9][0-9][0-9]|ELF[ -][0-9][0-9])(-bit)?( [LM]SB)? shared object( file)?[, -]* PA-RISC [0-9]\.[0-9]']
+ lt_cv_file_magic_test_file=/usr/lib/pa20_64/libc.sl
+ ;;
+ *)
+ lt_cv_deplibs_check_method='file_magic (s[[0-9]][[0-9]][[0-9]]|PA-RISC[[0-9]]\.[[0-9]]) shared library'
+ lt_cv_file_magic_test_file=/usr/lib/libc.sl
+ ;;
+ esac
+ ;;
+
+interix[[3-9]]*)
+ # PIC code is broken on Interix 3.x, that's why |\.a not |_pic\.a here
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|\.a)$'
+ ;;
+
+irix5* | irix6* | nonstopux*)
+ case $LD in
+ *-32|*"-32 ") libmagic=32-bit;;
+ *-n32|*"-n32 ") libmagic=N32;;
+ *-64|*"-64 ") libmagic=64-bit;;
+ *) libmagic=never-match;;
+ esac
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+# This must be glibc/ELF.
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ > /dev/null; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so|_pic\.a)$'
+ fi
+ ;;
+
+newos6*)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (executable|dynamic lib)'
+ lt_cv_file_magic_cmd=/usr/bin/file
+ lt_cv_file_magic_test_file=/usr/lib/libnls.so
+ ;;
+
+*nto* | *qnx*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+openbsd*)
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|\.so|_pic\.a)$'
+ else
+ lt_cv_deplibs_check_method='match_pattern /lib[[^/]]+(\.so\.[[0-9]]+\.[[0-9]]+|_pic\.a)$'
+ fi
+ ;;
+
+osf3* | osf4* | osf5*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+rdos*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+solaris*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX* | sysv4*uw2*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+
+sysv4 | sysv4.3*)
+ case $host_vendor in
+ motorola)
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[ML]]SB (shared object|dynamic lib) M[[0-9]][[0-9]]* Version [[0-9]]'
+ lt_cv_file_magic_test_file=`echo /usr/lib/libc.so*`
+ ;;
+ ncr)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ sequent)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method='file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB (shared object|dynamic lib )'
+ ;;
+ sni)
+ lt_cv_file_magic_cmd='/bin/file'
+ lt_cv_deplibs_check_method="file_magic ELF [[0-9]][[0-9]]*-bit [[LM]]SB dynamic lib"
+ lt_cv_file_magic_test_file=/lib/libc.so
+ ;;
+ siemens)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ pc)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+ esac
+ ;;
+
+tpf*)
+ lt_cv_deplibs_check_method=pass_all
+ ;;
+esac
+])
+
+file_magic_glob=
+want_nocaseglob=no
+if test "$build" = "$host"; then
+ case $host_os in
+ mingw* | pw32*)
+ if ( shopt | grep nocaseglob ) >/dev/null 2>&1; then
+ want_nocaseglob=yes
+ else
+ file_magic_glob=`echo aAbBcCdDeEfFgGhHiIjJkKlLmMnNoOpPqQrRsStTuUvVwWxXyYzZ | $SED -e "s/\(..\)/s\/[[\1]]\/[[\1]]\/g;/g"`
+ fi
+ ;;
+ esac
+fi
+
+file_magic_cmd=$lt_cv_file_magic_cmd
+deplibs_check_method=$lt_cv_deplibs_check_method
+test -z "$deplibs_check_method" && deplibs_check_method=unknown
+
+_LT_DECL([], [deplibs_check_method], [1],
+ [Method to check whether dependent libraries are shared objects])
+_LT_DECL([], [file_magic_cmd], [1],
+ [Command to use when deplibs_check_method = "file_magic"])
+_LT_DECL([], [file_magic_glob], [1],
+ [How to find potential files when deplibs_check_method = "file_magic"])
+_LT_DECL([], [want_nocaseglob], [1],
+ [Find potential files using nocaseglob when deplibs_check_method = "file_magic"])
+])# _LT_CHECK_MAGIC_METHOD
+
+
+# LT_PATH_NM
+# ----------
+# find the pathname to a BSD- or MS-compatible name lister
+AC_DEFUN([LT_PATH_NM],
+[AC_REQUIRE([AC_PROG_CC])dnl
+AC_CACHE_CHECK([for BSD- or MS-compatible name lister (nm)], lt_cv_path_NM,
+[if test -n "$NM"; then
+ # Let the user override the test.
+ lt_cv_path_NM="$NM"
+else
+ lt_nm_to_check="${ac_tool_prefix}nm"
+ if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+ lt_nm_to_check="$lt_nm_to_check nm"
+ fi
+ for lt_tmp_nm in $lt_nm_to_check; do
+ lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+ for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+ IFS="$lt_save_ifs"
+ test -z "$ac_dir" && ac_dir=.
+ tmp_nm="$ac_dir/$lt_tmp_nm"
+ if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+ # Check to see if the nm accepts a BSD-compat flag.
+ # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+ # nm: unknown option "B" ignored
+ # Tru64's nm complains that /dev/null is an invalid object file
+ case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+ */dev/null* | *'Invalid file or object type'*)
+ lt_cv_path_NM="$tmp_nm -B"
+ break
+ ;;
+ *)
+ case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+ */dev/null*)
+ lt_cv_path_NM="$tmp_nm -p"
+ break
+ ;;
+ *)
+ lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+ continue # so that we can try to find one that supports BSD flags
+ ;;
+ esac
+ ;;
+ esac
+ fi
+ done
+ IFS="$lt_save_ifs"
+ done
+ : ${lt_cv_path_NM=no}
+fi])
+if test "$lt_cv_path_NM" != "no"; then
+ NM="$lt_cv_path_NM"
+else
+ # Didn't find any BSD compatible name lister, look for dumpbin.
+ if test -n "$DUMPBIN"; then :
+ # Let the user override the test.
+ else
+ AC_CHECK_TOOLS(DUMPBIN, [dumpbin "link -dump"], :)
+ case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+ *COFF*)
+ DUMPBIN="$DUMPBIN -symbols"
+ ;;
+ *)
+ DUMPBIN=:
+ ;;
+ esac
+ fi
+ AC_SUBST([DUMPBIN])
+ if test "$DUMPBIN" != ":"; then
+ NM="$DUMPBIN"
+ fi
+fi
+test -z "$NM" && NM=nm
+AC_SUBST([NM])
+_LT_DECL([], [NM], [1], [A BSD- or MS-compatible name lister])dnl
+
+AC_CACHE_CHECK([the name lister ($NM) interface], [lt_cv_nm_interface],
+ [lt_cv_nm_interface="BSD nm"
+ echo "int some_variable = 0;" > conftest.$ac_ext
+ (eval echo "\"\$as_me:$LINENO: $ac_compile\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$ac_compile" 2>conftest.err)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: $NM \\\"conftest.$ac_objext\\\"\"" >&AS_MESSAGE_LOG_FD)
+ (eval "$NM \"conftest.$ac_objext\"" 2>conftest.err > conftest.out)
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ (eval echo "\"\$as_me:$LINENO: output\"" >&AS_MESSAGE_LOG_FD)
+ cat conftest.out >&AS_MESSAGE_LOG_FD
+ if $GREP 'External.*some_variable' conftest.out > /dev/null; then
+ lt_cv_nm_interface="MS dumpbin"
+ fi
+ rm -f conftest*])
+])# LT_PATH_NM
+
+# Old names:
+AU_ALIAS([AM_PROG_NM], [LT_PATH_NM])
+AU_ALIAS([AC_PROG_NM], [LT_PATH_NM])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_PROG_NM], [])
+dnl AC_DEFUN([AC_PROG_NM], [])
+
+# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+# --------------------------------
+# how to determine the name of the shared library
+# associated with a specific link library.
+# -- PORTME fill in with the dynamic library characteristics
+m4_defun([_LT_CHECK_SHAREDLIB_FROM_LINKLIB],
+[m4_require([_LT_DECL_EGREP])
+m4_require([_LT_DECL_OBJDUMP])
+m4_require([_LT_DECL_DLLTOOL])
+AC_CACHE_CHECK([how to associate runtime and link libraries],
+lt_cv_sharedlib_from_linklib_cmd,
+[lt_cv_sharedlib_from_linklib_cmd='unknown'
+
+case $host_os in
+cygwin* | mingw* | pw32* | cegcc*)
+ # two different shell functions defined in ltmain.sh
+ # decide which to use based on capabilities of $DLLTOOL
+ case `$DLLTOOL --help 2>&1` in
+ *--identify-strict*)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib
+ ;;
+ *)
+ lt_cv_sharedlib_from_linklib_cmd=func_cygming_dll_for_implib_fallback
+ ;;
+ esac
+ ;;
+*)
+ # fallback: assume linklib IS sharedlib
+ lt_cv_sharedlib_from_linklib_cmd="$ECHO"
+ ;;
+esac
+])
+sharedlib_from_linklib_cmd=$lt_cv_sharedlib_from_linklib_cmd
+test -z "$sharedlib_from_linklib_cmd" && sharedlib_from_linklib_cmd=$ECHO
+
+_LT_DECL([], [sharedlib_from_linklib_cmd], [1],
+ [Command to associate shared and link libraries])
+])# _LT_CHECK_SHAREDLIB_FROM_LINKLIB
+
+
+# _LT_PATH_MANIFEST_TOOL
+# ----------------------
+# locate the manifest tool
+m4_defun([_LT_PATH_MANIFEST_TOOL],
+[AC_CHECK_TOOL(MANIFEST_TOOL, mt, :)
+test -z "$MANIFEST_TOOL" && MANIFEST_TOOL=mt
+AC_CACHE_CHECK([if $MANIFEST_TOOL is a manifest tool], [lt_cv_path_mainfest_tool],
+ [lt_cv_path_mainfest_tool=no
+ echo "$as_me:$LINENO: $MANIFEST_TOOL '-?'" >&AS_MESSAGE_LOG_FD
+ $MANIFEST_TOOL '-?' 2>conftest.err > conftest.out
+ cat conftest.err >&AS_MESSAGE_LOG_FD
+ if $GREP 'Manifest Tool' conftest.out > /dev/null; then
+ lt_cv_path_mainfest_tool=yes
+ fi
+ rm -f conftest*])
+if test "x$lt_cv_path_mainfest_tool" != xyes; then
+ MANIFEST_TOOL=:
+fi
+_LT_DECL([], [MANIFEST_TOOL], [1], [Manifest tool])dnl
+])# _LT_PATH_MANIFEST_TOOL
+
+
+# LT_LIB_M
+# --------
+# check for math library
+AC_DEFUN([LT_LIB_M],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+LIBM=
+case $host in
+*-*-beos* | *-*-cegcc* | *-*-cygwin* | *-*-haiku* | *-*-pw32* | *-*-darwin*)
+ # These system don't have libm, or don't need it
+ ;;
+*-ncr-sysv4.3*)
+ AC_CHECK_LIB(mw, _mwvalidcheckl, LIBM="-lmw")
+ AC_CHECK_LIB(m, cos, LIBM="$LIBM -lm")
+ ;;
+*)
+ AC_CHECK_LIB(m, cos, LIBM="-lm")
+ ;;
+esac
+AC_SUBST([LIBM])
+])# LT_LIB_M
+
+# Old name:
+AU_ALIAS([AC_CHECK_LIBM], [LT_LIB_M])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_CHECK_LIBM], [])
+
+
+# _LT_COMPILER_NO_RTTI([TAGNAME])
+# -------------------------------
+m4_defun([_LT_COMPILER_NO_RTTI],
+[m4_require([_LT_TAG_COMPILER])dnl
+
+_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+
+if test "$GCC" = yes; then
+ case $cc_basename in
+ nvcc*)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -Xcompiler -fno-builtin' ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin' ;;
+ esac
+
+ _LT_COMPILER_OPTION([if $compiler supports -fno-rtti -fno-exceptions],
+ lt_cv_prog_compiler_rtti_exceptions,
+ [-fno-rtti -fno-exceptions], [],
+ [_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)="$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1) -fno-rtti -fno-exceptions"])
+fi
+_LT_TAGDECL([no_builtin_flag], [lt_prog_compiler_no_builtin_flag], [1],
+ [Compiler flag to turn off builtin functions])
+])# _LT_COMPILER_NO_RTTI
+
+
+# _LT_CMD_GLOBAL_SYMBOLS
+# ----------------------
+m4_defun([_LT_CMD_GLOBAL_SYMBOLS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_PROG_CC])dnl
+AC_REQUIRE([AC_PROG_AWK])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+AC_REQUIRE([LT_PATH_LD])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+
+# Check for command to grab the raw symbol name followed by C symbol from nm.
+AC_MSG_CHECKING([command to parse $NM output from $compiler object])
+AC_CACHE_VAL([lt_cv_sys_global_symbol_pipe],
+[
+# These are sane defaults that work on at least a few old systems.
+# [They come from Ultrix. What could be older than Ultrix?!! ;)]
+
+# Character class describing NM global symbol codes.
+symcode='[[BCDEGRST]]'
+
+# Regexp to match symbols that can be accessed directly from C.
+sympat='\([[_A-Za-z]][[_A-Za-z0-9]]*\)'
+
+# Define system-specific variables.
+case $host_os in
+aix*)
+ symcode='[[BCDT]]'
+ ;;
+cygwin* | mingw* | pw32* | cegcc*)
+ symcode='[[ABCDGISTW]]'
+ ;;
+hpux*)
+ if test "$host_cpu" = ia64; then
+ symcode='[[ABCDEGRST]]'
+ fi
+ ;;
+irix* | nonstopux*)
+ symcode='[[BCDEGRST]]'
+ ;;
+osf*)
+ symcode='[[BCDEGQRST]]'
+ ;;
+solaris*)
+ symcode='[[BDRT]]'
+ ;;
+sco3.2v5*)
+ symcode='[[DT]]'
+ ;;
+sysv4.2uw2*)
+ symcode='[[DT]]'
+ ;;
+sysv5* | sco5v6* | unixware* | OpenUNIX*)
+ symcode='[[ABDT]]'
+ ;;
+sysv4)
+ symcode='[[DFNSTU]]'
+ ;;
+esac
+
+# If we're using GNU nm, then use its standard symbol codes.
+case `$NM -V 2>&1` in
+*GNU* | *'with BFD'*)
+ symcode='[[ABCDGIRSTW]]' ;;
+esac
+
+# Transform an extracted symbol line into a proper C declaration.
+# Some systems (esp. on ia64) link data and code symbols differently,
+# so use this general approach.
+lt_cv_sys_global_symbol_to_cdecl="sed -n -e 's/^T .* \(.*\)$/extern int \1();/p' -e 's/^$symcode* .* \(.*\)$/extern char \1;/p'"
+
+# Transform an extracted symbol line into symbol name and symbol address
+lt_cv_sys_global_symbol_to_c_name_address="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p'"
+lt_cv_sys_global_symbol_to_c_name_address_lib_prefix="sed -n -e 's/^: \([[^ ]]*\)[[ ]]*$/ {\\\"\1\\\", (void *) 0},/p' -e 's/^$symcode* \([[^ ]]*\) \(lib[[^ ]]*\)$/ {\"\2\", (void *) \&\2},/p' -e 's/^$symcode* \([[^ ]]*\) \([[^ ]]*\)$/ {\"lib\2\", (void *) \&\2},/p'"
+
+# Handle CRLF in mingw tool chain
+opt_cr=
+case $build_os in
+mingw*)
+ opt_cr=`$ECHO 'x\{0,1\}' | tr x '\015'` # option cr in regexp
+ ;;
+esac
+
+# Try without a prefix underscore, then with it.
+for ac_symprfx in "" "_"; do
+
+ # Transform symcode, sympat, and symprfx into a raw symbol and a C symbol.
+ symxfrm="\\1 $ac_symprfx\\2 \\2"
+
+ # Write the raw and C identifiers.
+ if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ # Fake it for dumpbin and say T for any non-static function
+ # and D for any global variable.
+ # Also find C++ and __fastcall symbols from MSVC++,
+ # which start with @ or ?.
+ lt_cv_sys_global_symbol_pipe="$AWK ['"\
+" {last_section=section; section=\$ 3};"\
+" /^COFF SYMBOL TABLE/{for(i in hide) delete hide[i]};"\
+" /Section length .*#relocs.*(pick any)/{hide[last_section]=1};"\
+" \$ 0!~/External *\|/{next};"\
+" / 0+ UNDEF /{next}; / UNDEF \([^|]\)*()/{next};"\
+" {if(hide[section]) next};"\
+" {f=0}; \$ 0~/\(\).*\|/{f=1}; {printf f ? \"T \" : \"D \"};"\
+" {split(\$ 0, a, /\||\r/); split(a[2], s)};"\
+" s[1]~/^[@?]/{print s[1], s[1]; next};"\
+" s[1]~prfx {split(s[1],t,\"@\"); print t[1], substr(t[1],length(prfx))}"\
+" ' prfx=^$ac_symprfx]"
+ else
+ lt_cv_sys_global_symbol_pipe="sed -n -e 's/^.*[[ ]]\($symcode$symcode*\)[[ ]][[ ]]*$ac_symprfx$sympat$opt_cr$/$symxfrm/p'"
+ fi
+ lt_cv_sys_global_symbol_pipe="$lt_cv_sys_global_symbol_pipe | sed '/ __gnu_lto/d'"
+
+ # Check to see that the pipe works correctly.
+ pipe_works=no
+
+ rm -f conftest*
+ cat > conftest.$ac_ext <<_LT_EOF
+#ifdef __cplusplus
+extern "C" {
+#endif
+char nm_test_var;
+void nm_test_func(void);
+void nm_test_func(void){}
+#ifdef __cplusplus
+}
+#endif
+int main(){nm_test_var='a';nm_test_func();return(0);}
+_LT_EOF
+
+ if AC_TRY_EVAL(ac_compile); then
+ # Now try to grab the symbols.
+ nlist=conftest.nm
+ if AC_TRY_EVAL(NM conftest.$ac_objext \| "$lt_cv_sys_global_symbol_pipe" \> $nlist) && test -s "$nlist"; then
+ # Try sorting and uniquifying the output.
+ if sort "$nlist" | uniq > "$nlist"T; then
+ mv -f "$nlist"T "$nlist"
+ else
+ rm -f "$nlist"T
+ fi
+
+ # Make sure that we snagged all the symbols we need.
+ if $GREP ' nm_test_var$' "$nlist" >/dev/null; then
+ if $GREP ' nm_test_func$' "$nlist" >/dev/null; then
+ cat <<_LT_EOF > conftest.$ac_ext
+/* Keep this code in sync between libtool.m4, ltmain, lt_system.h, and tests. */
+#if defined(_WIN32) || defined(__CYGWIN__) || defined(_WIN32_WCE)
+/* DATA imports from DLLs on WIN32 con't be const, because runtime
+ relocations are performed -- see ld's documentation on pseudo-relocs. */
+# define LT@&t@_DLSYM_CONST
+#elif defined(__osf__)
+/* This system does not cope well with relocations in const data. */
+# define LT@&t@_DLSYM_CONST
+#else
+# define LT@&t@_DLSYM_CONST const
+#endif
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+_LT_EOF
+ # Now generate the symbol file.
+ eval "$lt_cv_sys_global_symbol_to_cdecl"' < "$nlist" | $GREP -v main >> conftest.$ac_ext'
+
+ cat <<_LT_EOF >> conftest.$ac_ext
+
+/* The mapping between symbol names and symbols. */
+LT@&t@_DLSYM_CONST struct {
+ const char *name;
+ void *address;
+}
+lt__PROGRAM__LTX_preloaded_symbols[[]] =
+{
+ { "@PROGRAM@", (void *) 0 },
+_LT_EOF
+ $SED "s/^$symcode$symcode* \(.*\) \(.*\)$/ {\"\2\", (void *) \&\2},/" < "$nlist" | $GREP -v main >> conftest.$ac_ext
+ cat <<\_LT_EOF >> conftest.$ac_ext
+ {0, (void *) 0}
+};
+
+/* This works around a problem in FreeBSD linker */
+#ifdef FREEBSD_WORKAROUND
+static const void *lt_preloaded_setup() {
+ return lt__PROGRAM__LTX_preloaded_symbols;
+}
+#endif
+
+#ifdef __cplusplus
+}
+#endif
+_LT_EOF
+ # Now try linking the two files.
+ mv conftest.$ac_objext conftstm.$ac_objext
+ lt_globsym_save_LIBS=$LIBS
+ lt_globsym_save_CFLAGS=$CFLAGS
+ LIBS="conftstm.$ac_objext"
+ CFLAGS="$CFLAGS$_LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)"
+ if AC_TRY_EVAL(ac_link) && test -s conftest${ac_exeext}; then
+ pipe_works=yes
+ fi
+ LIBS=$lt_globsym_save_LIBS
+ CFLAGS=$lt_globsym_save_CFLAGS
+ else
+ echo "cannot find nm_test_func in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot find nm_test_var in $nlist" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "cannot run $lt_cv_sys_global_symbol_pipe" >&AS_MESSAGE_LOG_FD
+ fi
+ else
+ echo "$progname: failed program was:" >&AS_MESSAGE_LOG_FD
+ cat conftest.$ac_ext >&5
+ fi
+ rm -rf conftest* conftst*
+
+ # Do not use the global_symbol_pipe unless it works.
+ if test "$pipe_works" = yes; then
+ break
+ else
+ lt_cv_sys_global_symbol_pipe=
+ fi
+done
+])
+if test -z "$lt_cv_sys_global_symbol_pipe"; then
+ lt_cv_sys_global_symbol_to_cdecl=
+fi
+if test -z "$lt_cv_sys_global_symbol_pipe$lt_cv_sys_global_symbol_to_cdecl"; then
+ AC_MSG_RESULT(failed)
+else
+ AC_MSG_RESULT(ok)
+fi
+
+# Response file support.
+if test "$lt_cv_nm_interface" = "MS dumpbin"; then
+ nm_file_list_spec='@'
+elif $NM --help 2>/dev/null | grep '[[@]]FILE' >/dev/null; then
+ nm_file_list_spec='@'
+fi
+
+_LT_DECL([global_symbol_pipe], [lt_cv_sys_global_symbol_pipe], [1],
+ [Take the output of nm and produce a listing of raw symbols and C names])
+_LT_DECL([global_symbol_to_cdecl], [lt_cv_sys_global_symbol_to_cdecl], [1],
+ [Transform the output of nm in a proper C declaration])
+_LT_DECL([global_symbol_to_c_name_address],
+ [lt_cv_sys_global_symbol_to_c_name_address], [1],
+ [Transform the output of nm in a C name address pair])
+_LT_DECL([global_symbol_to_c_name_address_lib_prefix],
+ [lt_cv_sys_global_symbol_to_c_name_address_lib_prefix], [1],
+ [Transform the output of nm in a C name address pair when lib prefix is needed])
+_LT_DECL([], [nm_file_list_spec], [1],
+ [Specify filename containing input files for $NM])
+]) # _LT_CMD_GLOBAL_SYMBOLS
+
+
+# _LT_COMPILER_PIC([TAGNAME])
+# ---------------------------
+m4_defun([_LT_COMPILER_PIC],
+[m4_require([_LT_TAG_COMPILER])dnl
+_LT_TAGVAR(lt_prog_compiler_wl, $1)=
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+_LT_TAGVAR(lt_prog_compiler_static, $1)=
+
+m4_if([$1], [CXX], [
+ # C++ specific cases for pic, static, wl, etc.
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+ *djgpp*)
+ # DJGPP does not support shared libraries at all
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ else
+ case $host_os in
+ aix[[4-9]]*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+ chorus*)
+ case $cc_basename in
+ cxch68*)
+ # Green Hills C++ Compiler
+ # _LT_TAGVAR(lt_prog_compiler_static, $1)="--no_auto_instantiation -u __main -u __premain -u _abort -r $COOL_DIR/lib/libOrb.a $MVME_DIR/lib/CC/libC.a $MVME_DIR/lib/classix/libcx.s.a"
+ ;;
+ esac
+ ;;
+ mingw* | cygwin* | os2* | pw32* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ freebsd* | dragonfly*)
+ # FreeBSD uses GNU C++
+ ;;
+ hpux9* | hpux10* | hpux11*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ fi
+ ;;
+ aCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ interix*)
+ # This is c89, which is MS Visual C++ (no shared libs)
+ # Anyone wants to do a port?
+ ;;
+ irix5* | irix6* | nonstopux*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ # CC pic flag -KPIC is the default.
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # KAI C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ ecpc* )
+ # old Intel C++ for x86_64 which still supported -KPIC.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ icpc* )
+ # Intel C++, used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ cxx*)
+ # Compaq C++
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xlc* | xlC* | bgxl[[cC]]* | mpixl[[cC]]*)
+ # IBM XL 8.0, 9.0 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+ lynxos*)
+ ;;
+ m88k*)
+ ;;
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-W c,exportall'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ netbsd* | netbsdelf*-gnu)
+ ;;
+ *qnx* | *nto*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='--backend -Wl,'
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ cxx*)
+ # Digital/Compaq C++
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # Make sure the PIC flag is empty. It appears that all Alpha
+ # Linux and Compaq Tru64 Unix objects are PIC.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ psos*)
+ ;;
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ lcc*)
+ # Lucid
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ ;;
+ *)
+ ;;
+ esac
+ ;;
+ vxworks*)
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+],
+[
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+
+ case $host_os in
+ aix*)
+ # All AIX code is PIC.
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ m68k)
+ # FIXME: we need at least 68020 code to build shared libraries, but
+ # adding the `-m68020' flag to GCC prevents building anything better,
+ # like `-m68040'.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-m68020 -resident32 -malways-restore-a4'
+ ;;
+ esac
+ ;;
+
+ beos* | irix5* | irix6* | nonstopux* | osf3* | osf4* | osf5*)
+ # PIC is the default for these OSes.
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ # Although the cygwin gcc ignores -fPIC, still need this for old-style
+ # (--disable-auto-import) libraries
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ darwin* | rhapsody*)
+ # PIC is the default on this platform
+ # Common symbols not allowed in MH_DYLIB files
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fno-common'
+ ;;
+
+ haiku*)
+ # PIC is the default for Haiku.
+ # The "-static" flag exists, but is broken.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)=
+ ;;
+
+ hpux*)
+ # PIC is the default for 64-bit PA HP-UX, but not for 32-bit
+ # PA HP-UX. On IA64 HP-UX, PIC is the default but the pic flag
+ # sets the default TLS model and affects inlining.
+ case $host_cpu in
+ hppa*64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ # Interix 3.x gcc -fpic/-fPIC options generate broken code.
+ # Instead, we relocate shared libraries at runtime.
+ ;;
+
+ msdosdjgpp*)
+ # Just because we use GCC doesn't mean we suddenly get shared libraries
+ # on systems that don't support them.
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ enable_shared=no
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=-Kconform_pic
+ fi
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ ;;
+ esac
+
+ case $cc_basename in
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Xlinker '
+ if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="-Xcompiler $_LT_TAGVAR(lt_prog_compiler_pic, $1)"
+ fi
+ ;;
+ esac
+ else
+ # PORTME Check for flag to pass linker flags through the system compiler.
+ case $host_os in
+ aix*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ if test "$host_cpu" = ia64; then
+ # AIX 5 now supports IA64 processor
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ else
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-bnso -bI:/lib/syscalls.exp'
+ fi
+ ;;
+
+ mingw* | cygwin* | pw32* | os2* | cegcc*)
+ # This hack is so that the source file can tell whether it is being
+ # built for inclusion in a dll (and should export symbols for example).
+ m4_if([$1], [GCJ], [],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)='-DDLL_EXPORT'])
+ ;;
+
+ hpux9* | hpux10* | hpux11*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC is the default for IA64 HP-UX and 64-bit HP-UX, but
+ # not for PA HP-UX.
+ case $host_cpu in
+ hppa*64*|ia64*)
+ # +Z the default
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='+Z'
+ ;;
+ esac
+ # Is there a better lt_prog_compiler_static that works with the bundled CC?
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='${wl}-a ${wl}archive'
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # PIC (with -KPIC) is the default.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ # old Intel for x86_64 which still supported -KPIC.
+ ecc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # icc used to be incompatible with GCC.
+ # ICC 10 doesn't accept -KPIC any more.
+ icc* | ifort*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ # Lahey Fortran 8.1.
+ lf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='--shared'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='--static'
+ ;;
+ nagfor*)
+ # NAG Fortran compiler
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,-Wl,,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ pgcc* | pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group compilers (*not* the Pentium gcc compiler,
+ # which looks to be a dead project)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ ccc*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All Alpha code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+ xl* | bgxl* | bgf* | mpixl*)
+ # IBM XL C 8.0/Fortran 10.1, 11.1 on PPC and BlueGene
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-qpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-qstaticlink'
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ Ceres\ Fortran* | *Sun*Fortran*\ [[1-7]].* | *Sun*Fortran*\ 8.[[0-3]]*)
+ # Sun Fortran 8.3 passes all unrecognized flags to the linker
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)=''
+ ;;
+ *Sun\ F* | *Sun*Fortran*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ ;;
+ *Sun\ C*)
+ # Sun C 5.9
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ ;;
+ *Intel*\ [[CF]]*Compiler*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-static'
+ ;;
+ *Portland\ Group*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fpic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *nto* | *qnx*)
+ # QNX uses GNU C++, but need to define -shared option too, otherwise
+ # it will coredump.
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-fPIC -shared'
+ ;;
+
+ osf3* | osf4* | osf5*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ # All OSF/1 code is PIC.
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ rdos*)
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ case $cc_basename in
+ f77* | f90* | f95* | sunf77* | sunf90* | sunf95*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld ';;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,';;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Qoption ld '
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-PIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4 | sysv4.2uw2* | sysv4.3*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec ;then
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-Kconform_pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ fi
+ ;;
+
+ sysv5* | unixware* | sco3.2v5* | sco5v6* | OpenUNIX*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-KPIC'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ unicos*)
+ _LT_TAGVAR(lt_prog_compiler_wl, $1)='-Wl,'
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)='-pic'
+ _LT_TAGVAR(lt_prog_compiler_static, $1)='-Bstatic'
+ ;;
+
+ *)
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no
+ ;;
+ esac
+ fi
+])
+case $host_os in
+ # For platforms which do not support PIC, -DPIC is meaningless:
+ *djgpp*)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ ;;
+ *)
+ _LT_TAGVAR(lt_prog_compiler_pic, $1)="$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])"
+ ;;
+esac
+
+AC_CACHE_CHECK([for $compiler option to produce PIC],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_prog_compiler_pic, $1)])
+_LT_TAGVAR(lt_prog_compiler_pic, $1)=$_LT_TAGVAR(lt_cv_prog_compiler_pic, $1)
+
+#
+# Check to make sure the PIC flag actually works.
+#
+if test -n "$_LT_TAGVAR(lt_prog_compiler_pic, $1)"; then
+ _LT_COMPILER_OPTION([if $compiler PIC flag $_LT_TAGVAR(lt_prog_compiler_pic, $1) works],
+ [_LT_TAGVAR(lt_cv_prog_compiler_pic_works, $1)],
+ [$_LT_TAGVAR(lt_prog_compiler_pic, $1)@&t@m4_if([$1],[],[ -DPIC],[m4_if([$1],[CXX],[ -DPIC],[])])], [],
+ [case $_LT_TAGVAR(lt_prog_compiler_pic, $1) in
+ "" | " "*) ;;
+ *) _LT_TAGVAR(lt_prog_compiler_pic, $1)=" $_LT_TAGVAR(lt_prog_compiler_pic, $1)" ;;
+ esac],
+ [_LT_TAGVAR(lt_prog_compiler_pic, $1)=
+ _LT_TAGVAR(lt_prog_compiler_can_build_shared, $1)=no])
+fi
+_LT_TAGDECL([pic_flag], [lt_prog_compiler_pic], [1],
+ [Additional compiler flags for building library objects])
+
+_LT_TAGDECL([wl], [lt_prog_compiler_wl], [1],
+ [How to pass a linker flag through the compiler])
+#
+# Check to make sure the static flag actually works.
+#
+wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1) eval lt_tmp_static_flag=\"$_LT_TAGVAR(lt_prog_compiler_static, $1)\"
+_LT_LINKER_OPTION([if $compiler static flag $lt_tmp_static_flag works],
+ _LT_TAGVAR(lt_cv_prog_compiler_static_works, $1),
+ $lt_tmp_static_flag,
+ [],
+ [_LT_TAGVAR(lt_prog_compiler_static, $1)=])
+_LT_TAGDECL([link_static_flag], [lt_prog_compiler_static], [1],
+ [Compiler flag to prevent dynamic linking])
+])# _LT_COMPILER_PIC
+
+
+# _LT_LINKER_SHLIBS([TAGNAME])
+# ----------------------------
+# See if the linker supports building shared libraries.
+m4_defun([_LT_LINKER_SHLIBS],
+[AC_REQUIRE([LT_PATH_LD])dnl
+AC_REQUIRE([LT_PATH_NM])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_DECL_SED])dnl
+m4_require([_LT_CMD_GLOBAL_SYMBOLS])dnl
+m4_require([_LT_TAG_COMPILER])dnl
+AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+m4_if([$1], [CXX], [
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ case $host_os in
+ aix[[4-9]]*)
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global defined
+ # symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ ;;
+ pw32*)
+ _LT_TAGVAR(export_symbols_cmds, $1)="$ltdll_cmds"
+ ;;
+ cygwin* | mingw* | cegcc*)
+ case $cc_basename in
+ cl*)
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+ ;;
+ esac
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ ;;
+ esac
+], [
+ runpath_var=
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(archive_cmds, $1)=
+ _LT_TAGVAR(archive_expsym_cmds, $1)=
+ _LT_TAGVAR(compiler_needs_object, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED '\''s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(hardcode_automatic, $1)=no
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ _LT_TAGVAR(hardcode_minus_L, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+ _LT_TAGVAR(inherit_rpath, $1)=no
+ _LT_TAGVAR(link_all_deplibs, $1)=unknown
+ _LT_TAGVAR(module_cmds, $1)=
+ _LT_TAGVAR(module_expsym_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)=
+ _LT_TAGVAR(old_archive_from_expsyms_cmds, $1)=
+ _LT_TAGVAR(thread_safe_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ # include_expsyms should be a list of space-separated symbols to be *always*
+ # included in the symbol list
+ _LT_TAGVAR(include_expsyms, $1)=
+ # exclude_expsyms can be an extended regexp of symbols to exclude
+ # it will be wrapped by ` (' and `)$', so one must not match beginning or
+ # end of line. Example: `a|bc|.*d.*' will exclude the symbols `a' and `bc',
+ # as well as any symbol that contains `d'.
+ _LT_TAGVAR(exclude_expsyms, $1)=['_GLOBAL_OFFSET_TABLE_|_GLOBAL__F[ID]_.*']
+ # Although _GLOBAL_OFFSET_TABLE_ is a valid symbol C name, most a.out
+ # platforms (ab)use it in PIC code, but their linkers get confused if
+ # the symbol is explicitly referenced. Since portable code cannot
+ # rely on this symbol name, it's probably fine to never include it in
+ # preloaded symbol tables.
+ # Exclude shared library initialization/finalization symbols.
+dnl Note also adjust exclude_expsyms for C++ above.
+ extract_expsyms_cmds=
+
+ case $host_os in
+ cygwin* | mingw* | pw32* | cegcc*)
+ # FIXME: the MSVC++ port hasn't been tested in a loooong time
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ if test "$GCC" != yes; then
+ with_gnu_ld=no
+ fi
+ ;;
+ interix*)
+ # we just hope/assume this is gcc and not c89 (= MSVC++)
+ with_gnu_ld=yes
+ ;;
+ openbsd*)
+ with_gnu_ld=no
+ ;;
+ linux* | k*bsd*-gnu | gnu*)
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ ;;
+ esac
+
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+
+ # On some targets, GNU ld is compatible enough with the native linker
+ # that we're better off using the native interface for both.
+ lt_use_gnu_ld_interface=no
+ if test "$with_gnu_ld" = yes; then
+ case $host_os in
+ aix*)
+ # The AIX port of GNU ld has always aspired to compatibility
+ # with the native linker. However, as the warning in the GNU ld
+ # block says, versions before 2.19.5* couldn't really create working
+ # shared libraries, regardless of the interface used.
+ case `$LD -v 2>&1` in
+ *\ \(GNU\ Binutils\)\ 2.19.5*) ;;
+ *\ \(GNU\ Binutils\)\ 2.[[2-9]]*) ;;
+ *\ \(GNU\ Binutils\)\ [[3-9]]*) ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ ;;
+ *)
+ lt_use_gnu_ld_interface=yes
+ ;;
+ esac
+ fi
+
+ if test "$lt_use_gnu_ld_interface" = yes; then
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ wlarc='${wl}'
+
+ # Set some defaults for GNU ld with shared library support. These
+ # are reset later if shared libraries are not supported. Putting them
+ # here allows them to be overridden if necessary.
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if $LD --help 2>&1 | $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ supports_anon_versioning=no
+ case `$LD -v 2>&1` in
+ *GNU\ gold*) supports_anon_versioning=yes ;;
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.10.*) ;; # catch versions < 2.11
+ *\ 2.11.93.0.2\ *) supports_anon_versioning=yes ;; # RH7.3 ...
+ *\ 2.11.92.0.12\ *) supports_anon_versioning=yes ;; # Mandrake 8.2 ...
+ *\ 2.11.*) ;; # other 2.11 versions
+ *) supports_anon_versioning=yes ;;
+ esac
+
+ # See if GNU ld supports shared libraries.
+ case $host_os in
+ aix[[3-9]]*)
+ # On AIX/PPC, the GNU linker is very broken
+ if test "$host_cpu" != ia64; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: the GNU linker, at least up to release 2.19, is reported
+*** to be unable to reliably create shared libraries on AIX.
+*** Therefore, libtool is disabling shared libraries support. If you
+*** really care for shared libraries, you may want to install binutils
+*** 2.20 or above, or modify your PATH so that a non-GNU linker is found.
+*** You will then need to restart the configuration process.
+
+_LT_EOF
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1 DATA/;s/^.*[[ ]]__nm__\([[^ ]]*\)[[ ]][[^ ]]*/\1 DATA/;/^I[[ ]]/d;/^[[AITW]][[ ]]/s/.* //'\'' | sort | uniq > $export_symbols'
+ _LT_TAGVAR(exclude_expsyms, $1)=['[_]+GLOBAL_OFFSET_TABLE_|[_]+GLOBAL__[FID]_.*|[_]+head_[A-Za-z0-9_]+_dll|[A-Za-z0-9_]+_dll_iname']
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared $output_objdir/$soname.def $libobjs $deplibs $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+
+ gnu* | linux* | tpf* | k*bsd*-gnu | kopensolaris*-gnu)
+ tmp_diet=no
+ if test "$host_os" = linux-dietlibc; then
+ case $cc_basename in
+ diet\ *) tmp_diet=yes;; # linux-dietlibc with static linking (!diet-dyn)
+ esac
+ fi
+ if $LD --help 2>&1 | $EGREP ': supported targets:.* elf' > /dev/null \
+ && test "$tmp_diet" = no
+ then
+ tmp_addflag=' $pic_flag'
+ tmp_sharedflag='-shared'
+ case $cc_basename,$host_cpu in
+ pgcc*) # Portland Group C compiler
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag'
+ ;;
+ pgf77* | pgf90* | pgf95* | pgfortran*)
+ # Portland Group f77 and f90 compilers
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ tmp_addflag=' $pic_flag -Mnomain' ;;
+ ecc*,ia64* | icc*,ia64*) # Intel C compiler on ia64
+ tmp_addflag=' -i_dynamic' ;;
+ efc*,ia64* | ifort*,ia64*) # Intel Fortran compiler on ia64
+ tmp_addflag=' -i_dynamic -nofor_main' ;;
+ ifc* | ifort*) # Intel Fortran compiler
+ tmp_addflag=' -nofor_main' ;;
+ lf95*) # Lahey Fortran 8.1
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ tmp_sharedflag='--shared' ;;
+ xl[[cC]]* | bgxl[[cC]]* | mpixl[[cC]]*) # IBM XL C 8.0 on PPC (deal with xlf below)
+ tmp_sharedflag='-qmkshrobj'
+ tmp_addflag= ;;
+ nvcc*) # Cuda Compiler Driver 2.2
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ ;;
+ esac
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*) # Sun C 5.9
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+ tmp_sharedflag='-G' ;;
+ *Sun\ F*) # Sun Fortran 8.3
+ tmp_sharedflag='-G' ;;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC '"$tmp_sharedflag""$tmp_addflag"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+
+ case $cc_basename in
+ xlf* | bgf* | bgxlf* | mpixlf*)
+ # IBM XL Fortran 10.1 on PPC cannot create shared libs itself
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='--whole-archive$convenience --no-whole-archive'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared $libobjs $deplibs $linker_flags -soname $soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $LD -shared $libobjs $deplibs $linker_flags -soname $soname -version-script $output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ esac
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable $libobjs $deplibs $linker_flags -o $lib'
+ wlarc=
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ fi
+ ;;
+
+ solaris*)
+ if $LD -v 2>&1 | $GREP 'BFD 2\.8' > /dev/null; then
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: The releases 2.8.* of the GNU linker cannot reliably
+*** create shared libraries on Solaris systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.9.1 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ elif $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6* | unixware* | OpenUNIX*)
+ case `$LD -v 2>&1` in
+ *\ [[01]].* | *\ 2.[[0-9]].* | *\ 2.1[[0-5]].*)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ cat <<_LT_EOF 1>&2
+
+*** Warning: Releases of the GNU linker prior to 2.16.91.0.3 can not
+*** reliably create shared libraries on SCO systems. Therefore, libtool
+*** is disabling shared libraries support. We urge you to upgrade GNU
+*** binutils to release 2.16.91.0.3 or newer. Another option is to modify
+*** your PATH or compiler configuration so that the native linker is
+*** used, and then restart.
+
+_LT_EOF
+ ;;
+ *)
+ # For security reasons, it is highly recommended that you always
+ # use absolute paths for naming shared libraries, and exclude the
+ # DT_RUNPATH tag from executables and libraries. But doing so
+ # requires that you compile everything twice, which is a pain.
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ sunos4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+
+ if test "$_LT_TAGVAR(ld_shlibs, $1)" = no; then
+ runpath_var=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ # PORTME fill in a description of your system's linker (not GNU ld)
+ case $host_os in
+ aix3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$LD -o $output_objdir/$soname $libobjs $deplibs $linker_flags -bE:$export_symbols -T512 -H512 -bM:SRE~$AR $AR_FLAGS $lib $output_objdir/$soname'
+ # Note: this linker hardcodes the directories in LIBPATH if there
+ # are no directories specified by -L.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ if test "$GCC" = yes && test -z "$lt_prog_compiler_static"; then
+ # Neither direct hardcoding nor static linking is supported with a
+ # broken collect2.
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ # If we're using GNU nm, then we don't want the "-C" option.
+ # -C means demangle to AIX nm, but means don't demangle with GNU nm
+ # Also, AIX nm treats weak defined symbols like other global
+ # defined symbols, whereas GNU nm marks them as "W".
+ if $NM -V 2>&1 | $GREP 'GNU' > /dev/null; then
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -Bpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B") || (\$ 2 == "W")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ else
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM -BCpg $libobjs $convenience | awk '\''{ if (((\$ 2 == "T") || (\$ 2 == "D") || (\$ 2 == "B")) && ([substr](\$ 3,1,1) != ".")) { print \$ 3 } }'\'' | sort -u > $export_symbols'
+ fi
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ if (test $ld_flag = "-brtl" || test $ld_flag = "-Wl,-brtl"); then
+ aix_use_runtimelinking=yes
+ break
+ fi
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GCC" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ ;;
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=no
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ amigaos*)
+ case $host_cpu in
+ powerpc)
+ # see comment about AmigaOS4 .so support
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)=''
+ ;;
+ m68k)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/a2ixlibrary.data~$ECHO "#define NAME $libname" > $output_objdir/a2ixlibrary.data~$ECHO "#define LIBRARY_ID 1" >> $output_objdir/a2ixlibrary.data~$ECHO "#define VERSION $major" >> $output_objdir/a2ixlibrary.data~$ECHO "#define REVISION $revision" >> $output_objdir/a2ixlibrary.data~$AR $AR_FLAGS $lib $libobjs~$RANLIB $lib~(cd $output_objdir && a2ixlibrary -32)'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ ;;
+
+ bsdi[[45]]*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)=-rdynamic
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ # When not using gcc, we currently assume that we are using
+ # Microsoft Visual C++.
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ case $cc_basename in
+ cl*)
+ # Native MSVC
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ sed -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ sed -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ _LT_TAGVAR(exclude_expsyms, $1)='_NULL_IMPORT_DESCRIPTOR|_IMPORT_DESCRIPTOR_.*'
+ _LT_TAGVAR(export_symbols_cmds, $1)='$NM $libobjs $convenience | $global_symbol_pipe | $SED -e '\''/^[[BCDGRS]][[ ]]/s/.*[[ ]]\([[^ ]]*\)/\1,DATA/'\'' | $SED -e '\''/^[[AITW]][[ ]]/s/.*[[ ]]//'\'' | sort | uniq > $export_symbols'
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # Assume MSVC wrapper
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $lib $libobjs $compiler_flags `func_echo_all "$deplibs" | $SED '\''s/ -lc$//'\''` -link -dll~linknames='
+ # The linker will automatically build a .lib file if we build a DLL.
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ # FIXME: Should let the user specify the lib program.
+ _LT_TAGVAR(old_archive_cmds, $1)='lib -OUT:$oldlib$oldobjs$old_deplibs'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ ;;
+ esac
+ ;;
+
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 2.2.[012] allows us to include c++rt0.o to get C++ constructor
+ # support. Future versions do this automatically, but an explicit c++rt0.o
+ # does not break anything, and helps significantly (at the cost of a little
+ # extra space).
+ freebsd2.2*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags /usr/lib/c++rt0.o'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # Unfortunately, older versions of FreeBSD 2 do not have this feature.
+ freebsd2.*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ # FreeBSD 3 and greater uses gcc -shared to do shared libraries.
+ freebsd* | dragonfly*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ hpux9*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $libobjs $deplibs $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$LD -b +b $install_libdir -o $output_objdir/$soname $libobjs $deplibs $linker_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+
+ hpux10*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ fi
+ ;;
+
+ hpux11*)
+ if test "$GCC" = yes && test "$with_gnu_ld" = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ else
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ m4_if($1, [], [
+ # Older versions of the 11.00 compiler do not understand -b yet
+ # (HP92453-01 A.11.01.20 doesn't, HP92453-01 B.11.X.35175-35176.GP does)
+ _LT_LINKER_OPTION([if $CC understands -b],
+ _LT_TAGVAR(lt_cv_prog_compiler__b, $1), [-b],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'],
+ [_LT_TAGVAR(archive_cmds, $1)='$LD -b +h $soname +b $install_libdir -o $lib $libobjs $deplibs $linker_flags'])],
+ [_LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $libobjs $deplibs $compiler_flags'])
+ ;;
+ esac
+ fi
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+
+ # hardcode_minus_L: Not really in the search PATH,
+ # but as the default location of the library.
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ ;;
+ esac
+ fi
+ ;;
+
+ irix5* | irix6* | nonstopux*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ # Try to use the -exported_symbol ld option, if it does not
+ # work, assume that -exports_file does not work either and
+ # implicitly export all symbols.
+ # This should be the same for all languages, so no per-tag cache variable.
+ AC_CACHE_CHECK([whether the $host_os linker accepts -exported_symbol],
+ [lt_cv_irix_exported_symbol],
+ [save_LDFLAGS="$LDFLAGS"
+ LDFLAGS="$LDFLAGS -shared ${wl}-exported_symbol ${wl}foo ${wl}-update_registry ${wl}/dev/null"
+ AC_LINK_IFELSE(
+ [AC_LANG_SOURCE(
+ [AC_LANG_CASE([C], [[int foo (void) { return 0; }]],
+ [C++], [[int foo (void) { return 0; }]],
+ [Fortran 77], [[
+ subroutine foo
+ end]],
+ [Fortran], [[
+ subroutine foo
+ end]])])],
+ [lt_cv_irix_exported_symbol=yes],
+ [lt_cv_irix_exported_symbol=no])
+ LDFLAGS="$save_LDFLAGS"])
+ if test "$lt_cv_irix_exported_symbol" = yes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations ${wl}-exports_file ${wl}$export_symbols -o $lib'
+ fi
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -exports_file $export_symbols -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ netbsd* | netbsdelf*-gnu)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags' # a.out
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -shared -o $lib $libobjs $deplibs $linker_flags' # ELF
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ newsos6)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *nto* | *qnx*)
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ if test -z "`echo __ELF__ | $CC -E - | $GREP __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags ${wl}-retain-symbols-file,$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ else
+ case $host_os in
+ openbsd[[01]].* | openbsd2.[[0-7]] | openbsd2.[[0-7]].*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ ;;
+ esac
+ fi
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ os2*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(archive_cmds, $1)='$ECHO "LIBRARY $libname INITINSTANCE" > $output_objdir/$libname.def~$ECHO "DESCRIPTION \"$libname\"" >> $output_objdir/$libname.def~echo DATA >> $output_objdir/$libname.def~echo " SINGLE NONSHARED" >> $output_objdir/$libname.def~echo EXPORTS >> $output_objdir/$libname.def~emxexp $libobjs >> $output_objdir/$libname.def~$CC -Zdll -Zcrtdll -o $lib $libobjs $deplibs $compiler_flags $output_objdir/$libname.def'
+ _LT_TAGVAR(old_archive_from_new_cmds, $1)='emximp -o $output_objdir/$libname.a $output_objdir/$libname.def'
+ ;;
+
+ osf3*)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ osf4* | osf5*) # as osf3* with the addition of -msym flag
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $pic_flag $libobjs $deplibs $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ else
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $libobjs $deplibs $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done; printf "%s\\n" "-hidden">> $lib.exp~
+ $CC -shared${allow_undefined_flag} ${wl}-input ${wl}$lib.exp $compiler_flags $libobjs $deplibs -soname $soname `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~$RM $lib.exp'
+
+ # Both c and cxx compiler support -rpath directly
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)='no'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ ;;
+
+ solaris*)
+ _LT_TAGVAR(no_undefined_flag, $1)=' -z defs'
+ if test "$GCC" = yes; then
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag ${wl}-z ${wl}text ${wl}-M ${wl}$lib.exp ${wl}-h ${wl}$soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ else
+ case `$CC -V 2>&1` in
+ *"Compilers 5.0"*)
+ wlarc=''
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $LD -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $linker_flags~$RM $lib.exp'
+ ;;
+ *)
+ wlarc='${wl}'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} -M $lib.exp -h $soname -o $lib $libobjs $deplibs $compiler_flags~$RM $lib.exp'
+ ;;
+ esac
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'. GCC discards it without `$wl',
+ # but is careful enough not to reorder.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ fi
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ sunos4*)
+ if test "x$host_vendor" = xsequent; then
+ # Use $CC to link under sequent, because it throws in some extra .o
+ # files that make .init and .fini sections work.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h $soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$LD -assert pure-text -Bstatic -o $lib $libobjs $deplibs $linker_flags'
+ fi
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4)
+ case $host_vendor in
+ sni)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=yes # is this really true???
+ ;;
+ siemens)
+ ## LD is ld it makes a PLAMLIB
+ ## CC just makes a GrossModule.
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(reload_cmds, $1)='$CC -r -o $output$reload_objs'
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ ;;
+ motorola)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_direct, $1)=no #Motorola manual says yes, but my tests say they lie
+ ;;
+ esac
+ runpath_var='LD_RUN_PATH'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ sysv4.3*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='-Bexport'
+ ;;
+
+ sysv4*MP*)
+ if test -d /usr/nec; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var=LD_RUN_PATH
+ hardcode_runpath_var=yes
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ fi
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ if test "$GCC" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ fi
+ ;;
+
+ uts4*)
+ _LT_TAGVAR(archive_cmds, $1)='$LD -G -h $soname -o $lib $libobjs $deplibs $linker_flags'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+
+ *)
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ if test x$host_vendor = xsni; then
+ case $host in
+ sysv4 | sysv4.2uw2* | sysv4.3* | sysv5*)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Blargedynsym'
+ ;;
+ esac
+ fi
+ fi
+])
+AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+_LT_TAGVAR(with_gnu_ld, $1)=$with_gnu_ld
+
+_LT_DECL([], [libext], [0], [Old archive suffix (normally "a")])dnl
+_LT_DECL([], [shrext_cmds], [1], [Shared library suffix (normally ".so")])dnl
+_LT_DECL([], [extract_expsyms_cmds], [2],
+ [The commands to extract the exported symbol list from a shared archive])
+
+#
+# Do we need to explicitly link libc?
+#
+case "x$_LT_TAGVAR(archive_cmds_need_lc, $1)" in
+x|xyes)
+ # Assume -lc should be added
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+
+ if test "$enable_shared" = yes && test "$GCC" = yes; then
+ case $_LT_TAGVAR(archive_cmds, $1) in
+ *'~'*)
+ # FIXME: we may have to deal with multi-command sequences.
+ ;;
+ '$CC '*)
+ # Test whether the compiler implicitly links with -lc since on some
+ # systems, -lgcc has to come before -lc. If gcc already passes -lc
+ # to ld, don't add -lc before -lgcc.
+ AC_CACHE_CHECK([whether -lc should be explicitly linked in],
+ [lt_cv_]_LT_TAGVAR(archive_cmds_need_lc, $1),
+ [$RM conftest*
+ echo "$lt_simple_compile_test_code" > conftest.$ac_ext
+
+ if AC_TRY_EVAL(ac_compile) 2>conftest.err; then
+ soname=conftest
+ lib=conftest
+ libobjs=conftest.$ac_objext
+ deplibs=
+ wl=$_LT_TAGVAR(lt_prog_compiler_wl, $1)
+ pic_flag=$_LT_TAGVAR(lt_prog_compiler_pic, $1)
+ compiler_flags=-v
+ linker_flags=-v
+ verstring=
+ output_objdir=.
+ libname=conftest
+ lt_save_allow_undefined_flag=$_LT_TAGVAR(allow_undefined_flag, $1)
+ _LT_TAGVAR(allow_undefined_flag, $1)=
+ if AC_TRY_EVAL(_LT_TAGVAR(archive_cmds, $1) 2\>\&1 \| $GREP \" -lc \" \>/dev/null 2\>\&1)
+ then
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ else
+ lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ fi
+ _LT_TAGVAR(allow_undefined_flag, $1)=$lt_save_allow_undefined_flag
+ else
+ cat conftest.err 1>&5
+ fi
+ $RM conftest*
+ ])
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=$lt_cv_[]_LT_TAGVAR(archive_cmds_need_lc, $1)
+ ;;
+ esac
+ fi
+ ;;
+esac
+
+_LT_TAGDECL([build_libtool_need_lc], [archive_cmds_need_lc], [0],
+ [Whether or not to add -lc for building shared libraries])
+_LT_TAGDECL([allow_libtool_libs_with_static_runtimes],
+ [enable_shared_with_static_runtimes], [0],
+ [Whether or not to disallow shared libs when runtime libs are static])
+_LT_TAGDECL([], [export_dynamic_flag_spec], [1],
+ [Compiler flag to allow reflexive dlopens])
+_LT_TAGDECL([], [whole_archive_flag_spec], [1],
+ [Compiler flag to generate shared objects directly from archives])
+_LT_TAGDECL([], [compiler_needs_object], [1],
+ [Whether the compiler copes with passing no objects directly])
+_LT_TAGDECL([], [old_archive_from_new_cmds], [2],
+ [Create an old-style archive from a shared archive])
+_LT_TAGDECL([], [old_archive_from_expsyms_cmds], [2],
+ [Create a temporary old-style archive to link instead of a shared archive])
+_LT_TAGDECL([], [archive_cmds], [2], [Commands used to build a shared archive])
+_LT_TAGDECL([], [archive_expsym_cmds], [2])
+_LT_TAGDECL([], [module_cmds], [2],
+ [Commands used to build a loadable module if different from building
+ a shared archive.])
+_LT_TAGDECL([], [module_expsym_cmds], [2])
+_LT_TAGDECL([], [with_gnu_ld], [1],
+ [Whether we are building with GNU ld or not])
+_LT_TAGDECL([], [allow_undefined_flag], [1],
+ [Flag that allows shared libraries with undefined symbols to be built])
+_LT_TAGDECL([], [no_undefined_flag], [1],
+ [Flag that enforces no undefined symbols])
+_LT_TAGDECL([], [hardcode_libdir_flag_spec], [1],
+ [Flag to hardcode $libdir into a binary during linking.
+ This must work even if $libdir does not exist])
+_LT_TAGDECL([], [hardcode_libdir_separator], [1],
+ [Whether we need a single "-rpath" flag with a separated argument])
+_LT_TAGDECL([], [hardcode_direct], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary])
+_LT_TAGDECL([], [hardcode_direct_absolute], [0],
+ [Set to "yes" if using DIR/libNAME${shared_ext} during linking hardcodes
+ DIR into the resulting binary and the resulting library dependency is
+ "absolute", i.e impossible to change by setting ${shlibpath_var} if the
+ library is relocated])
+_LT_TAGDECL([], [hardcode_minus_L], [0],
+ [Set to "yes" if using the -LDIR flag during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_shlibpath_var], [0],
+ [Set to "yes" if using SHLIBPATH_VAR=DIR during linking hardcodes DIR
+ into the resulting binary])
+_LT_TAGDECL([], [hardcode_automatic], [0],
+ [Set to "yes" if building a shared library automatically hardcodes DIR
+ into the library and all subsequent libraries and executables linked
+ against it])
+_LT_TAGDECL([], [inherit_rpath], [0],
+ [Set to yes if linker adds runtime paths of dependent libraries
+ to runtime path list])
+_LT_TAGDECL([], [link_all_deplibs], [0],
+ [Whether libtool must link a program against all its dependency libraries])
+_LT_TAGDECL([], [always_export_symbols], [0],
+ [Set to "yes" if exported symbols are required])
+_LT_TAGDECL([], [export_symbols_cmds], [2],
+ [The commands to list exported symbols])
+_LT_TAGDECL([], [exclude_expsyms], [1],
+ [Symbols that should not be listed in the preloaded symbols])
+_LT_TAGDECL([], [include_expsyms], [1],
+ [Symbols that must always be exported])
+_LT_TAGDECL([], [prelink_cmds], [2],
+ [Commands necessary for linking programs (against libraries) with templates])
+_LT_TAGDECL([], [postlink_cmds], [2],
+ [Commands necessary for finishing linking programs])
+_LT_TAGDECL([], [file_list_spec], [1],
+ [Specify filename containing input files])
+dnl FIXME: Not yet implemented
+dnl _LT_TAGDECL([], [thread_safe_flag_spec], [1],
+dnl [Compiler flag to generate thread safe objects])
+])# _LT_LINKER_SHLIBS
+
+
+# _LT_LANG_C_CONFIG([TAG])
+# ------------------------
+# Ensure that the configuration variables for a C compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_C_CONFIG],
+[m4_require([_LT_DECL_EGREP])dnl
+lt_save_CC="$CC"
+AC_LANG_PUSH(C)
+
+# Source file extension for C test sources.
+ac_ext=c
+
+# Object file extension for compiled C test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="int some_variable = 0;"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='int main(){return(0);}'
+
+_LT_TAG_COMPILER
+# Save the default compiler, since it gets overwritten when the other
+# tags are being tested, and _LT_TAGVAR(compiler, []) is a NOP.
+compiler_DEFAULT=$CC
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+ LT_SYS_DLOPEN_SELF
+ _LT_CMD_STRIPLIB
+
+ # Report which library types will actually be built
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_CONFIG($1)
+fi
+AC_LANG_POP
+CC="$lt_save_CC"
+])# _LT_LANG_C_CONFIG
+
+
+# _LT_LANG_CXX_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a C++ compiler are suitably
+# defined. These variables are subsequently used by _LT_CONFIG to write
+# the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_CXX_CONFIG],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+m4_require([_LT_DECL_EGREP])dnl
+m4_require([_LT_PATH_MANIFEST_TOOL])dnl
+if test -n "$CXX" && ( test "X$CXX" != "Xno" &&
+ ( (test "X$CXX" = "Xg++" && `g++ -v >/dev/null 2>&1` ) ||
+ (test "X$CXX" != "Xg++"))) ; then
+ AC_PROG_CXXCPP
+else
+ _lt_caught_CXX_error=yes
+fi
+
+AC_LANG_PUSH(C++)
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(compiler_needs_object, $1)=no
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_shlibpath_var, $1)=unsupported
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for C++ test sources.
+ac_ext=cpp
+
+# Object file extension for compiled C++ test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the CXX compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_caught_CXX_error" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="int some_variable = 0;"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code='int main(int, char *[[]]) { return(0); }'
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC=$CC
+ lt_save_CFLAGS=$CFLAGS
+ lt_save_LD=$LD
+ lt_save_GCC=$GCC
+ GCC=$GXX
+ lt_save_with_gnu_ld=$with_gnu_ld
+ lt_save_path_LD=$lt_cv_path_LD
+ if test -n "${lt_cv_prog_gnu_ldcxx+set}"; then
+ lt_cv_prog_gnu_ld=$lt_cv_prog_gnu_ldcxx
+ else
+ $as_unset lt_cv_prog_gnu_ld
+ fi
+ if test -n "${lt_cv_path_LDCXX+set}"; then
+ lt_cv_path_LD=$lt_cv_path_LDCXX
+ else
+ $as_unset lt_cv_path_LD
+ fi
+ test -z "${LDCXX+set}" || LD=$LDCXX
+ CC=${CXX-"c++"}
+ CFLAGS=$CXXFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ # We don't want -fno-exception when compiling C++ code, so set the
+ # no_builtin_flag separately
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=' -fno-builtin'
+ else
+ _LT_TAGVAR(lt_prog_compiler_no_builtin_flag, $1)=
+ fi
+
+ if test "$GXX" = yes; then
+ # Set up default GNU C++ configuration
+
+ LT_PATH_LD
+
+ # Check if GNU C++ uses GNU ld as the underlying linker, since the
+ # archiving commands below assume that GNU ld is being used.
+ if test "$with_gnu_ld" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC $pic_flag -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # If archive_cmds runs LD, not CC, wlarc should be empty
+ # XXX I think wlarc can be eliminated in ltcf-cxx, but I need to
+ # investigate it a little bit more. (MM)
+ wlarc='${wl}'
+
+ # ancient GNU ld didn't support --whole-archive et. al.
+ if eval "`$CC -print-prog-name=ld` --help 2>&1" |
+ $GREP 'no-whole-archive' > /dev/null; then
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ else
+ _LT_TAGVAR(whole_archive_flag_spec, $1)=
+ fi
+ else
+ with_gnu_ld=no
+ wlarc=
+
+ # A generic and very simple default shared library creation
+ # command for GNU C++ for the case where it uses the native
+ # linker, instead of GNU ld. If possible, this setting should
+ # overridden to take advantage of the native linker features on
+ # the platform it is being used on.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ fi
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ GXX=no
+ with_gnu_ld=no
+ wlarc=
+ fi
+
+ # PORTME: fill in a description of your system's C++ link characteristics
+ AC_MSG_CHECKING([whether the $compiler linker ($LD) supports shared libraries])
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ case $host_os in
+ aix3*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" = ia64; then
+ # On IA64, the linker does run time linking by default, so we don't
+ # have to do anything special.
+ aix_use_runtimelinking=no
+ exp_sym_flag='-Bexport'
+ no_entry_flag=""
+ else
+ aix_use_runtimelinking=no
+
+ # Test if we are trying to use run time linking or normal
+ # AIX style linking. If -brtl is somewhere in LDFLAGS, we
+ # need to do runtime linking.
+ case $host_os in aix4.[[23]]|aix4.[[23]].*|aix[[5-9]]*)
+ for ld_flag in $LDFLAGS; do
+ case $ld_flag in
+ *-brtl*)
+ aix_use_runtimelinking=yes
+ break
+ ;;
+ esac
+ done
+ ;;
+ esac
+
+ exp_sym_flag='-bexport'
+ no_entry_flag='-bnoentry'
+ fi
+
+ # When large executables or shared objects are built, AIX ld can
+ # have problems creating the table of contents. If linking a library
+ # or program results in "error TOC overflow" add -mminimal-toc to
+ # CXXFLAGS/CFLAGS for g++/gcc. In the cases where that is not
+ # enough to fix the problem, add -Wl,-bbigtoc to LDFLAGS.
+
+ _LT_TAGVAR(archive_cmds, $1)=''
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='${wl}-f,'
+
+ if test "$GXX" = yes; then
+ case $host_os in aix4.[[012]]|aix4.[[012]].*)
+ # We only want to do this on AIX 4.2 and lower, the check
+ # below for broken collect2 doesn't work under 4.3+
+ collect2name=`${CC} -print-prog-name=collect2`
+ if test -f "$collect2name" &&
+ strings "$collect2name" | $GREP resolve_lib_name >/dev/null
+ then
+ # We have reworked collect2
+ :
+ else
+ # We have old collect2
+ _LT_TAGVAR(hardcode_direct, $1)=unsupported
+ # It fails to find uninstalled libraries when the uninstalled
+ # path is not listed in the libpath. Setting hardcode_minus_L
+ # to unsupported forces relinking
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=
+ fi
+ esac
+ shared_flag='-shared'
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag="$shared_flag "'${wl}-G'
+ fi
+ else
+ # not using gcc
+ if test "$host_cpu" = ia64; then
+ # VisualAge C++, Version 5.5 for AIX 5L for IA-64, Beta 3 Release
+ # chokes on -Wl,-G. The following line is correct:
+ shared_flag='-G'
+ else
+ if test "$aix_use_runtimelinking" = yes; then
+ shared_flag='${wl}-G'
+ else
+ shared_flag='${wl}-bM:SRE'
+ fi
+ fi
+ fi
+
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-bexpall'
+ # It seems that -bexpall does not export symbols beginning with
+ # underscore (_), so it is better to generate a list of symbols to
+ # export.
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ if test "$aix_use_runtimelinking" = yes; then
+ # Warning - without using the other runtime loading flags (-brtl),
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(allow_undefined_flag, $1)='-berok'
+ # Determine the default libpath from the value encoded in an empty
+ # executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags `if test "x${allow_undefined_flag}" != "x"; then func_echo_all "${wl}${allow_undefined_flag}"; else :; fi` '"\${wl}$exp_sym_flag:\$export_symbols $shared_flag"
+ else
+ if test "$host_cpu" = ia64; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $libdir:/usr/lib:/lib'
+ _LT_TAGVAR(allow_undefined_flag, $1)="-z nodefs"
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs '"\${wl}$no_entry_flag"' $compiler_flags ${wl}${allow_undefined_flag} '"\${wl}$exp_sym_flag:\$export_symbols"
+ else
+ # Determine the default libpath from the value encoded in an
+ # empty executable.
+ _LT_SYS_MODULE_PATH_AIX([$1])
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-blibpath:$libdir:'"$aix_libpath"
+ # Warning - without using the other run time loading flags,
+ # -berok will link without error, but may produce a broken library.
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-bernotok'
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-berok'
+ if test "$with_gnu_ld" = yes; then
+ # We only use this code for GNU lds that support --whole-archive.
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ else
+ # Exported symbols can be pulled into shared objects from archives
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='$convenience'
+ fi
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=yes
+ # This is similar to how AIX traditionally builds its shared
+ # libraries.
+ _LT_TAGVAR(archive_expsym_cmds, $1)="\$CC $shared_flag"' -o $output_objdir/$soname $libobjs $deplibs ${wl}-bnoentry $compiler_flags ${wl}-bE:$export_symbols${allow_undefined_flag}~$AR $AR_FLAGS $output_objdir/$libname$release.a $output_objdir/$soname'
+ fi
+ fi
+ ;;
+
+ beos*)
+ if $LD --help 2>&1 | $GREP ': supported targets:.* elf' > /dev/null; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ # Joseph Beckenbach <jrb3@best.com> says some releases of gcc
+ # support --undefined. This deserves some investigation. FIXME
+ _LT_TAGVAR(archive_cmds, $1)='$CC -nostart $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ chorus*)
+ case $cc_basename in
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ cygwin* | mingw* | pw32* | cegcc*)
+ case $GXX,$cc_basename in
+ ,cl* | no,cl*)
+ # Native MSVC
+ # hardcode_libdir_flag_spec is actually meaningless, as there is
+ # no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)=' '
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=yes
+ _LT_TAGVAR(file_list_spec, $1)='@'
+ # Tell ltmain to make .lib files, not .a files.
+ libext=lib
+ # Tell ltmain to make .dll files, not .so files.
+ shrext_cmds=".dll"
+ # FIXME: Setting linknames here is a bad hack.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -o $output_objdir/$soname $libobjs $compiler_flags $deplibs -Wl,-dll~linknames='
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ $SED -n -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' -e '1\\\!p' < $export_symbols > $output_objdir/$soname.exp;
+ else
+ $SED -e 's/\\\\\\\(.*\\\\\\\)/-link\\\ -EXPORT:\\\\\\\1/' < $export_symbols > $output_objdir/$soname.exp;
+ fi~
+ $CC -o $tool_output_objdir$soname $libobjs $compiler_flags $deplibs "@$tool_output_objdir$soname.exp" -Wl,-DLL,-IMPLIB:"$tool_output_objdir$libname.dll.lib"~
+ linknames='
+ # The linker will not automatically build a static lib if we build a DLL.
+ # _LT_TAGVAR(old_archive_from_new_cmds, $1)='true'
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+ # Don't use ranlib
+ _LT_TAGVAR(old_postinstall_cmds, $1)='chmod 644 $oldlib'
+ _LT_TAGVAR(postlink_cmds, $1)='lt_outputfile="@OUTPUT@"~
+ lt_tool_outputfile="@TOOL_OUTPUT@"~
+ case $lt_outputfile in
+ *.exe|*.EXE) ;;
+ *)
+ lt_outputfile="$lt_outputfile.exe"
+ lt_tool_outputfile="$lt_tool_outputfile.exe"
+ ;;
+ esac~
+ func_to_tool_file "$lt_outputfile"~
+ if test "$MANIFEST_TOOL" != ":" && test -f "$lt_outputfile.manifest"; then
+ $MANIFEST_TOOL -manifest "$lt_tool_outputfile.manifest" -outputresource:"$lt_tool_outputfile" || exit 1;
+ $RM "$lt_outputfile.manifest";
+ fi'
+ ;;
+ *)
+ # g++
+ # _LT_TAGVAR(hardcode_libdir_flag_spec, $1) is actually meaningless,
+ # as there is no search path for DLLs.
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-L$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-all-symbols'
+ _LT_TAGVAR(allow_undefined_flag, $1)=unsupported
+ _LT_TAGVAR(always_export_symbols, $1)=no
+ _LT_TAGVAR(enable_shared_with_static_runtimes, $1)=yes
+
+ if $LD --help 2>&1 | $GREP 'auto-import' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ # If the export-symbols file already is a .def file (1st line
+ # is EXPORTS), use it as is; otherwise, prepend...
+ _LT_TAGVAR(archive_expsym_cmds, $1)='if test "x`$SED 1q $export_symbols`" = xEXPORTS; then
+ cp $export_symbols $output_objdir/$soname.def;
+ else
+ echo EXPORTS > $output_objdir/$soname.def;
+ cat $export_symbols >> $output_objdir/$soname.def;
+ fi~
+ $CC -shared -nostdlib $output_objdir/$soname.def $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $output_objdir/$soname ${wl}--enable-auto-image-base -Xlinker --out-implib -Xlinker $lib'
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+ darwin* | rhapsody*)
+ _LT_DARWIN_LINKER_FEATURES($1)
+ ;;
+
+ dgux*)
+ case $cc_basename in
+ ec++*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ ghcx*)
+ # Green Hills C++ Compiler
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ freebsd2.*)
+ # C++ shared libraries reported to be fairly broken before
+ # switch to ELF
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ freebsd-elf*)
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ ;;
+
+ freebsd* | dragonfly*)
+ # FreeBSD 3 and later use GNU C++ and GNU ld with standard ELF
+ # conventions
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ haiku*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+
+ hpux9*)
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -b ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $EGREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ _LT_TAGVAR(archive_cmds, $1)='$RM $output_objdir/$soname~$CC -shared -nostdlib $pic_flag ${wl}+b ${wl}$install_libdir -o $output_objdir/$soname $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~test $output_objdir/$soname = $lib || mv $output_objdir/$soname $lib'
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ hpux10*|hpux11*)
+ if test $with_gnu_ld = no; then
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}+b ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ case $host_cpu in
+ hppa*64*|ia64*)
+ ;;
+ *)
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ ;;
+ esac
+ fi
+ case $host_cpu in
+ hppa*64*|ia64*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ ;;
+ *)
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(hardcode_minus_L, $1)=yes # Not in the search PATH,
+ # but as the default
+ # location of the library.
+ ;;
+ esac
+
+ case $cc_basename in
+ CC*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ aCC*)
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -b ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`($CC -b $CFLAGS -v conftest.$objext 2>&1) | $GREP "\-L"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test $with_gnu_ld = no; then
+ case $host_cpu in
+ hppa*64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib -fPIC ${wl}+h ${wl}$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ ia64*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+nodefaultrpath -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib $pic_flag ${wl}+h ${wl}$soname ${wl}+b ${wl}$install_libdir -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ ;;
+ esac
+ fi
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ interix[[3-9]]*)
+ _LT_TAGVAR(hardcode_direct, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ # Hack: On Interix 3.x, we cannot compile PIC because of a broken gcc.
+ # Instead, shared libraries are loaded at an image base (0x10000000 by
+ # default) and relocated if they conflict, which is a slow very memory
+ # consuming and fragmenting process. To avoid this, we pick a random,
+ # 256 KiB-aligned image base between 0x50000000 and 0x6FFC0000 at link
+ # time. Moving up from 0x10000000 also allows more sbrk(2) space.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='sed "s,^,_," $export_symbols >$output_objdir/$soname.expsym~$CC -shared $pic_flag $libobjs $deplibs $compiler_flags ${wl}-h,$soname ${wl}--retain-symbols-file,$output_objdir/$soname.expsym ${wl}--image-base,`expr ${RANDOM-$$} % 4096 / 2 \* 262144 + 1342177280` -o $lib'
+ ;;
+ irix5* | irix6*)
+ case $cc_basename in
+ CC*)
+ # SGI C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -all -multigot $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+
+ # Archives containing C++ object files must be created using
+ # "CC -ar", where "CC" is the IRIX C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -ar -WR,-u -o $oldlib $oldobjs'
+ ;;
+ *)
+ if test "$GXX" = yes; then
+ if test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ else
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` -o $lib'
+ fi
+ fi
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ ;;
+ esac
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+ _LT_TAGVAR(inherit_rpath, $1)=yes
+ ;;
+
+ linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo $lib | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib ${wl}-retain-symbols-file,$export_symbols; mv \$templib $lib'
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1 | $GREP "ld"`; rm -f libconftest$shared_ext; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+
+ # Archives containing C++ object files must be created using
+ # "CC -Bstatic", where "CC" is the KAI C++ compiler.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs'
+ ;;
+ icpc* | ecpc* )
+ # Intel C++
+ with_gnu_ld=yes
+ # version 8.0 and above of icpc choke on multiply defined symbols
+ # if we add $predep_objects and $postdep_objects, however 7.1 and
+ # earlier do not add the objects themselves.
+ case `$CC -V 2>&1` in
+ *"Version 7."*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ *) # Version 8.0 or newer
+ tmp_idyn=
+ case $host_cpu in
+ ia64*) tmp_idyn=' -i_dynamic';;
+ esac
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared'"$tmp_idyn"' $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-retain-symbols-file $wl$export_symbols -o $lib'
+ ;;
+ esac
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive$convenience ${wl}--no-whole-archive'
+ ;;
+ pgCC* | pgcpp*)
+ # Portland Group C++ compiler
+ case `$CC -V` in
+ *pgCC\ [[1-5]].* | *pgcpp\ [[1-5]].*)
+ _LT_TAGVAR(prelink_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $objs $libobjs $compile_deplibs~
+ compile_command="$compile_command `find $tpldir -name \*.o | sort | $NL2SP`"'
+ _LT_TAGVAR(old_archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $oldobjs$old_deplibs~
+ $AR $AR_FLAGS $oldlib$oldobjs$old_deplibs `find $tpldir -name \*.o | sort | $NL2SP`~
+ $RANLIB $oldlib'
+ _LT_TAGVAR(archive_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='tpldir=Template.dir~
+ rm -rf $tpldir~
+ $CC --prelink_objects --instantiation_dir $tpldir $predep_objects $libobjs $deplibs $convenience $postdep_objects~
+ $CC -shared $pic_flag $predep_objects $libobjs $deplibs `find $tpldir -name \*.o | sort | $NL2SP` $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ *) # Version 6 and above use weak symbols
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname ${wl}-retain-symbols-file ${wl}$export_symbols -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}--rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`for conv in $convenience\"\"; do test -n \"$conv\" && new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ ;;
+ cxx*)
+ # Compaq C++
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $wl$soname -o $lib ${wl}-retain-symbols-file $wl$export_symbols'
+
+ runpath_var=LD_RUN_PATH
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld .*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "X$list" | $Xsed'
+ ;;
+ xl* | mpixl* | bgxl*)
+ # IBM XL 8.0 on PPC, with GNU ld
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}--export-dynamic'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
+ if test "x$supports_anon_versioning" = xyes; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $output_objdir/$libname.ver~
+ cat $export_symbols | sed -e "s/\(.*\)/\1;/" >> $output_objdir/$libname.ver~
+ echo "local: *; };" >> $output_objdir/$libname.ver~
+ $CC -qmkshrobj $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname ${wl}-version-script ${wl}$output_objdir/$libname.ver -o $lib'
+ fi
+ ;;
+ *)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file ${wl}$export_symbols'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}--whole-archive`new_convenience=; for conv in $convenience\"\"; do test -z \"$conv\" || new_convenience=\"$new_convenience,$conv\"; done; func_echo_all \"$new_convenience\"` ${wl}--no-whole-archive'
+ _LT_TAGVAR(compiler_needs_object, $1)=yes
+
+ # Not sure whether something based on
+ # $CC $CFLAGS -v conftest.$objext -o libconftest$shared_ext 2>&1
+ # would be better.
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ esac
+ ;;
+ esac
+ ;;
+
+ lynxos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ m88k*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ mvs*)
+ case $cc_basename in
+ cxx*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ netbsd*)
+ if echo __ELF__ | $CC -E - | $GREP __ELF__ >/dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$LD -Bshareable -o $lib $predep_objects $libobjs $deplibs $postdep_objects $linker_flags'
+ wlarc=
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ fi
+ # Workaround some broken pre-1.5 toolchains
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP conftest.$objext | $SED -e "s:-lgcc -lc -lgcc::"'
+ ;;
+
+ *nto* | *qnx*)
+ _LT_TAGVAR(ld_shlibs, $1)=yes
+ ;;
+
+ openbsd2*)
+ # C++ shared libraries are fairly broken
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ openbsd*)
+ if test -f /usr/libexec/ld.so; then
+ _LT_TAGVAR(hardcode_direct, $1)=yes
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_direct_absolute, $1)=yes
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ if test -z "`echo __ELF__ | $CC -E - | grep __ELF__`" || test "$host_os-$host_cpu" = "openbsd2.8-powerpc"; then
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared $pic_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-retain-symbols-file,$export_symbols -o $lib'
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-E'
+ _LT_TAGVAR(whole_archive_flag_spec, $1)="$wlarc"'--whole-archive$convenience '"$wlarc"'--no-whole-archive'
+ fi
+ output_verbose_link_cmd=func_echo_all
+ else
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+
+ osf3* | osf4* | osf5*)
+ case $cc_basename in
+ KCC*)
+ # Kuck and Associates, Inc. (KAI) C++ Compiler
+
+ # KCC will only create a shared library if the output file
+ # ends with ".so" (or ".sl" for HP-UX), so rename the library
+ # to its proper name (with version) after linking.
+ _LT_TAGVAR(archive_cmds, $1)='tempext=`echo $shared_ext | $SED -e '\''s/\([[^()0-9A-Za-z{}]]\)/\\\\\1/g'\''`; templib=`echo "$lib" | $SED -e "s/\${tempext}\..*/.so/"`; $CC $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags --soname $soname -o \$templib; mv \$templib $lib'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Archives containing C++ object files must be created using
+ # the KAI C++ compiler.
+ case $host in
+ osf3*) _LT_TAGVAR(old_archive_cmds, $1)='$CC -Bstatic -o $oldlib $oldobjs' ;;
+ *) _LT_TAGVAR(old_archive_cmds, $1)='$CC -o $oldlib $oldobjs' ;;
+ esac
+ ;;
+ RCC*)
+ # Rational C++ 2.4.1
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ cxx*)
+ case $host in
+ osf3*)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname $soname `test -n "$verstring" && func_echo_all "${wl}-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ ;;
+ *)
+ _LT_TAGVAR(allow_undefined_flag, $1)=' -expect_unresolved \*'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname `test -n "$verstring" && func_echo_all "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='for i in `cat $export_symbols`; do printf "%s %s\\n" -exported_symbol "\$i" >> $lib.exp; done~
+ echo "-hidden">> $lib.exp~
+ $CC -shared$allow_undefined_flag $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags -msym -soname $soname ${wl}-input ${wl}$lib.exp `test -n "$verstring" && $ECHO "-set_version $verstring"` -update_registry ${output_objdir}/so_locations -o $lib~
+ $RM $lib.exp'
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-rpath $libdir'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ #
+ # There doesn't appear to be a way to prevent this compiler from
+ # explicitly linking system object files so we need to strip them
+ # from the output so that they don't get included in the library
+ # dependencies.
+ output_verbose_link_cmd='templist=`$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP "ld" | $GREP -v "ld:"`; templist=`func_echo_all "$templist" | $SED "s/\(^.*ld.*\)\( .*ld.*$\)/\1/"`; list=""; for z in $templist; do case $z in conftest.$objext) list="$list $z";; *.$objext);; *) list="$list $z";;esac; done; func_echo_all "$list"'
+ ;;
+ *)
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(allow_undefined_flag, $1)=' ${wl}-expect_unresolved ${wl}\*'
+ case $host in
+ osf3*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib ${allow_undefined_flag} $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-msym ${wl}-soname ${wl}$soname `test -n "$verstring" && func_echo_all "${wl}-set_version ${wl}$verstring"` ${wl}-update_registry ${wl}${output_objdir}/so_locations -o $lib'
+ ;;
+ esac
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-rpath ${wl}$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=:
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+
+ else
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ fi
+ ;;
+ esac
+ ;;
+
+ psos*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ sunos4*)
+ case $cc_basename in
+ CC*)
+ # Sun C++ 4.x
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ lcc*)
+ # Lucid
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # Sun C++ 4.2, 5.x and Centerline C++
+ _LT_TAGVAR(archive_cmds_need_lc,$1)=yes
+ _LT_TAGVAR(no_undefined_flag, $1)=' -zdefs'
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G${allow_undefined_flag} -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G${allow_undefined_flag} ${wl}-M ${wl}$lib.exp -h$soname -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='-R$libdir'
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ # The compiler driver will combine and reorder linker options,
+ # but understands `-z linker_flag'.
+ # Supported since Solaris 2.6 (maybe 2.5.1?)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='-z allextract$convenience -z defaultextract'
+ ;;
+ esac
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+
+ output_verbose_link_cmd='func_echo_all'
+
+ # Archives containing C++ object files must be created using
+ # "CC -xar", where "CC" is the Sun C++ compiler. This is
+ # necessary to make sure instantiated templates are included
+ # in the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -xar -o $oldlib $oldobjs'
+ ;;
+ gcx*)
+ # Green Hills C++ Compiler
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+
+ # The C++ compiler must be used to create the archive.
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC $LDFLAGS -archive -o $oldlib $oldobjs'
+ ;;
+ *)
+ # GNU C++ compiler with Solaris linker
+ if test "$GXX" = yes && test "$with_gnu_ld" = no; then
+ _LT_TAGVAR(no_undefined_flag, $1)=' ${wl}-z ${wl}defs'
+ if $CC --version | $GREP -v '^2\.7' > /dev/null; then
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared $pic_flag -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -shared $pic_flag -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -shared $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ else
+ # g++ 2.7 appears to require `-G' NOT `-shared' on this
+ # platform.
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G -nostdlib $LDFLAGS $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags ${wl}-h $wl$soname -o $lib'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='echo "{ global:" > $lib.exp~cat $export_symbols | $SED -e "s/\(.*\)/\1;/" >> $lib.exp~echo "local: *; };" >> $lib.exp~
+ $CC -G -nostdlib ${wl}-M $wl$lib.exp -o $lib $predep_objects $libobjs $deplibs $postdep_objects $compiler_flags~$RM $lib.exp'
+
+ # Commands to make compiler produce verbose output that lists
+ # what "hidden" libraries, object files and flags are used when
+ # linking a shared library.
+ output_verbose_link_cmd='$CC -G $CFLAGS -v conftest.$objext 2>&1 | $GREP -v "^Configured with:" | $GREP "\-L"'
+ fi
+
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R $wl$libdir'
+ case $host_os in
+ solaris2.[[0-5]] | solaris2.[[0-5]].*) ;;
+ *)
+ _LT_TAGVAR(whole_archive_flag_spec, $1)='${wl}-z ${wl}allextract$convenience ${wl}-z ${wl}defaultextract'
+ ;;
+ esac
+ fi
+ ;;
+ esac
+ ;;
+
+ sysv4*uw2* | sysv5OpenUNIX* | sysv5UnixWare7.[[01]].[[10]]* | unixware7* | sco3.2v5.0.[[024]]*)
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ sysv5* | sco3.2v5* | sco5v6*)
+ # Note: We can NOT use -z defs as we might desire, because we do not
+ # link with -lc, and that would cause any symbols used from libc to
+ # always be unresolved, which means just about no library would
+ # ever link correctly. If we're not using GNU ld we use -z text
+ # though, which does catch some bad symbols but isn't as heavy-handed
+ # as -z defs.
+ _LT_TAGVAR(no_undefined_flag, $1)='${wl}-z,text'
+ _LT_TAGVAR(allow_undefined_flag, $1)='${wl}-z,nodefs'
+ _LT_TAGVAR(archive_cmds_need_lc, $1)=no
+ _LT_TAGVAR(hardcode_shlibpath_var, $1)=no
+ _LT_TAGVAR(hardcode_libdir_flag_spec, $1)='${wl}-R,$libdir'
+ _LT_TAGVAR(hardcode_libdir_separator, $1)=':'
+ _LT_TAGVAR(link_all_deplibs, $1)=yes
+ _LT_TAGVAR(export_dynamic_flag_spec, $1)='${wl}-Bexport'
+ runpath_var='LD_RUN_PATH'
+
+ case $cc_basename in
+ CC*)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -G ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -G ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(old_archive_cmds, $1)='$CC -Tprelink_objects $oldobjs~
+ '"$_LT_TAGVAR(old_archive_cmds, $1)"
+ _LT_TAGVAR(reload_cmds, $1)='$CC -Tprelink_objects $reload_objs~
+ '"$_LT_TAGVAR(reload_cmds, $1)"
+ ;;
+ *)
+ _LT_TAGVAR(archive_cmds, $1)='$CC -shared ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ _LT_TAGVAR(archive_expsym_cmds, $1)='$CC -shared ${wl}-Bexport:$export_symbols ${wl}-h,$soname -o $lib $libobjs $deplibs $compiler_flags'
+ ;;
+ esac
+ ;;
+
+ tandem*)
+ case $cc_basename in
+ NCC*)
+ # NonStop-UX NCC 3.20
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+ ;;
+
+ vxworks*)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+
+ *)
+ # FIXME: insert proper C++ library support
+ _LT_TAGVAR(ld_shlibs, $1)=no
+ ;;
+ esac
+
+ AC_MSG_RESULT([$_LT_TAGVAR(ld_shlibs, $1)])
+ test "$_LT_TAGVAR(ld_shlibs, $1)" = no && can_build_shared=no
+
+ _LT_TAGVAR(GCC, $1)="$GXX"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+ LDCXX=$LD
+ LD=$lt_save_LD
+ GCC=$lt_save_GCC
+ with_gnu_ld=$lt_save_with_gnu_ld
+ lt_cv_path_LDCXX=$lt_cv_path_LD
+ lt_cv_path_LD=$lt_save_path_LD
+ lt_cv_prog_gnu_ldcxx=$lt_cv_prog_gnu_ld
+ lt_cv_prog_gnu_ld=$lt_save_with_gnu_ld
+fi # test "$_lt_caught_CXX_error" != yes
+
+AC_LANG_POP
+])# _LT_LANG_CXX_CONFIG
+
+
+# _LT_FUNC_STRIPNAME_CNF
+# ----------------------
+# func_stripname_cnf prefix suffix name
+# strip PREFIX and SUFFIX off of NAME.
+# PREFIX and SUFFIX must not contain globbing or regex special
+# characters, hashes, percent signs, but SUFFIX may contain a leading
+# dot (in which case that matches only a dot).
+#
+# This function is identical to the (non-XSI) version of func_stripname,
+# except this one can be used by m4 code that may be executed by configure,
+# rather than the libtool script.
+m4_defun([_LT_FUNC_STRIPNAME_CNF],[dnl
+AC_REQUIRE([_LT_DECL_SED])
+AC_REQUIRE([_LT_PROG_ECHO_BACKSLASH])
+func_stripname_cnf ()
+{
+ case ${2} in
+ .*) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%\\\\${2}\$%%"`;;
+ *) func_stripname_result=`$ECHO "${3}" | $SED "s%^${1}%%; s%${2}\$%%"`;;
+ esac
+} # func_stripname_cnf
+])# _LT_FUNC_STRIPNAME_CNF
+
+# _LT_SYS_HIDDEN_LIBDEPS([TAGNAME])
+# ---------------------------------
+# Figure out "hidden" library dependencies from verbose
+# compiler output when linking a shared library.
+# Parse the compiler output and extract the necessary
+# objects, libraries and library flags.
+m4_defun([_LT_SYS_HIDDEN_LIBDEPS],
+[m4_require([_LT_FILEUTILS_DEFAULTS])dnl
+AC_REQUIRE([_LT_FUNC_STRIPNAME_CNF])dnl
+# Dependencies to place before and after the object being linked:
+_LT_TAGVAR(predep_objects, $1)=
+_LT_TAGVAR(postdep_objects, $1)=
+_LT_TAGVAR(predeps, $1)=
+_LT_TAGVAR(postdeps, $1)=
+_LT_TAGVAR(compiler_lib_search_path, $1)=
+
+dnl we can't use the lt_simple_compile_test_code here,
+dnl because it contains code intended for an executable,
+dnl not a library. It's possible we should let each
+dnl tag define a new lt_????_link_test_code variable,
+dnl but it's only used here...
+m4_if([$1], [], [cat > conftest.$ac_ext <<_LT_EOF
+int a;
+void foo (void) { a = 0; }
+_LT_EOF
+], [$1], [CXX], [cat > conftest.$ac_ext <<_LT_EOF
+class Foo
+{
+public:
+ Foo (void) { a = 0; }
+private:
+ int a;
+};
+_LT_EOF
+], [$1], [F77], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer*4 a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [FC], [cat > conftest.$ac_ext <<_LT_EOF
+ subroutine foo
+ implicit none
+ integer a
+ a=0
+ return
+ end
+_LT_EOF
+], [$1], [GCJ], [cat > conftest.$ac_ext <<_LT_EOF
+public class foo {
+ private int a;
+ public void bar (void) {
+ a = 0;
+ }
+};
+_LT_EOF
+], [$1], [GO], [cat > conftest.$ac_ext <<_LT_EOF
+package foo
+func foo() {
+}
+_LT_EOF
+])
+
+_lt_libdeps_save_CFLAGS=$CFLAGS
+case "$CC $CFLAGS " in #(
+*\ -flto*\ *) CFLAGS="$CFLAGS -fno-lto" ;;
+*\ -fwhopr*\ *) CFLAGS="$CFLAGS -fno-whopr" ;;
+*\ -fuse-linker-plugin*\ *) CFLAGS="$CFLAGS -fno-use-linker-plugin" ;;
+esac
+
+dnl Parse the compiler output and extract the necessary
+dnl objects, libraries and library flags.
+if AC_TRY_EVAL(ac_compile); then
+ # Parse the compiler output and extract the necessary
+ # objects, libraries and library flags.
+
+ # Sentinel used to keep track of whether or not we are before
+ # the conftest object file.
+ pre_test_object_deps_done=no
+
+ for p in `eval "$output_verbose_link_cmd"`; do
+ case ${prev}${p} in
+
+ -L* | -R* | -l*)
+ # Some compilers place space between "-{L,R}" and the path.
+ # Remove the space.
+ if test $p = "-L" ||
+ test $p = "-R"; then
+ prev=$p
+ continue
+ fi
+
+ # Expand the sysroot to ease extracting the directories later.
+ if test -z "$prev"; then
+ case $p in
+ -L*) func_stripname_cnf '-L' '' "$p"; prev=-L; p=$func_stripname_result ;;
+ -R*) func_stripname_cnf '-R' '' "$p"; prev=-R; p=$func_stripname_result ;;
+ -l*) func_stripname_cnf '-l' '' "$p"; prev=-l; p=$func_stripname_result ;;
+ esac
+ fi
+ case $p in
+ =*) func_stripname_cnf '=' '' "$p"; p=$lt_sysroot$func_stripname_result ;;
+ esac
+ if test "$pre_test_object_deps_done" = no; then
+ case ${prev} in
+ -L | -R)
+ # Internal compiler library paths should come after those
+ # provided the user. The postdeps already come after the
+ # user supplied libs so there is no need to process them.
+ if test -z "$_LT_TAGVAR(compiler_lib_search_path, $1)"; then
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(compiler_lib_search_path, $1)="${_LT_TAGVAR(compiler_lib_search_path, $1)} ${prev}${p}"
+ fi
+ ;;
+ # The "-l" case would never come before the object being
+ # linked, so don't bother handling this case.
+ esac
+ else
+ if test -z "$_LT_TAGVAR(postdeps, $1)"; then
+ _LT_TAGVAR(postdeps, $1)="${prev}${p}"
+ else
+ _LT_TAGVAR(postdeps, $1)="${_LT_TAGVAR(postdeps, $1)} ${prev}${p}"
+ fi
+ fi
+ prev=
+ ;;
+
+ *.lto.$objext) ;; # Ignore GCC LTO objects
+ *.$objext)
+ # This assumes that the test object file only shows up
+ # once in the compiler output.
+ if test "$p" = "conftest.$objext"; then
+ pre_test_object_deps_done=yes
+ continue
+ fi
+
+ if test "$pre_test_object_deps_done" = no; then
+ if test -z "$_LT_TAGVAR(predep_objects, $1)"; then
+ _LT_TAGVAR(predep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(predep_objects, $1)="$_LT_TAGVAR(predep_objects, $1) $p"
+ fi
+ else
+ if test -z "$_LT_TAGVAR(postdep_objects, $1)"; then
+ _LT_TAGVAR(postdep_objects, $1)="$p"
+ else
+ _LT_TAGVAR(postdep_objects, $1)="$_LT_TAGVAR(postdep_objects, $1) $p"
+ fi
+ fi
+ ;;
+
+ *) ;; # Ignore the rest.
+
+ esac
+ done
+
+ # Clean up.
+ rm -f a.out a.exe
+else
+ echo "libtool.m4: error: problem compiling $1 test program"
+fi
+
+$RM -f confest.$objext
+CFLAGS=$_lt_libdeps_save_CFLAGS
+
+# PORTME: override above test on systems where it is broken
+m4_if([$1], [CXX],
+[case $host_os in
+interix[[3-9]]*)
+ # Interix 3.5 installs completely hosed .la files for C++, so rather than
+ # hack all around it, let's just trust "g++" to DTRT.
+ _LT_TAGVAR(predep_objects,$1)=
+ _LT_TAGVAR(postdep_objects,$1)=
+ _LT_TAGVAR(postdeps,$1)=
+ ;;
+
+linux*)
+ case `$CC -V 2>&1 | sed 5q` in
+ *Sun\ C*)
+ # Sun C++ 5.9
+
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+
+solaris*)
+ case $cc_basename in
+ CC* | sunCC*)
+ # The more standards-conforming stlport4 library is
+ # incompatible with the Cstd library. Avoid specifying
+ # it if it's in CXXFLAGS. Ignore libCrun as
+ # -library=stlport4 depends on it.
+ case " $CXX $CXXFLAGS " in
+ *" -library=stlport4 "*)
+ solaris_use_stlport4=yes
+ ;;
+ esac
+
+ # Adding this requires a known-good setup of shared libraries for
+ # Sun compiler versions before 5.6, else PIC objects from an old
+ # archive will be linked into the output, leading to subtle bugs.
+ if test "$solaris_use_stlport4" != yes; then
+ _LT_TAGVAR(postdeps,$1)='-library=Cstd -library=Crun'
+ fi
+ ;;
+ esac
+ ;;
+esac
+])
+
+case " $_LT_TAGVAR(postdeps, $1) " in
+*" -lc "*) _LT_TAGVAR(archive_cmds_need_lc, $1)=no ;;
+esac
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=
+if test -n "${_LT_TAGVAR(compiler_lib_search_path, $1)}"; then
+ _LT_TAGVAR(compiler_lib_search_dirs, $1)=`echo " ${_LT_TAGVAR(compiler_lib_search_path, $1)}" | ${SED} -e 's! -L! !g' -e 's!^ !!'`
+fi
+_LT_TAGDECL([], [compiler_lib_search_dirs], [1],
+ [The directories searched by this compiler when creating a shared library])
+_LT_TAGDECL([], [predep_objects], [1],
+ [Dependencies to place before and after the objects being linked to
+ create a shared library])
+_LT_TAGDECL([], [postdep_objects], [1])
+_LT_TAGDECL([], [predeps], [1])
+_LT_TAGDECL([], [postdeps], [1])
+_LT_TAGDECL([], [compiler_lib_search_path], [1],
+ [The library search path used internally by the compiler when linking
+ a shared library])
+])# _LT_SYS_HIDDEN_LIBDEPS
+
+
+# _LT_LANG_F77_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for a Fortran 77 compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_F77_CONFIG],
+[AC_LANG_PUSH(Fortran 77)
+if test -z "$F77" || test "X$F77" = "Xno"; then
+ _lt_disable_F77=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for f77 test sources.
+ac_ext=f
+
+# Object file extension for compiled f77 test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the F77 compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_F77" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${F77-"f77"}
+ CFLAGS=$FFLAGS
+ compiler=$CC
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+ GCC=$G77
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$G77"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC="$lt_save_CC"
+ CFLAGS="$lt_save_CFLAGS"
+fi # test "$_lt_disable_F77" != yes
+
+AC_LANG_POP
+])# _LT_LANG_F77_CONFIG
+
+
+# _LT_LANG_FC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for a Fortran compiler are
+# suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_FC_CONFIG],
+[AC_LANG_PUSH(Fortran)
+
+if test -z "$FC" || test "X$FC" = "Xno"; then
+ _lt_disable_FC=yes
+fi
+
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+_LT_TAGVAR(allow_undefined_flag, $1)=
+_LT_TAGVAR(always_export_symbols, $1)=no
+_LT_TAGVAR(archive_expsym_cmds, $1)=
+_LT_TAGVAR(export_dynamic_flag_spec, $1)=
+_LT_TAGVAR(hardcode_direct, $1)=no
+_LT_TAGVAR(hardcode_direct_absolute, $1)=no
+_LT_TAGVAR(hardcode_libdir_flag_spec, $1)=
+_LT_TAGVAR(hardcode_libdir_separator, $1)=
+_LT_TAGVAR(hardcode_minus_L, $1)=no
+_LT_TAGVAR(hardcode_automatic, $1)=no
+_LT_TAGVAR(inherit_rpath, $1)=no
+_LT_TAGVAR(module_cmds, $1)=
+_LT_TAGVAR(module_expsym_cmds, $1)=
+_LT_TAGVAR(link_all_deplibs, $1)=unknown
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+_LT_TAGVAR(no_undefined_flag, $1)=
+_LT_TAGVAR(whole_archive_flag_spec, $1)=
+_LT_TAGVAR(enable_shared_with_static_runtimes, $1)=no
+
+# Source file extension for fc test sources.
+ac_ext=${ac_fc_srcext-f}
+
+# Object file extension for compiled fc test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# No sense in running all these tests if we already determined that
+# the FC compiler isn't working. Some variables (like enable_shared)
+# are currently assumed to apply to all compilers on this platform,
+# and will be corrupted by setting them based on a non-working compiler.
+if test "$_lt_disable_FC" != yes; then
+ # Code to be used in simple compile tests
+ lt_simple_compile_test_code="\
+ subroutine t
+ return
+ end
+"
+
+ # Code to be used in simple link tests
+ lt_simple_link_test_code="\
+ program t
+ end
+"
+
+ # ltmain only uses $CC for tagged configurations so make sure $CC is set.
+ _LT_TAG_COMPILER
+
+ # save warnings/boilerplate of simple test code
+ _LT_COMPILER_BOILERPLATE
+ _LT_LINKER_BOILERPLATE
+
+ # Allow CC to be a program name with arguments.
+ lt_save_CC="$CC"
+ lt_save_GCC=$GCC
+ lt_save_CFLAGS=$CFLAGS
+ CC=${FC-"f95"}
+ CFLAGS=$FCFLAGS
+ compiler=$CC
+ GCC=$ac_cv_fc_compiler_gnu
+
+ _LT_TAGVAR(compiler, $1)=$CC
+ _LT_CC_BASENAME([$compiler])
+
+ if test -n "$compiler"; then
+ AC_MSG_CHECKING([if libtool supports shared libraries])
+ AC_MSG_RESULT([$can_build_shared])
+
+ AC_MSG_CHECKING([whether to build shared libraries])
+ test "$can_build_shared" = "no" && enable_shared=no
+
+ # On AIX, shared libraries and static libraries use the same namespace, and
+ # are all built from PIC.
+ case $host_os in
+ aix3*)
+ test "$enable_shared" = yes && enable_static=no
+ if test -n "$RANLIB"; then
+ archive_cmds="$archive_cmds~\$RANLIB \$lib"
+ postinstall_cmds='$RANLIB $lib'
+ fi
+ ;;
+ aix[[4-9]]*)
+ if test "$host_cpu" != ia64 && test "$aix_use_runtimelinking" = no ; then
+ test "$enable_shared" = yes && enable_static=no
+ fi
+ ;;
+ esac
+ AC_MSG_RESULT([$enable_shared])
+
+ AC_MSG_CHECKING([whether to build static libraries])
+ # Make sure either enable_shared or enable_static is yes.
+ test "$enable_shared" = yes || enable_static=yes
+ AC_MSG_RESULT([$enable_static])
+
+ _LT_TAGVAR(GCC, $1)="$ac_cv_fc_compiler_gnu"
+ _LT_TAGVAR(LD, $1)="$LD"
+
+ ## CAVEAT EMPTOR:
+ ## There is no encapsulation within the following macros, do not change
+ ## the running order or otherwise move them around unless you know exactly
+ ## what you are doing...
+ _LT_SYS_HIDDEN_LIBDEPS($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_SYS_DYNAMIC_LINKER($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+ fi # test -n "$compiler"
+
+ GCC=$lt_save_GCC
+ CC=$lt_save_CC
+ CFLAGS=$lt_save_CFLAGS
+fi # test "$_lt_disable_FC" != yes
+
+AC_LANG_POP
+])# _LT_LANG_FC_CONFIG
+
+
+# _LT_LANG_GCJ_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Java Compiler compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GCJ_CONFIG],
+[AC_REQUIRE([LT_PROG_GCJ])dnl
+AC_LANG_SAVE
+
+# Source file extension for Java test sources.
+ac_ext=java
+
+# Object file extension for compiled Java test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="class foo {}"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='public class conftest { public static void main(String[[]] argv) {}; }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GCJ-"gcj"}
+CFLAGS=$GCJFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# GCJ did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GCJ_CONFIG
+
+
+# _LT_LANG_GO_CONFIG([TAG])
+# --------------------------
+# Ensure that the configuration variables for the GNU Go compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_GO_CONFIG],
+[AC_REQUIRE([LT_PROG_GO])dnl
+AC_LANG_SAVE
+
+# Source file extension for Go test sources.
+ac_ext=go
+
+# Object file extension for compiled Go test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code="package main; func main() { }"
+
+# Code to be used in simple link tests
+lt_simple_link_test_code='package main; func main() { }'
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC=$CC
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=yes
+CC=${GOC-"gccgo"}
+CFLAGS=$GOFLAGS
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_TAGVAR(LD, $1)="$LD"
+_LT_CC_BASENAME([$compiler])
+
+# Go did not exist at the time GCC didn't implicitly link libc in.
+_LT_TAGVAR(archive_cmds_need_lc, $1)=no
+
+_LT_TAGVAR(old_archive_cmds, $1)=$old_archive_cmds
+_LT_TAGVAR(reload_flag, $1)=$reload_flag
+_LT_TAGVAR(reload_cmds, $1)=$reload_cmds
+
+## CAVEAT EMPTOR:
+## There is no encapsulation within the following macros, do not change
+## the running order or otherwise move them around unless you know exactly
+## what you are doing...
+if test -n "$compiler"; then
+ _LT_COMPILER_NO_RTTI($1)
+ _LT_COMPILER_PIC($1)
+ _LT_COMPILER_C_O($1)
+ _LT_COMPILER_FILE_LOCKS($1)
+ _LT_LINKER_SHLIBS($1)
+ _LT_LINKER_HARDCODE_LIBPATH($1)
+
+ _LT_CONFIG($1)
+fi
+
+AC_LANG_RESTORE
+
+GCC=$lt_save_GCC
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_GO_CONFIG
+
+
+# _LT_LANG_RC_CONFIG([TAG])
+# -------------------------
+# Ensure that the configuration variables for the Windows resource compiler
+# are suitably defined. These variables are subsequently used by _LT_CONFIG
+# to write the compiler configuration to `libtool'.
+m4_defun([_LT_LANG_RC_CONFIG],
+[AC_REQUIRE([LT_PROG_RC])dnl
+AC_LANG_SAVE
+
+# Source file extension for RC test sources.
+ac_ext=rc
+
+# Object file extension for compiled RC test sources.
+objext=o
+_LT_TAGVAR(objext, $1)=$objext
+
+# Code to be used in simple compile tests
+lt_simple_compile_test_code='sample MENU { MENUITEM "&Soup", 100, CHECKED }'
+
+# Code to be used in simple link tests
+lt_simple_link_test_code="$lt_simple_compile_test_code"
+
+# ltmain only uses $CC for tagged configurations so make sure $CC is set.
+_LT_TAG_COMPILER
+
+# save warnings/boilerplate of simple test code
+_LT_COMPILER_BOILERPLATE
+_LT_LINKER_BOILERPLATE
+
+# Allow CC to be a program name with arguments.
+lt_save_CC="$CC"
+lt_save_CFLAGS=$CFLAGS
+lt_save_GCC=$GCC
+GCC=
+CC=${RC-"windres"}
+CFLAGS=
+compiler=$CC
+_LT_TAGVAR(compiler, $1)=$CC
+_LT_CC_BASENAME([$compiler])
+_LT_TAGVAR(lt_cv_prog_compiler_c_o, $1)=yes
+
+if test -n "$compiler"; then
+ :
+ _LT_CONFIG($1)
+fi
+
+GCC=$lt_save_GCC
+AC_LANG_RESTORE
+CC=$lt_save_CC
+CFLAGS=$lt_save_CFLAGS
+])# _LT_LANG_RC_CONFIG
+
+
+# LT_PROG_GCJ
+# -----------
+AC_DEFUN([LT_PROG_GCJ],
+[m4_ifdef([AC_PROG_GCJ], [AC_PROG_GCJ],
+ [m4_ifdef([A][M_PROG_GCJ], [A][M_PROG_GCJ],
+ [AC_CHECK_TOOL(GCJ, gcj,)
+ test "x${GCJFLAGS+set}" = xset || GCJFLAGS="-g -O2"
+ AC_SUBST(GCJFLAGS)])])[]dnl
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_GCJ], [LT_PROG_GCJ])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_GCJ], [])
+
+
+# LT_PROG_GO
+# ----------
+AC_DEFUN([LT_PROG_GO],
+[AC_CHECK_TOOL(GOC, gccgo,)
+])
+
+
+# LT_PROG_RC
+# ----------
+AC_DEFUN([LT_PROG_RC],
+[AC_CHECK_TOOL(RC, windres,)
+])
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_RC], [LT_PROG_RC])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_RC], [])
+
+
+# _LT_DECL_EGREP
+# --------------
+# If we don't have a new enough Autoconf to choose the best grep
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_EGREP],
+[AC_REQUIRE([AC_PROG_EGREP])dnl
+AC_REQUIRE([AC_PROG_FGREP])dnl
+test -z "$GREP" && GREP=grep
+_LT_DECL([], [GREP], [1], [A grep program that handles long lines])
+_LT_DECL([], [EGREP], [1], [An ERE matcher])
+_LT_DECL([], [FGREP], [1], [A literal string matcher])
+dnl Non-bleeding-edge autoconf doesn't subst GREP, so do it here too
+AC_SUBST([GREP])
+])
+
+
+# _LT_DECL_OBJDUMP
+# --------------
+# If we don't have a new enough Autoconf to choose the best objdump
+# available, choose the one first in the user's PATH.
+m4_defun([_LT_DECL_OBJDUMP],
+[AC_CHECK_TOOL(OBJDUMP, objdump, false)
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [An object symbol dumper])
+AC_SUBST([OBJDUMP])
+])
+
+# _LT_DECL_DLLTOOL
+# ----------------
+# Ensure DLLTOOL variable is set.
+m4_defun([_LT_DECL_DLLTOOL],
+[AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])
+AC_SUBST([DLLTOOL])
+])
+
+# _LT_DECL_SED
+# ------------
+# Check for a fully-functional sed program, that truncates
+# as few characters as possible. Prefer GNU sed if found.
+m4_defun([_LT_DECL_SED],
+[AC_PROG_SED
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+_LT_DECL([], [SED], [1], [A sed program that does not truncate output])
+_LT_DECL([], [Xsed], ["\$SED -e 1s/^X//"],
+ [Sed that helps us avoid accidentally triggering echo(1) options like -n])
+])# _LT_DECL_SED
+
+m4_ifndef([AC_PROG_SED], [
+############################################################
+# NOTE: This macro has been submitted for inclusion into #
+# GNU Autoconf as AC_PROG_SED. When it is available in #
+# a released version of Autoconf we should remove this #
+# macro and use it instead. #
+############################################################
+
+m4_defun([AC_PROG_SED],
+[AC_MSG_CHECKING([for a sed that does not truncate output])
+AC_CACHE_VAL(lt_cv_path_SED,
+[# Loop through the user's path and test for sed and gsed.
+# Then use that list of sed's as ones to test for truncation.
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+ IFS=$as_save_IFS
+ test -z "$as_dir" && as_dir=.
+ for lt_ac_prog in sed gsed; do
+ for ac_exec_ext in '' $ac_executable_extensions; do
+ if $as_executable_p "$as_dir/$lt_ac_prog$ac_exec_ext"; then
+ lt_ac_sed_list="$lt_ac_sed_list $as_dir/$lt_ac_prog$ac_exec_ext"
+ fi
+ done
+ done
+done
+IFS=$as_save_IFS
+lt_ac_max=0
+lt_ac_count=0
+# Add /usr/xpg4/bin/sed as it is typically found on Solaris
+# along with /bin/sed that truncates output.
+for lt_ac_sed in $lt_ac_sed_list /usr/xpg4/bin/sed; do
+ test ! -f $lt_ac_sed && continue
+ cat /dev/null > conftest.in
+ lt_ac_count=0
+ echo $ECHO_N "0123456789$ECHO_C" >conftest.in
+ # Check for GNU sed and select it if it is found.
+ if "$lt_ac_sed" --version 2>&1 < /dev/null | grep 'GNU' > /dev/null; then
+ lt_cv_path_SED=$lt_ac_sed
+ break
+ fi
+ while true; do
+ cat conftest.in conftest.in >conftest.tmp
+ mv conftest.tmp conftest.in
+ cp conftest.in conftest.nl
+ echo >>conftest.nl
+ $lt_ac_sed -e 's/a$//' < conftest.nl >conftest.out || break
+ cmp -s conftest.out conftest.nl || break
+ # 10000 chars as input seems more than enough
+ test $lt_ac_count -gt 10 && break
+ lt_ac_count=`expr $lt_ac_count + 1`
+ if test $lt_ac_count -gt $lt_ac_max; then
+ lt_ac_max=$lt_ac_count
+ lt_cv_path_SED=$lt_ac_sed
+ fi
+ done
+done
+])
+SED=$lt_cv_path_SED
+AC_SUBST([SED])
+AC_MSG_RESULT([$SED])
+])#AC_PROG_SED
+])#m4_ifndef
+
+# Old name:
+AU_ALIAS([LT_AC_PROG_SED], [AC_PROG_SED])
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([LT_AC_PROG_SED], [])
+
+
+# _LT_CHECK_SHELL_FEATURES
+# ------------------------
+# Find out whether the shell is Bourne or XSI compatible,
+# or has some other useful features.
+m4_defun([_LT_CHECK_SHELL_FEATURES],
+[AC_MSG_CHECKING([whether the shell understands some XSI constructs])
+# Try some XSI features
+xsi_shell=no
+( _lt_dummy="a/b/c"
+ test "${_lt_dummy##*/},${_lt_dummy%/*},${_lt_dummy#??}"${_lt_dummy%"$_lt_dummy"}, \
+ = c,a/b,b/c, \
+ && eval 'test $(( 1 + 1 )) -eq 2 \
+ && test "${#_lt_dummy}" -eq 5' ) >/dev/null 2>&1 \
+ && xsi_shell=yes
+AC_MSG_RESULT([$xsi_shell])
+_LT_CONFIG_LIBTOOL_INIT([xsi_shell='$xsi_shell'])
+
+AC_MSG_CHECKING([whether the shell understands "+="])
+lt_shell_append=no
+( foo=bar; set foo baz; eval "$[1]+=\$[2]" && test "$foo" = barbaz ) \
+ >/dev/null 2>&1 \
+ && lt_shell_append=yes
+AC_MSG_RESULT([$lt_shell_append])
+_LT_CONFIG_LIBTOOL_INIT([lt_shell_append='$lt_shell_append'])
+
+if ( (MAIL=60; unset MAIL) || exit) >/dev/null 2>&1; then
+ lt_unset=unset
+else
+ lt_unset=false
+fi
+_LT_DECL([], [lt_unset], [0], [whether the shell understands "unset"])dnl
+
+# test EBCDIC or ASCII
+case `echo X|tr X '\101'` in
+ A) # ASCII based system
+ # \n is not interpreted correctly by Solaris 8 /usr/ucb/tr
+ lt_SP2NL='tr \040 \012'
+ lt_NL2SP='tr \015\012 \040\040'
+ ;;
+ *) # EBCDIC based system
+ lt_SP2NL='tr \100 \n'
+ lt_NL2SP='tr \r\n \100\100'
+ ;;
+esac
+_LT_DECL([SP2NL], [lt_SP2NL], [1], [turn spaces into newlines])dnl
+_LT_DECL([NL2SP], [lt_NL2SP], [1], [turn newlines into spaces])dnl
+])# _LT_CHECK_SHELL_FEATURES
+
+
+# _LT_PROG_FUNCTION_REPLACE (FUNCNAME, REPLACEMENT-BODY)
+# ------------------------------------------------------
+# In `$cfgfile', look for function FUNCNAME delimited by `^FUNCNAME ()$' and
+# '^} FUNCNAME ', and replace its body with REPLACEMENT-BODY.
+m4_defun([_LT_PROG_FUNCTION_REPLACE],
+[dnl {
+sed -e '/^$1 ()$/,/^} # $1 /c\
+$1 ()\
+{\
+m4_bpatsubsts([$2], [$], [\\], [^\([ ]\)], [\\\1])
+} # Extended-shell $1 implementation' "$cfgfile" > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+test 0 -eq $? || _lt_function_replace_fail=:
+])
+
+
+# _LT_PROG_REPLACE_SHELLFNS
+# -------------------------
+# Replace existing portable implementations of several shell functions with
+# equivalent extended shell implementations where those features are available..
+m4_defun([_LT_PROG_REPLACE_SHELLFNS],
+[if test x"$xsi_shell" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_dirname], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_basename], [dnl
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_dirname_and_basename], [dnl
+ case ${1} in
+ */*) func_dirname_result="${1%/*}${2}" ;;
+ * ) func_dirname_result="${3}" ;;
+ esac
+ func_basename_result="${1##*/}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_stripname], [dnl
+ # pdksh 5.2.14 does not do ${X%$Y} correctly if both X and Y are
+ # positional parameters, so assign one to ordinary parameter first.
+ func_stripname_result=${3}
+ func_stripname_result=${func_stripname_result#"${1}"}
+ func_stripname_result=${func_stripname_result%"${2}"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_long_opt], [dnl
+ func_split_long_opt_name=${1%%=*}
+ func_split_long_opt_arg=${1#*=}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_split_short_opt], [dnl
+ func_split_short_opt_arg=${1#??}
+ func_split_short_opt_name=${1%"$func_split_short_opt_arg"}])
+
+ _LT_PROG_FUNCTION_REPLACE([func_lo2o], [dnl
+ case ${1} in
+ *.lo) func_lo2o_result=${1%.lo}.${objext} ;;
+ *) func_lo2o_result=${1} ;;
+ esac])
+
+ _LT_PROG_FUNCTION_REPLACE([func_xform], [ func_xform_result=${1%.*}.lo])
+
+ _LT_PROG_FUNCTION_REPLACE([func_arith], [ func_arith_result=$(( $[*] ))])
+
+ _LT_PROG_FUNCTION_REPLACE([func_len], [ func_len_result=${#1}])
+fi
+
+if test x"$lt_shell_append" = xyes; then
+ _LT_PROG_FUNCTION_REPLACE([func_append], [ eval "${1}+=\\${2}"])
+
+ _LT_PROG_FUNCTION_REPLACE([func_append_quoted], [dnl
+ func_quote_for_eval "${2}"
+dnl m4 expansion turns \\\\ into \\, and then the shell eval turns that into \
+ eval "${1}+=\\\\ \\$func_quote_for_eval_result"])
+
+ # Save a `func_append' function call where possible by direct use of '+='
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1+="%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+else
+ # Save a `func_append' function call even when '+=' is not available
+ sed -e 's%func_append \([[a-zA-Z_]]\{1,\}\) "%\1="$\1%g' $cfgfile > $cfgfile.tmp \
+ && mv -f "$cfgfile.tmp" "$cfgfile" \
+ || (rm -f "$cfgfile" && cp "$cfgfile.tmp" "$cfgfile" && rm -f "$cfgfile.tmp")
+ test 0 -eq $? || _lt_function_replace_fail=:
+fi
+
+if test x"$_lt_function_replace_fail" = x":"; then
+ AC_MSG_WARN([Unable to substitute extended shell functions in $ofile])
+fi
+])
+
+# _LT_PATH_CONVERSION_FUNCTIONS
+# -----------------------------
+# Determine which file name conversion functions should be used by
+# func_to_host_file (and, implicitly, by func_to_host_path). These are needed
+# for certain cross-compile configurations and native mingw.
+m4_defun([_LT_PATH_CONVERSION_FUNCTIONS],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+AC_REQUIRE([AC_CANONICAL_BUILD])dnl
+AC_MSG_CHECKING([how to convert $build file names to $host format])
+AC_CACHE_VAL(lt_cv_to_host_file_cmd,
+[case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_cygwin_to_w32
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_w32
+ ;;
+ esac
+ ;;
+ *-*-cygwin* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_host_file_cmd=func_convert_file_msys_to_cygwin
+ ;;
+ *-*-cygwin* )
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+ * ) # otherwise, assume *nix
+ lt_cv_to_host_file_cmd=func_convert_file_nix_to_cygwin
+ ;;
+ esac
+ ;;
+ * ) # unhandled hosts (and "normal" native builds)
+ lt_cv_to_host_file_cmd=func_convert_file_noop
+ ;;
+esac
+])
+to_host_file_cmd=$lt_cv_to_host_file_cmd
+AC_MSG_RESULT([$lt_cv_to_host_file_cmd])
+_LT_DECL([to_host_file_cmd], [lt_cv_to_host_file_cmd],
+ [0], [convert $build file names to $host format])dnl
+
+AC_MSG_CHECKING([how to convert $build file names to toolchain format])
+AC_CACHE_VAL(lt_cv_to_tool_file_cmd,
+[#assume ordinary cross tools, or native build.
+lt_cv_to_tool_file_cmd=func_convert_file_noop
+case $host in
+ *-*-mingw* )
+ case $build in
+ *-*-mingw* ) # actually msys
+ lt_cv_to_tool_file_cmd=func_convert_file_msys_to_w32
+ ;;
+ esac
+ ;;
+esac
+])
+to_tool_file_cmd=$lt_cv_to_tool_file_cmd
+AC_MSG_RESULT([$lt_cv_to_tool_file_cmd])
+_LT_DECL([to_tool_file_cmd], [lt_cv_to_tool_file_cmd],
+ [0], [convert $build files to toolchain format])dnl
+])# _LT_PATH_CONVERSION_FUNCTIONS
--- /dev/null
+# Helper functions for option handling. -*- Autoconf -*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008, 2009 Free Software Foundation,
+# Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 7 ltoptions.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOPTIONS_VERSION], [m4_if([1])])
+
+
+# _LT_MANGLE_OPTION(MACRO-NAME, OPTION-NAME)
+# ------------------------------------------
+m4_define([_LT_MANGLE_OPTION],
+[[_LT_OPTION_]m4_bpatsubst($1__$2, [[^a-zA-Z0-9_]], [_])])
+
+
+# _LT_SET_OPTION(MACRO-NAME, OPTION-NAME)
+# ---------------------------------------
+# Set option OPTION-NAME for macro MACRO-NAME, and if there is a
+# matching handler defined, dispatch to it. Other OPTION-NAMEs are
+# saved as a flag.
+m4_define([_LT_SET_OPTION],
+[m4_define(_LT_MANGLE_OPTION([$1], [$2]))dnl
+m4_ifdef(_LT_MANGLE_DEFUN([$1], [$2]),
+ _LT_MANGLE_DEFUN([$1], [$2]),
+ [m4_warning([Unknown $1 option `$2'])])[]dnl
+])
+
+
+# _LT_IF_OPTION(MACRO-NAME, OPTION-NAME, IF-SET, [IF-NOT-SET])
+# ------------------------------------------------------------
+# Execute IF-SET if OPTION is set, IF-NOT-SET otherwise.
+m4_define([_LT_IF_OPTION],
+[m4_ifdef(_LT_MANGLE_OPTION([$1], [$2]), [$3], [$4])])
+
+
+# _LT_UNLESS_OPTIONS(MACRO-NAME, OPTION-LIST, IF-NOT-SET)
+# -------------------------------------------------------
+# Execute IF-NOT-SET unless all options in OPTION-LIST for MACRO-NAME
+# are set.
+m4_define([_LT_UNLESS_OPTIONS],
+[m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [m4_ifdef(_LT_MANGLE_OPTION([$1], _LT_Option),
+ [m4_define([$0_found])])])[]dnl
+m4_ifdef([$0_found], [m4_undefine([$0_found])], [$3
+])[]dnl
+])
+
+
+# _LT_SET_OPTIONS(MACRO-NAME, OPTION-LIST)
+# ----------------------------------------
+# OPTION-LIST is a space-separated list of Libtool options associated
+# with MACRO-NAME. If any OPTION has a matching handler declared with
+# LT_OPTION_DEFINE, dispatch to that macro; otherwise complain about
+# the unknown option and exit.
+m4_defun([_LT_SET_OPTIONS],
+[# Set options
+m4_foreach([_LT_Option], m4_split(m4_normalize([$2])),
+ [_LT_SET_OPTION([$1], _LT_Option)])
+
+m4_if([$1],[LT_INIT],[
+ dnl
+ dnl Simply set some default values (i.e off) if boolean options were not
+ dnl specified:
+ _LT_UNLESS_OPTIONS([LT_INIT], [dlopen], [enable_dlopen=no
+ ])
+ _LT_UNLESS_OPTIONS([LT_INIT], [win32-dll], [enable_win32_dll=no
+ ])
+ dnl
+ dnl If no reference was made to various pairs of opposing options, then
+ dnl we run the default mode handler for the pair. For example, if neither
+ dnl `shared' nor `disable-shared' was passed, we enable building of shared
+ dnl archives by default:
+ _LT_UNLESS_OPTIONS([LT_INIT], [shared disable-shared], [_LT_ENABLE_SHARED])
+ _LT_UNLESS_OPTIONS([LT_INIT], [static disable-static], [_LT_ENABLE_STATIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [pic-only no-pic], [_LT_WITH_PIC])
+ _LT_UNLESS_OPTIONS([LT_INIT], [fast-install disable-fast-install],
+ [_LT_ENABLE_FAST_INSTALL])
+ ])
+])# _LT_SET_OPTIONS
+
+
+## --------------------------------- ##
+## Macros to handle LT_INIT options. ##
+## --------------------------------- ##
+
+# _LT_MANGLE_DEFUN(MACRO-NAME, OPTION-NAME)
+# -----------------------------------------
+m4_define([_LT_MANGLE_DEFUN],
+[[_LT_OPTION_DEFUN_]m4_bpatsubst(m4_toupper([$1__$2]), [[^A-Z0-9_]], [_])])
+
+
+# LT_OPTION_DEFINE(MACRO-NAME, OPTION-NAME, CODE)
+# -----------------------------------------------
+m4_define([LT_OPTION_DEFINE],
+[m4_define(_LT_MANGLE_DEFUN([$1], [$2]), [$3])[]dnl
+])# LT_OPTION_DEFINE
+
+
+# dlopen
+# ------
+LT_OPTION_DEFINE([LT_INIT], [dlopen], [enable_dlopen=yes
+])
+
+AU_DEFUN([AC_LIBTOOL_DLOPEN],
+[_LT_SET_OPTION([LT_INIT], [dlopen])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `dlopen' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_DLOPEN], [])
+
+
+# win32-dll
+# ---------
+# Declare package support for building win32 dll's.
+LT_OPTION_DEFINE([LT_INIT], [win32-dll],
+[enable_win32_dll=yes
+
+case $host in
+*-*-cygwin* | *-*-mingw* | *-*-pw32* | *-*-cegcc*)
+ AC_CHECK_TOOL(AS, as, false)
+ AC_CHECK_TOOL(DLLTOOL, dlltool, false)
+ AC_CHECK_TOOL(OBJDUMP, objdump, false)
+ ;;
+esac
+
+test -z "$AS" && AS=as
+_LT_DECL([], [AS], [1], [Assembler program])dnl
+
+test -z "$DLLTOOL" && DLLTOOL=dlltool
+_LT_DECL([], [DLLTOOL], [1], [DLL creation program])dnl
+
+test -z "$OBJDUMP" && OBJDUMP=objdump
+_LT_DECL([], [OBJDUMP], [1], [Object dumper program])dnl
+])# win32-dll
+
+AU_DEFUN([AC_LIBTOOL_WIN32_DLL],
+[AC_REQUIRE([AC_CANONICAL_HOST])dnl
+_LT_SET_OPTION([LT_INIT], [win32-dll])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `win32-dll' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_WIN32_DLL], [])
+
+
+# _LT_ENABLE_SHARED([DEFAULT])
+# ----------------------------
+# implement the --enable-shared flag, and supports the `shared' and
+# `disable-shared' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_SHARED],
+[m4_define([_LT_ENABLE_SHARED_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([shared],
+ [AS_HELP_STRING([--enable-shared@<:@=PKGS@:>@],
+ [build shared libraries @<:@default=]_LT_ENABLE_SHARED_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_shared=yes ;;
+ no) enable_shared=no ;;
+ *)
+ enable_shared=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_shared=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_shared=]_LT_ENABLE_SHARED_DEFAULT)
+
+ _LT_DECL([build_libtool_libs], [enable_shared], [0],
+ [Whether or not to build shared libraries])
+])# _LT_ENABLE_SHARED
+
+LT_OPTION_DEFINE([LT_INIT], [shared], [_LT_ENABLE_SHARED([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-shared], [_LT_ENABLE_SHARED([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[shared])
+])
+
+AC_DEFUN([AC_DISABLE_SHARED],
+[_LT_SET_OPTION([LT_INIT], [disable-shared])
+])
+
+AU_DEFUN([AM_ENABLE_SHARED], [AC_ENABLE_SHARED($@)])
+AU_DEFUN([AM_DISABLE_SHARED], [AC_DISABLE_SHARED($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_SHARED], [])
+dnl AC_DEFUN([AM_DISABLE_SHARED], [])
+
+
+
+# _LT_ENABLE_STATIC([DEFAULT])
+# ----------------------------
+# implement the --enable-static flag, and support the `static' and
+# `disable-static' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_STATIC],
+[m4_define([_LT_ENABLE_STATIC_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([static],
+ [AS_HELP_STRING([--enable-static@<:@=PKGS@:>@],
+ [build static libraries @<:@default=]_LT_ENABLE_STATIC_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_static=yes ;;
+ no) enable_static=no ;;
+ *)
+ enable_static=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_static=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_static=]_LT_ENABLE_STATIC_DEFAULT)
+
+ _LT_DECL([build_old_libs], [enable_static], [0],
+ [Whether or not to build static libraries])
+])# _LT_ENABLE_STATIC
+
+LT_OPTION_DEFINE([LT_INIT], [static], [_LT_ENABLE_STATIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-static], [_LT_ENABLE_STATIC([no])])
+
+# Old names:
+AC_DEFUN([AC_ENABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[static])
+])
+
+AC_DEFUN([AC_DISABLE_STATIC],
+[_LT_SET_OPTION([LT_INIT], [disable-static])
+])
+
+AU_DEFUN([AM_ENABLE_STATIC], [AC_ENABLE_STATIC($@)])
+AU_DEFUN([AM_DISABLE_STATIC], [AC_DISABLE_STATIC($@)])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AM_ENABLE_STATIC], [])
+dnl AC_DEFUN([AM_DISABLE_STATIC], [])
+
+
+
+# _LT_ENABLE_FAST_INSTALL([DEFAULT])
+# ----------------------------------
+# implement the --enable-fast-install flag, and support the `fast-install'
+# and `disable-fast-install' LT_INIT options.
+# DEFAULT is either `yes' or `no'. If omitted, it defaults to `yes'.
+m4_define([_LT_ENABLE_FAST_INSTALL],
+[m4_define([_LT_ENABLE_FAST_INSTALL_DEFAULT], [m4_if($1, no, no, yes)])dnl
+AC_ARG_ENABLE([fast-install],
+ [AS_HELP_STRING([--enable-fast-install@<:@=PKGS@:>@],
+ [optimize for fast installation @<:@default=]_LT_ENABLE_FAST_INSTALL_DEFAULT[@:>@])],
+ [p=${PACKAGE-default}
+ case $enableval in
+ yes) enable_fast_install=yes ;;
+ no) enable_fast_install=no ;;
+ *)
+ enable_fast_install=no
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for pkg in $enableval; do
+ IFS="$lt_save_ifs"
+ if test "X$pkg" = "X$p"; then
+ enable_fast_install=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [enable_fast_install=]_LT_ENABLE_FAST_INSTALL_DEFAULT)
+
+_LT_DECL([fast_install], [enable_fast_install], [0],
+ [Whether or not to optimize for fast installation])dnl
+])# _LT_ENABLE_FAST_INSTALL
+
+LT_OPTION_DEFINE([LT_INIT], [fast-install], [_LT_ENABLE_FAST_INSTALL([yes])])
+LT_OPTION_DEFINE([LT_INIT], [disable-fast-install], [_LT_ENABLE_FAST_INSTALL([no])])
+
+# Old names:
+AU_DEFUN([AC_ENABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], m4_if([$1], [no], [disable-])[fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `fast-install' option into LT_INIT's first parameter.])
+])
+
+AU_DEFUN([AC_DISABLE_FAST_INSTALL],
+[_LT_SET_OPTION([LT_INIT], [disable-fast-install])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you put
+the `disable-fast-install' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_ENABLE_FAST_INSTALL], [])
+dnl AC_DEFUN([AM_DISABLE_FAST_INSTALL], [])
+
+
+# _LT_WITH_PIC([MODE])
+# --------------------
+# implement the --with-pic flag, and support the `pic-only' and `no-pic'
+# LT_INIT options.
+# MODE is either `yes' or `no'. If omitted, it defaults to `both'.
+m4_define([_LT_WITH_PIC],
+[AC_ARG_WITH([pic],
+ [AS_HELP_STRING([--with-pic@<:@=PKGS@:>@],
+ [try to use only PIC/non-PIC objects @<:@default=use both@:>@])],
+ [lt_p=${PACKAGE-default}
+ case $withval in
+ yes|no) pic_mode=$withval ;;
+ *)
+ pic_mode=default
+ # Look at the argument we got. We use all the common list separators.
+ lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+ for lt_pkg in $withval; do
+ IFS="$lt_save_ifs"
+ if test "X$lt_pkg" = "X$lt_p"; then
+ pic_mode=yes
+ fi
+ done
+ IFS="$lt_save_ifs"
+ ;;
+ esac],
+ [pic_mode=default])
+
+test -z "$pic_mode" && pic_mode=m4_default([$1], [default])
+
+_LT_DECL([], [pic_mode], [0], [What type of objects to build])dnl
+])# _LT_WITH_PIC
+
+LT_OPTION_DEFINE([LT_INIT], [pic-only], [_LT_WITH_PIC([yes])])
+LT_OPTION_DEFINE([LT_INIT], [no-pic], [_LT_WITH_PIC([no])])
+
+# Old name:
+AU_DEFUN([AC_LIBTOOL_PICMODE],
+[_LT_SET_OPTION([LT_INIT], [pic-only])
+AC_DIAGNOSE([obsolete],
+[$0: Remove this warning and the call to _LT_SET_OPTION when you
+put the `pic-only' option into LT_INIT's first parameter.])
+])
+
+dnl aclocal-1.4 backwards compatibility:
+dnl AC_DEFUN([AC_LIBTOOL_PICMODE], [])
+
+## ----------------- ##
+## LTDL_INIT Options ##
+## ----------------- ##
+
+m4_define([_LTDL_MODE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [nonrecursive],
+ [m4_define([_LTDL_MODE], [nonrecursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [recursive],
+ [m4_define([_LTDL_MODE], [recursive])])
+LT_OPTION_DEFINE([LTDL_INIT], [subproject],
+ [m4_define([_LTDL_MODE], [subproject])])
+
+m4_define([_LTDL_TYPE], [])
+LT_OPTION_DEFINE([LTDL_INIT], [installable],
+ [m4_define([_LTDL_TYPE], [installable])])
+LT_OPTION_DEFINE([LTDL_INIT], [convenience],
+ [m4_define([_LTDL_TYPE], [convenience])])
--- /dev/null
+# ltsugar.m4 -- libtool m4 base layer. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2008 Free Software Foundation, Inc.
+# Written by Gary V. Vaughan, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 6 ltsugar.m4
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTSUGAR_VERSION], [m4_if([0.1])])
+
+
+# lt_join(SEP, ARG1, [ARG2...])
+# -----------------------------
+# Produce ARG1SEPARG2...SEPARGn, omitting [] arguments and their
+# associated separator.
+# Needed until we can rely on m4_join from Autoconf 2.62, since all earlier
+# versions in m4sugar had bugs.
+m4_define([lt_join],
+[m4_if([$#], [1], [],
+ [$#], [2], [[$2]],
+ [m4_if([$2], [], [], [[$2]_])$0([$1], m4_shift(m4_shift($@)))])])
+m4_define([_lt_join],
+[m4_if([$#$2], [2], [],
+ [m4_if([$2], [], [], [[$1$2]])$0([$1], m4_shift(m4_shift($@)))])])
+
+
+# lt_car(LIST)
+# lt_cdr(LIST)
+# ------------
+# Manipulate m4 lists.
+# These macros are necessary as long as will still need to support
+# Autoconf-2.59 which quotes differently.
+m4_define([lt_car], [[$1]])
+m4_define([lt_cdr],
+[m4_if([$#], 0, [m4_fatal([$0: cannot be called without arguments])],
+ [$#], 1, [],
+ [m4_dquote(m4_shift($@))])])
+m4_define([lt_unquote], $1)
+
+
+# lt_append(MACRO-NAME, STRING, [SEPARATOR])
+# ------------------------------------------
+# Redefine MACRO-NAME to hold its former content plus `SEPARATOR'`STRING'.
+# Note that neither SEPARATOR nor STRING are expanded; they are appended
+# to MACRO-NAME as is (leaving the expansion for when MACRO-NAME is invoked).
+# No SEPARATOR is output if MACRO-NAME was previously undefined (different
+# than defined and empty).
+#
+# This macro is needed until we can rely on Autoconf 2.62, since earlier
+# versions of m4sugar mistakenly expanded SEPARATOR but not STRING.
+m4_define([lt_append],
+[m4_define([$1],
+ m4_ifdef([$1], [m4_defn([$1])[$3]])[$2])])
+
+
+
+# lt_combine(SEP, PREFIX-LIST, INFIX, SUFFIX1, [SUFFIX2...])
+# ----------------------------------------------------------
+# Produce a SEP delimited list of all paired combinations of elements of
+# PREFIX-LIST with SUFFIX1 through SUFFIXn. Each element of the list
+# has the form PREFIXmINFIXSUFFIXn.
+# Needed until we can rely on m4_combine added in Autoconf 2.62.
+m4_define([lt_combine],
+[m4_if(m4_eval([$# > 3]), [1],
+ [m4_pushdef([_Lt_sep], [m4_define([_Lt_sep], m4_defn([lt_car]))])]]dnl
+[[m4_foreach([_Lt_prefix], [$2],
+ [m4_foreach([_Lt_suffix],
+ ]m4_dquote(m4_dquote(m4_shift(m4_shift(m4_shift($@)))))[,
+ [_Lt_sep([$1])[]m4_defn([_Lt_prefix])[$3]m4_defn([_Lt_suffix])])])])])
+
+
+# lt_if_append_uniq(MACRO-NAME, VARNAME, [SEPARATOR], [UNIQ], [NOT-UNIQ])
+# -----------------------------------------------------------------------
+# Iff MACRO-NAME does not yet contain VARNAME, then append it (delimited
+# by SEPARATOR if supplied) and expand UNIQ, else NOT-UNIQ.
+m4_define([lt_if_append_uniq],
+[m4_ifdef([$1],
+ [m4_if(m4_index([$3]m4_defn([$1])[$3], [$3$2$3]), [-1],
+ [lt_append([$1], [$2], [$3])$4],
+ [$5])],
+ [lt_append([$1], [$2], [$3])$4])])
+
+
+# lt_dict_add(DICT, KEY, VALUE)
+# -----------------------------
+m4_define([lt_dict_add],
+[m4_define([$1($2)], [$3])])
+
+
+# lt_dict_add_subkey(DICT, KEY, SUBKEY, VALUE)
+# --------------------------------------------
+m4_define([lt_dict_add_subkey],
+[m4_define([$1($2:$3)], [$4])])
+
+
+# lt_dict_fetch(DICT, KEY, [SUBKEY])
+# ----------------------------------
+m4_define([lt_dict_fetch],
+[m4_ifval([$3],
+ m4_ifdef([$1($2:$3)], [m4_defn([$1($2:$3)])]),
+ m4_ifdef([$1($2)], [m4_defn([$1($2)])]))])
+
+
+# lt_if_dict_fetch(DICT, KEY, [SUBKEY], VALUE, IF-TRUE, [IF-FALSE])
+# -----------------------------------------------------------------
+m4_define([lt_if_dict_fetch],
+[m4_if(lt_dict_fetch([$1], [$2], [$3]), [$4],
+ [$5],
+ [$6])])
+
+
+# lt_dict_filter(DICT, [SUBKEY], VALUE, [SEPARATOR], KEY, [...])
+# --------------------------------------------------------------
+m4_define([lt_dict_filter],
+[m4_if([$5], [], [],
+ [lt_join(m4_quote(m4_default([$4], [[, ]])),
+ lt_unquote(m4_split(m4_normalize(m4_foreach(_Lt_key, lt_car([m4_shiftn(4, $@)]),
+ [lt_if_dict_fetch([$1], _Lt_key, [$2], [$3], [_Lt_key ])])))))])[]dnl
+])
--- /dev/null
+# ltversion.m4 -- version numbers -*- Autoconf -*-
+#
+# Copyright (C) 2004 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# @configure_input@
+
+# serial 3337 ltversion.m4
+# This file is part of GNU Libtool
+
+m4_define([LT_PACKAGE_VERSION], [2.4.2])
+m4_define([LT_PACKAGE_REVISION], [1.3337])
+
+AC_DEFUN([LTVERSION_VERSION],
+[macro_version='2.4.2'
+macro_revision='1.3337'
+_LT_DECL(, macro_version, 0, [Which release of libtool.m4 was used?])
+_LT_DECL(, macro_revision, 0)
+])
--- /dev/null
+# lt~obsolete.m4 -- aclocal satisfying obsolete definitions. -*-Autoconf-*-
+#
+# Copyright (C) 2004, 2005, 2007, 2009 Free Software Foundation, Inc.
+# Written by Scott James Remnant, 2004.
+#
+# This file is free software; the Free Software Foundation gives
+# unlimited permission to copy and/or distribute it, with or without
+# modifications, as long as this notice is preserved.
+
+# serial 5 lt~obsolete.m4
+
+# These exist entirely to fool aclocal when bootstrapping libtool.
+#
+# In the past libtool.m4 has provided macros via AC_DEFUN (or AU_DEFUN)
+# which have later been changed to m4_define as they aren't part of the
+# exported API, or moved to Autoconf or Automake where they belong.
+#
+# The trouble is, aclocal is a bit thick. It'll see the old AC_DEFUN
+# in /usr/share/aclocal/libtool.m4 and remember it, then when it sees us
+# using a macro with the same name in our local m4/libtool.m4 it'll
+# pull the old libtool.m4 in (it doesn't see our shiny new m4_define
+# and doesn't know about Autoconf macros at all.)
+#
+# So we provide this file, which has a silly filename so it's always
+# included after everything else. This provides aclocal with the
+# AC_DEFUNs it wants, but when m4 processes it, it doesn't do anything
+# because those macros already exist, or will be overwritten later.
+# We use AC_DEFUN over AU_DEFUN for compatibility with aclocal-1.6.
+#
+# Anytime we withdraw an AC_DEFUN or AU_DEFUN, remember to add it here.
+# Yes, that means every name once taken will need to remain here until
+# we give up compatibility with versions before 1.7, at which point
+# we need to keep only those names which we still refer to.
+
+# This is to help aclocal find these macros, as it can't see m4_define.
+AC_DEFUN([LTOBSOLETE_VERSION], [m4_if([1])])
+
+m4_ifndef([AC_LIBTOOL_LINKER_OPTION], [AC_DEFUN([AC_LIBTOOL_LINKER_OPTION])])
+m4_ifndef([AC_PROG_EGREP], [AC_DEFUN([AC_PROG_EGREP])])
+m4_ifndef([_LT_AC_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_AC_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_AC_SHELL_INIT], [AC_DEFUN([_LT_AC_SHELL_INIT])])
+m4_ifndef([_LT_AC_SYS_LIBPATH_AIX], [AC_DEFUN([_LT_AC_SYS_LIBPATH_AIX])])
+m4_ifndef([_LT_PROG_LTMAIN], [AC_DEFUN([_LT_PROG_LTMAIN])])
+m4_ifndef([_LT_AC_TAGVAR], [AC_DEFUN([_LT_AC_TAGVAR])])
+m4_ifndef([AC_LTDL_ENABLE_INSTALL], [AC_DEFUN([AC_LTDL_ENABLE_INSTALL])])
+m4_ifndef([AC_LTDL_PREOPEN], [AC_DEFUN([AC_LTDL_PREOPEN])])
+m4_ifndef([_LT_AC_SYS_COMPILER], [AC_DEFUN([_LT_AC_SYS_COMPILER])])
+m4_ifndef([_LT_AC_LOCK], [AC_DEFUN([_LT_AC_LOCK])])
+m4_ifndef([AC_LIBTOOL_SYS_OLD_ARCHIVE], [AC_DEFUN([AC_LIBTOOL_SYS_OLD_ARCHIVE])])
+m4_ifndef([_LT_AC_TRY_DLOPEN_SELF], [AC_DEFUN([_LT_AC_TRY_DLOPEN_SELF])])
+m4_ifndef([AC_LIBTOOL_PROG_CC_C_O], [AC_DEFUN([AC_LIBTOOL_PROG_CC_C_O])])
+m4_ifndef([AC_LIBTOOL_SYS_HARD_LINK_LOCKS], [AC_DEFUN([AC_LIBTOOL_SYS_HARD_LINK_LOCKS])])
+m4_ifndef([AC_LIBTOOL_OBJDIR], [AC_DEFUN([AC_LIBTOOL_OBJDIR])])
+m4_ifndef([AC_LTDL_OBJDIR], [AC_DEFUN([AC_LTDL_OBJDIR])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH], [AC_DEFUN([AC_LIBTOOL_PROG_LD_HARDCODE_LIBPATH])])
+m4_ifndef([AC_LIBTOOL_SYS_LIB_STRIP], [AC_DEFUN([AC_LIBTOOL_SYS_LIB_STRIP])])
+m4_ifndef([AC_PATH_MAGIC], [AC_DEFUN([AC_PATH_MAGIC])])
+m4_ifndef([AC_PROG_LD_GNU], [AC_DEFUN([AC_PROG_LD_GNU])])
+m4_ifndef([AC_PROG_LD_RELOAD_FLAG], [AC_DEFUN([AC_PROG_LD_RELOAD_FLAG])])
+m4_ifndef([AC_DEPLIBS_CHECK_METHOD], [AC_DEFUN([AC_DEPLIBS_CHECK_METHOD])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_NO_RTTI], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_NO_RTTI])])
+m4_ifndef([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE], [AC_DEFUN([AC_LIBTOOL_SYS_GLOBAL_SYMBOL_PIPE])])
+m4_ifndef([AC_LIBTOOL_PROG_COMPILER_PIC], [AC_DEFUN([AC_LIBTOOL_PROG_COMPILER_PIC])])
+m4_ifndef([AC_LIBTOOL_PROG_LD_SHLIBS], [AC_DEFUN([AC_LIBTOOL_PROG_LD_SHLIBS])])
+m4_ifndef([AC_LIBTOOL_POSTDEP_PREDEP], [AC_DEFUN([AC_LIBTOOL_POSTDEP_PREDEP])])
+m4_ifndef([LT_AC_PROG_EGREP], [AC_DEFUN([LT_AC_PROG_EGREP])])
+m4_ifndef([LT_AC_PROG_SED], [AC_DEFUN([LT_AC_PROG_SED])])
+m4_ifndef([_LT_CC_BASENAME], [AC_DEFUN([_LT_CC_BASENAME])])
+m4_ifndef([_LT_COMPILER_BOILERPLATE], [AC_DEFUN([_LT_COMPILER_BOILERPLATE])])
+m4_ifndef([_LT_LINKER_BOILERPLATE], [AC_DEFUN([_LT_LINKER_BOILERPLATE])])
+m4_ifndef([_AC_PROG_LIBTOOL], [AC_DEFUN([_AC_PROG_LIBTOOL])])
+m4_ifndef([AC_LIBTOOL_SETUP], [AC_DEFUN([AC_LIBTOOL_SETUP])])
+m4_ifndef([_LT_AC_CHECK_DLFCN], [AC_DEFUN([_LT_AC_CHECK_DLFCN])])
+m4_ifndef([AC_LIBTOOL_SYS_DYNAMIC_LINKER], [AC_DEFUN([AC_LIBTOOL_SYS_DYNAMIC_LINKER])])
+m4_ifndef([_LT_AC_TAGCONFIG], [AC_DEFUN([_LT_AC_TAGCONFIG])])
+m4_ifndef([AC_DISABLE_FAST_INSTALL], [AC_DEFUN([AC_DISABLE_FAST_INSTALL])])
+m4_ifndef([_LT_AC_LANG_CXX], [AC_DEFUN([_LT_AC_LANG_CXX])])
+m4_ifndef([_LT_AC_LANG_F77], [AC_DEFUN([_LT_AC_LANG_F77])])
+m4_ifndef([_LT_AC_LANG_GCJ], [AC_DEFUN([_LT_AC_LANG_GCJ])])
+m4_ifndef([AC_LIBTOOL_LANG_C_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_C_CONFIG])])
+m4_ifndef([_LT_AC_LANG_C_CONFIG], [AC_DEFUN([_LT_AC_LANG_C_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_CXX_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_CXX_CONFIG])])
+m4_ifndef([_LT_AC_LANG_CXX_CONFIG], [AC_DEFUN([_LT_AC_LANG_CXX_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_F77_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_F77_CONFIG])])
+m4_ifndef([_LT_AC_LANG_F77_CONFIG], [AC_DEFUN([_LT_AC_LANG_F77_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_GCJ_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_GCJ_CONFIG])])
+m4_ifndef([_LT_AC_LANG_GCJ_CONFIG], [AC_DEFUN([_LT_AC_LANG_GCJ_CONFIG])])
+m4_ifndef([AC_LIBTOOL_LANG_RC_CONFIG], [AC_DEFUN([AC_LIBTOOL_LANG_RC_CONFIG])])
+m4_ifndef([_LT_AC_LANG_RC_CONFIG], [AC_DEFUN([_LT_AC_LANG_RC_CONFIG])])
+m4_ifndef([AC_LIBTOOL_CONFIG], [AC_DEFUN([AC_LIBTOOL_CONFIG])])
+m4_ifndef([_LT_AC_FILE_LTDLL_C], [AC_DEFUN([_LT_AC_FILE_LTDLL_C])])
+m4_ifndef([_LT_REQUIRED_DARWIN_CHECKS], [AC_DEFUN([_LT_REQUIRED_DARWIN_CHECKS])])
+m4_ifndef([_LT_AC_PROG_CXXCPP], [AC_DEFUN([_LT_AC_PROG_CXXCPP])])
+m4_ifndef([_LT_PREPARE_SED_QUOTE_VARS], [AC_DEFUN([_LT_PREPARE_SED_QUOTE_VARS])])
+m4_ifndef([_LT_PROG_ECHO_BACKSLASH], [AC_DEFUN([_LT_PROG_ECHO_BACKSLASH])])
+m4_ifndef([_LT_PROG_F77], [AC_DEFUN([_LT_PROG_F77])])
+m4_ifndef([_LT_PROG_FC], [AC_DEFUN([_LT_PROG_FC])])
+m4_ifndef([_LT_PROG_CXX], [AC_DEFUN([_LT_PROG_CXX])])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_BISON], [
+ AC_REQUIRE([AC_PROG_YACC])
+ AC_REQUIRE([AC_PROG_EGREP])
+
+ AC_CACHE_CHECK([if bison is the parser generator],[pdns_cv_prog_bison],[
+ AS_IF([$YACC --version 2>/dev/null | $EGREP -q '^bison '],
+ [pdns_cv_prog_bison=yes], [pdns_cv_prog_bison=no])
+ ])
+
+ AS_IF([test "x$pdns_cv_prog_bison" = "xno"], [
+ AS_IF([test ! -f "${srcdir}/pdns/bindparser.cc"],
+ [AC_MSG_ERROR([bison is missing and you don't have ${srcdir}/pdns/bindparser.cc. Please install bison])]
+ )]
+ )
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_CDB],[
+ PKG_CHECK_MODULES([CDB], [libcdb],
+ [],
+ [AC_CHECK_HEADERS([cdb.h],
+ [AC_CHECK_LIB([cdb], [cdb_find],
+ [CDB_LIBS="-lcdb"],
+ [AC_MSG_ERROR([Could not find libcdb])]
+ )],
+ [AC_MSG_ERROR([Could not find cdb.h])]
+ )]
+ )
+ AC_SUBST(CDB_LIBS)
+ AC_SUBST(CDB_CFLAGS)
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_CLOCK_GETTIME],[
+ OLD_LIBS="$LIBS"; LIBS=""
+ AC_SEARCH_LIBS([clock_gettime], [rt], [AC_DEFINE(HAVE_CLOCK_GETTIME, [1], [Define to 1 if you have clock_gettime])])
+ AC_SUBST([RT_LIBS],[$LIBS])
+ LIBS="$OLD_LIBS"
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_CURL_PROGRAM], [
+ AC_CHECK_PROG([CURL], [curl], [curl], [no])
+
+ AS_IF([test "x$CURL" = "xno"], [
+ AC_MSG_ERROR([curl program is missing, required for running remotebackend unit tests])
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_FLEX], [
+ AC_REQUIRE([AC_PROG_LEX])
+ AC_REQUIRE([AC_PROG_EGREP])
+
+ AC_CACHE_CHECK([if the lexer is flex],[pdns_cv_prog_flex],[
+ AS_IF([$LEX --version 2>/dev/null | $EGREP -q '^flex '],
+ [pdns_cv_prog_flex=yes], [pdns_cv_prog_flex=no])
+ ])
+
+ AS_IF([test "x$pdns_cv_prog_flex" = "xno"], [
+ AS_IF([test ! -f "${srcdir}/pdns/bindlexer.c"],
+ [AC_MSG_ERROR([flex is missing and you don't have ${srcdir}/pdns/bindlexer.c. Please install flex])]
+ )]
+ )
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_LDAP],[
+ AC_CHECK_HEADERS([ldap.h],
+ [],
+ [AC_MSG_ERROR([ldap header (ldap.h) not found])]
+ )
+
+ AC_CHECK_HEADERS([lber.h],
+ [],
+ [AC_MSG_ERROR([ldap header (lber.h) not found])]
+ )
+
+ AC_CHECK_LIB([ldap_r], [ldap_set_option],
+ [
+ AC_DEFINE([HAVE_LIBLDAP_R], [1], [Have -lldap_r])
+ LIBLDAP="ldap_r"
+ LDAP_LIBS="-lldap_r -llber"
+ ],
+ [
+ AC_CHECK_LIB([ldap], [ldap_set_option],
+ [
+ AC_DEFINE([HAVE_LIBLDAP], 1, [Have -lldap])
+ LIBLDAP="ldap"
+ LDAP_LIBS="-lldap -llber"
+ ],
+ [AC_MSG_ERROR([ldap library (libldap) not found])]
+ )
+ ]
+ )
+
+ AC_CHECK_LIB([$LIBLDAP], [ldap_initialize],
+ [AC_DEFINE([HAVE_LDAP_INITIALIZE], 1, [Define to 1 if you have ldap_initialize])]
+ )
+
+ AC_CHECK_LIB([$LIBLDAP], [ldap_sasl_bind],
+ [AC_DEFINE([HAVE_LDAP_SASL_BIND], 1, [Define to 1 if you have ldap_sasl_bind])]
+ )
+
+ AC_ARG_VAR([LDAP_LIBS], [linker flags for openldap])
+])
--- /dev/null
+# SYNOPSIS
+#
+# PDNS_CHECK_LIBCRYPTO([action-if-found[, action-if-not-found]])
+#
+# DESCRIPTION
+#
+# Look for OpenSSL's libcrypto in a number of default spots, or in a
+# user-selected spot (via --with-libcrypto). Sets
+#
+# LIBCRYPTO_INCLUDES to the include directives required
+# LIBCRYPTO_LIBS to the -l directives required
+# LIBCRYPTO_LDFLAGS to the -L or -R flags required
+#
+# and calls ACTION-IF-FOUND or ACTION-IF-NOT-FOUND appropriately
+#
+# This macro sets LIBCRYPTO_INCLUDES such that source files should use the
+# openssl/ directory in include directives:
+#
+# #include <openssl/hmac.h>
+#
+# LICENSE
+#
+# Taken and modified from AX_CHECK_OPENSSL by:
+# Copyright (c) 2009,2010 Zmanda Inc. <http://www.zmanda.com/>
+# Copyright (c) 2009,2010 Dustin J. Mitchell <dustin@zmanda.com>
+#
+# Copying and distribution of this file, with or without modification, are
+# permitted in any medium without royalty provided the copyright notice
+# and this notice are preserved. This file is offered as-is, without any
+# warranty.
+
+#serial 1
+
+AU_ALIAS([CHECK_LIBCRYPTO], [PDNS_CHECK_LIBCRYPTO])
+AC_DEFUN([PDNS_CHECK_LIBCRYPTO], [
+ found=false
+ AC_ARG_WITH([libcrypto],
+ [AS_HELP_STRING([--with-libcrypto=DIR],
+ [root of the OpenSSL directory])],
+ [
+ case "$withval" in
+ "" | y | ye | yes | n | no)
+ AC_MSG_ERROR([Invalid --with-libcrypto value])
+ ;;
+ *) ssldirs="$withval"
+ ;;
+ esac
+ ], [
+ # if pkg-config is installed and openssl has installed a .pc file,
+ # then use that information and don't search ssldirs
+ AC_CHECK_TOOL([PKG_CONFIG], [pkg-config])
+ if test x"$PKG_CONFIG" != x""; then
+ LIBCRYPTO_LDFLAGS=`$PKG_CONFIG libcrypto --libs-only-L 2>/dev/null`
+ if test $? = 0; then
+ LIBCRYPTO_LIBS=`$PKG_CONFIG libcrypto --libs-only-l 2>/dev/null`
+ LIBCRYPTO_INCLUDES=`$PKG_CONFIG libcrypto --cflags-only-I 2>/dev/null`
+ ssldir=`$PKG_CONFIG libcrypto --variable=prefix 2>/dev/null`
+ found=true
+ fi
+ fi
+
+ # no such luck; use some default ssldirs
+ if ! $found; then
+ ssldirs="/usr/local/ssl /usr/lib/ssl /usr/ssl /usr/pkg /usr/local /usr"
+ fi
+ ]
+ )
+
+
+ # note that we #include <openssl/foo.h>, so the OpenSSL headers have to be in
+ # an 'openssl' subdirectory
+
+ if ! $found; then
+ LIBCRYPTO_INCLUDES=
+ for ssldir in $ssldirs; do
+ AC_MSG_CHECKING([for openssl/crypto.h in $ssldir])
+ if test -f "$ssldir/include/openssl/crypto.h"; then
+ LIBCRYPTO_INCLUDES="-I$ssldir/include"
+ LIBCRYPTO_LDFLAGS="-L$ssldir/lib"
+ LIBCRYPTO_LIBS="-lcrypto"
+ found=true
+ AC_MSG_RESULT([yes])
+ break
+ else
+ AC_MSG_RESULT([no])
+ fi
+ done
+
+ # if the file wasn't found, well, go ahead and try the link anyway -- maybe
+ # it will just work!
+ fi
+
+ # try the preprocessor and linker with our new flags,
+ # being careful not to pollute the global LIBS, LDFLAGS, and CPPFLAGS
+
+ AC_MSG_CHECKING([whether compiling and linking against OpenSSL's libcrypto works])
+ echo "Trying link with LIBCRYPTO_LDFLAGS=$LIBCRYPTO_LDFLAGS;" \
+ "LIBCRYPTO_LIBS=$LIBCRYPTO_LIBS; LIBCRYPTO_INCLUDES=$LIBCRYPTO_INCLUDES" >&AS_MESSAGE_LOG_FD
+
+ save_LIBS="$LIBS"
+ save_LDFLAGS="$LDFLAGS"
+ save_CPPFLAGS="$CPPFLAGS"
+ LDFLAGS="$LDFLAGS $LIBCRYPTO_LDFLAGS"
+ LIBS="$LIBCRYPTO_LIBS $LIBS"
+ CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS"
+ AC_LINK_IFELSE(
+ [AC_LANG_PROGRAM([#include <openssl/crypto.h>], [ERR_load_CRYPTO_strings()])],
+ [
+ AC_MSG_RESULT([yes])
+ $1
+ ], [
+ AC_MSG_RESULT([no])
+ $2
+ ])
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+
+ AC_SUBST([LIBCRYPTO_INCLUDES])
+ AC_SUBST([LIBCRYPTO_LIBS])
+ AC_SUBST([LIBCRYPTO_LDFLAGS])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_LIBCRYPTO_ECDSA], [
+ AC_REQUIRE([PDNS_CHECK_LIBCRYPTO])
+
+ # Set the environment correctly for a possibly non-default OpenSSL path that was found by/supplied to PDNS_CHECK_LIBCRYPTO
+ save_CPPFLAGS="$CPPFLAGS"
+ save_LDFLAGS="$LDFLAGS"
+ save_LIBS="$LIBS"
+
+ CPPFLAGS="$LIBCRYPTO_INCLUDES $CPPFLAGS"
+ LDFLAGS="$LIBCRYPTO_LDFLAGS $LDFLAGS"
+ LIBS="$LIBCRYPTO_LIBS $LIBS"
+
+ # Find the headers we need for ECDSA
+ libcrypto_ecdsa=yes
+ AC_CHECK_HEADER([$ssldir/include/openssl/ecdsa.h], [
+ AC_CHECK_DECLS([NID_X9_62_prime256v1, NID_secp384r1], [ : ], [
+ libcrypto_ecdsa=no
+ ], [AC_INCLUDES_DEFAULT
+#include <$ssldir/include/openssl/evp.h>
+ ])
+ ], [
+ libcrypto_ecdsa=no
+ ])
+
+ AS_IF([test "x$libcrypto_ecdsa" = "xyes"], [
+ AC_DEFINE([HAVE_LIBCRYPTO_ECDSA], [1], [define to 1 if OpenSSL ecdsa support is available.])
+ ])
+
+ # Restore variables
+ CPPFLAGS="$save_CPPFLAGS"
+ LDFLAGS="$save_LDFLAGS"
+ LIBS="$save_LIBS"
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_LIBDECAF],[
+ AC_MSG_CHECKING([whether we will be linking in libdecaf])
+ AC_ARG_ENABLE([libdecaf],
+ [AS_HELP_STRING([--enable-libdecaf],[use libdecaf @<:@default=no@:>@])],
+ [enable_libdecaf=$enableval],
+ [enable_libdecaf=no]
+ )
+ AC_MSG_RESULT([$enable_libdecaf])
+
+ AM_CONDITIONAL([LIBDECAF],[test "x$enable_libdecaf" != "xno"])
+
+ AS_IF([test "x$enable_libdecaf" != "xno"],[
+ save_LIBS=$LIBS
+ LIBS=""
+ AC_SEARCH_LIBS([decaf_ed25519_sign],[decaf],[
+ AC_DEFINE([HAVE_LIBDECAF],[1],[Define to 1 if you have libdecaf])
+ AC_SUBST([LIBDECAF_LIBS],["$LIBS"])
+ ],[
+ AC_MSG_ERROR([Could not find libdecaf])
+ ])
+ LIBS="$save_LIBS"
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_LIBSODIUM], [
+ AC_MSG_CHECKING([whether we will be linking in libsodium])
+ AC_ARG_ENABLE([libsodium],
+ AS_HELP_STRING([--enable-libsodium],[use libsodium @<:@default=no@:>@]),
+ [enable_libsodium=$enableval],
+ [enable_libsodium=no],
+ )
+ AC_MSG_RESULT([$enable_libsodium])
+
+ AM_CONDITIONAL([LIBSODIUM], [test "x$enable_libsodium" != "xno"])
+
+ AM_COND_IF([LIBSODIUM], [
+ PKG_CHECK_MODULES([LIBSODIUM], [libsodium], [
+ AC_DEFINE([HAVE_LIBSODIUM], [1], [Define to 1 if you have libsodium])
+ ],[
+ AC_MSG_ERROR([libsodium requested but not available])
+ ])
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_LUA_HPP],[
+ AC_REQUIRE([PDNS_WITH_LUA])
+ AC_REQUIRE([PDNS_WITH_LUAJIT])
+ AS_IF([test "x$LUAPC" != "x" -o "x$LUAJITPC" != "x" ], [
+ AC_CHECK_HEADER([lua.hpp], [ have_lua_hpp=y ])
+ ])
+ AM_CONDITIONAL([HAVE_LUA_HPP], [ test x"$have_lua_hpp" = "xy" ])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_NETWORK_LIBS],[
+ AC_SEARCH_LIBS([inet_aton], [resolv])
+ AC_SEARCH_LIBS([gethostbyname], [nsl])
+ AC_SEARCH_LIBS([socket], [socket])
+ AC_SEARCH_LIBS([gethostent], [nsl])
+])
+
--- /dev/null
+AC_DEFUN([PDNS_CHECK_OPENDBX], [
+ PKG_CHECK_MODULES([OPENDBX], [opendbx], [], [
+ AC_CHECK_HEADERS([odbx.h], [
+ AC_CHECK_LIB([opendbx], [odbx_init],
+ [OPENDBX_LIBS="-lopendbx"],
+ [AC_MSG_ERROR([libopendbx not found])]
+ )], [
+ AC_MSG_ERROR([opendbx header (odbx.h) not found])
+ ]
+ )
+ ])
+ AC_SUBST([OPENDBX_LIBS])
+])
+
--- /dev/null
+AC_DEFUN([PDNS_CHECK_OS],[
+ THREADFLAGS=""
+
+ case "$host_os" in
+ solaris2.1*)
+ LIBS="-lposix4 -lpthread $LIBS"
+ CXXFLAGS="-D_REENTRANT $CXXFLAGS"
+ have_solaris="yes"
+ ;;
+ solaris2.8 | solaris2.9 )
+ AC_DEFINE(NEED_POSIX_TYPEDEF,,[If POSIX typedefs need to be defined])
+ AC_DEFINE(NEED_INET_NTOP_PROTO,,[If your OS is so broken that it needs an additional prototype])
+ LIBS="-lposix4 -lpthread $LIBS"
+ CXXFLAGS="-D_REENTRANT $CXXFLAGS"
+ have_solaris="yes"
+ ;;
+ linux*)
+ THREADFLAGS="-pthread"
+ have_linux="yes"
+ ;;
+ darwin*)
+ CXXFLAGS="-D__APPLE_USE_RFC_3542 -D_XOPEN_SOURCE $CXXFLAGS"
+ ;;
+ freebsd*)
+ THREADFLAGS="-pthread"
+ have_freebsd="yes"
+ ;;
+ *)
+ LDFLAGS="-pthread $LDFLAGS"
+ CXXFLAGS="-pthread $CXXFLAGS"
+ ;;
+ esac
+
+ AM_CONDITIONAL([HAVE_FREEBSD], [test "x$have_freebsd" = "xyes"])
+ AM_CONDITIONAL([HAVE_LINUX], [test "x$have_linux" = "xyes"])
+ AM_CONDITIONAL([HAVE_SOLARIS], [test "x$have_solaris" = "xyes"])
+
+ case "$host" in
+ mips* | powerpc* )
+ AX_CHECK_LINK_FLAG([-latomic],
+ [ : ],
+ [ AC_MSG_ERROR([Unable to link against libatomic, cannot continue]) ]
+ )
+ LDFLAGS="-latomic $LDFLAGS"
+ ;;
+ esac
+
+ AC_SUBST(THREADFLAGS)
+ AC_SUBST([DYNLINKFLAGS], [-export-dynamic])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_PANDOC], [
+ AC_CHECK_PROG([PANDOC], [pandoc], [pandoc], [no])
+
+ AS_IF([test "x$PANDOC" = "xno"], [
+ AS_IF([test ! -d "$srcdir/docs/html" -o ! -f "$srcdir/docs/pdns_server.1"],
+ [AC_MSG_WARN([pandoc is missing, unable to build documentation and manpages.])]
+ )
+ ])
+ AM_CONDITIONAL([HAVE_PANDOC], [test "x$PANDOC" != "xno"])
+ AM_CONDITIONAL([HAVE_MANPAGES], [test -e "$srcdir/docs/pdns_server.1"])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_RAGEL], [
+ AC_CHECK_PROG([RAGEL], [ragel], [ragel])
+ if test "x$RAGEL" = "x"; then
+ if test ! -f "${srcdir}/pdns/dnslabeltext.cc"; then
+ AC_MSG_ERROR([ragel is missing and you don't have ${srcdir}/pdns/dnslabeltext.cc. Install ragel or download sources from www.powerdns.com])
+ fi
+ fi
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_SQLITE3], [
+ AS_IF([test "x$needsqlite3" = "xyes"], [
+ PKG_CHECK_MODULES([SQLITE3], [sqlite3],
+ [AC_DEFINE([HAVE_SQLITE3], [1], [Define to 1 if you have sqlite3])],
+ [AC_MSG_ERROR([Could not find libsqlite3])]
+ )
+ ])
+])
--- /dev/null
+dnl
+dnl Check for support D_FORTIFY_SOURCE
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_CC_D_FORTIFY_SOURCE],[
+ OLD_CXXFLAGS="$CXXFLAGS"
+ CXXFLAGS="-Wall -W -Werror $CXXFLAGS"
+ gl_COMPILER_OPTION_IF([-D_FORTIFY_SOURCE=2], [
+ CFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $CFLAGS"
+ CXXFLAGS="-U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=2 $OLD_CXXFLAGS"
+ ], [CXXFLAGS="$OLD_CXXFLAGS"], [AC_LANG_PROGRAM([[#include <stdio.h>]],[])])
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_BOTAN],[
+ AC_MSG_CHECKING([whether we will be linking in Botan 1.10])
+ AC_ARG_ENABLE([botan1.10],
+ [AS_HELP_STRING([--enable-botan1.10],[use Botan 1.10 @<:@default=no@:>@])],
+ [enable_botan110=$enableval],
+ [enable_botan110=no]
+ )
+ AC_MSG_RESULT([$enable_botan110])
+ AM_CONDITIONAL(BOTAN110, [test "x$enable_botan110" != "xno"])
+
+
+ AS_IF([test "x$enable_botan110" != "xno"], [
+ PKG_CHECK_MODULES([BOTAN110], [botan-1.10],
+ [AC_DEFINE([HAVE_BOTAN110],[1],[Define to 1 if you have botan 1.10])],
+ [AC_MSG_ERROR([Could not find botan 1.10])]
+ )]
+ )
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_COVERAGE], [
+ AC_MSG_CHECKING([whether to enable code coverage])
+ AC_ARG_ENABLE([coverage],
+ AS_HELP_STRING([--enable-coverage],
+ [enable code coverage @<:@default=no@:>@]),
+ [enable_coverage=$enableval],
+ [enable_coverage=no]
+ )
+ AC_MSG_RESULT([$enable_coverage])
+ AS_IF([test "x$enable_coverage" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fprofile-arcs -ftest-coverage], [
+ CXXFLAGS="$CXXFLAGS -U_FORTIFY_SOURCE -g -O0 -fprofile-arcs -ftest-coverage"
+ ], [
+ AC_MSG_ERROR([$CXX does not support gathering coverage data])
+ ])
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_GSS_TSIG],[
+ AC_MSG_CHECKING([whether to enable experimental GSS-TSIG support])
+ AC_ARG_ENABLE([experimental_gss_tsig],
+ AS_HELP_STRING([--enable-experimental-gss-tsig],
+ [enable experimental GSS-TSIG support @<:@default=no@:>@]
+ ),
+ [enable_experimental_gss_tsig=$enableval],
+ [enable_experimental_gss_tsig=no]
+ )
+
+ AC_MSG_RESULT([$enable_experimental_gss_tsig])
+
+ AM_CONDITIONAL([GSS_TSIG],[test "x$enable_experimental_gss_tsig" != "xno"])
+ AC_SUBST(GSS_TSIG)
+ AS_IF([test "x$enable_experimental_gss_tsig" != "xno"],
+ [PKG_CHECK_MODULES([GSS], [krb5 krb5-gssapi gss],
+ [
+ AC_DEFINE([ENABLE_GSS_TSIG], [1], [Define to 1 if you want to enable GSS-TSIG support])
+ GSS_TSIG=yes
+ ],
+ [AC_MSG_ERROR([Required libraries for GSS-TSIG not found])]
+ )],
+ [GSS_TSIG=no])
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_MALLOC_TRACE], [
+ AC_MSG_CHECKING([whether to enable code malloc-trace])
+ AC_ARG_ENABLE([malloc-trace],
+ AS_HELP_STRING([--enable-malloc-trace],
+ [enable malloc-trace @<:@default=no@:>@]),
+ [enable_malloc_trace=$enableval],
+ [enable_malloc_trace=no]
+ )
+ AC_MSG_RESULT([$enable_malloc_trace])
+ AM_CONDITIONAL([MALLOC_TRACE], [test "x$enable_malloc_trace" = "xyes"])
+ AS_IF([test "x$enable_malloc_trace" = "xyes"],
+ AC_DEFINE([MALLOC_TRACE], [1], [Define to 1 if you want to benefit from malloc trace]) )
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_PKCS11],[
+ AC_MSG_CHECKING([whether to enable PKCS11 support])
+ AC_ARG_ENABLE([experimental-pkcs11],
+ [AS_HELP_STRING([--enable-experimental-pkcs11],[enable experimental PKCS11 support @<:@default=no@:>@])],
+ [enable_pkcs11=$enableval],
+ [enable_pkcs11=no]
+ )
+ AC_MSG_RESULT([$enable_pkcs11])
+ AM_CONDITIONAL([PKCS11], [test "x$enable_pkcs11" != "xno"])
+
+ AS_IF([test "x$enable_pkcs11" != "xno"], [
+ PKG_CHECK_MODULES([P11KIT1], [p11-kit-1],
+ [
+ AC_DEFINE([HAVE_P11KIT1],[1],[Define to 1 if you have p11-kit-1])
+ AC_CHECK_LIB([p11-kit], [p11_kit_module_for_name], [AC_DEFINE([HAVE_P11KIT1_V2],[1],[Define to 1 if you have 0.20 or newer P11-kit])], [], [$P11KIT1_LIBS])
+ ],
+ [AC_MSG_ERROR([Could not find p11-kit-1])]
+ )]
+ )
+
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_REMOTEBACKEND_ZEROMQ],[
+ AC_MSG_CHECKING([whether to enable ZeroMQ connector in remotebackend])
+ AC_ARG_ENABLE([remotebackend_zeromq],
+ AS_HELP_STRING([--enable-remotebackend-zeromq],
+ [enable ZeroMQ connector for remotebackend @<:@default=no@:>@]
+ ),
+ [enable_remotebackend_zeromq=$enableval],
+ [enable_remotebackend_zeromq=no]
+ )
+
+ AC_MSG_RESULT([$enable_remotebackend_zeromq])
+
+ AM_CONDITIONAL([REMOTEBACKEND_ZEROMQ],[test "x$enable_remotebackend_zeromq" != "xno"])
+ AC_SUBST(REMOTEBACKEND_ZEROMQ)
+
+ AS_IF([test "x$enable_remotebackend_zeromq" != "xno"],
+ [
+ AS_IF([test "x$have_remotebackend" = "xyes"],
+ [
+ PKG_CHECK_MODULES([LIBZMQ], [libzmq],
+ [
+ AC_DEFINE([HAVE_LIBZMQ], [1], [Define to 1 if you have libzmq])
+ AC_DEFINE([REMOTEBACKEND_ZEROMQ], [1], [Define to 1 if you have the ZeroMQ connector])
+ REMOTEBACKEND_ZEROMQ=yes
+ ],
+ [AC_MSG_ERROR([Could not find libzmq])]
+ )
+
+ old_CXXFLAGS="$CXXFLAGS"
+ old_LDFLAGS="$LDFLAGS"
+ CXXFLAGS="$CFLAGS $LIBZMQ_CFLAGS"
+ LDFLAGS="$LDFLAGS $LIBZMQ_LIBS"
+ AC_CHECK_LIB([zmq], [zmq_msg_send],
+ [
+ AC_DEFINE([HAVE_ZMQ_MSG_SEND], [1], [Define to 1 if the ZeroMQ 3.x or greater API is available])
+ ]
+ )
+ CXXFLAGS="$old_CXXFLAGS"
+ LDFLAGS="$old_LDFLAGS"
+ ],
+ [AC_MSG_ERROR([remotebackend \"zeromq\" selected but the \"remote\" backend itself is not selected. Please add \"remote\" to your modules or dynmodules list and re-run configure!])]
+ )
+ ]
+ )
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_REPRODUCIBLE], [
+ AC_REQUIRE([PDNS_CHECK_OS])
+ AC_MSG_CHECKING([whether to enable reproducible builds.])
+ AC_ARG_ENABLE([reproducible],
+ AS_HELP_STRING([--enable-reproducible],
+ [Create reproducible builds. Use this only if you are a distribution maintainer and need reproducible builds. If you compile PowerDNS yourself, leave this disabled, as it might make debugging harder. @<:@default=no@:>@]),
+ [enable_reproducible=$enableval],
+ [enable_reproducible=no])
+
+ AC_MSG_RESULT($enable_reproducible)
+
+ AS_IF([test x"$enable_reproducible" = "xyes"],[
+ AC_DEFINE([REPRODUCIBLE], [1], [Define to 1 for reproducible builds])
+ ],[
+ build_user=$(id -u -n)
+
+ case "$host_os" in
+ solaris2.1* | SunOS | openbsd*)
+ build_host_host=$(hostname)
+ build_host_domain=$(domainname)
+ build_host="$build_host_host.$build_host_domain"
+ ;;
+ *)
+ build_host=$(hostname -f || hostname || echo 'localhost')
+ ;;
+ esac
+ AC_DEFINE_UNQUOTED([BUILD_HOST], ["$build_user@$build_host"], [Set to the user and host that builds PowerDNS])
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_SANITIZERS], [
+ PDNS_ENABLE_ASAN
+ PDNS_ENABLE_MSAN
+ PDNS_ENABLE_TSAN
+ PDNS_ENABLE_LSAN
+ PDNS_ENABLE_UBSAN
+
+ AS_IF([test "x$enable_asan" != "xno" -a "x$enable_tsan" != "xno"],[
+ AC_MSG_ERROR([Address Sanitizer is not compatible with Thread Sanitizer])
+ ])
+
+ AS_IF([test "x$enable_msan" != "xno" -a "x$enable_asan" != "xno"],[
+ AC_MSG_ERROR([Memory Sanitizer is not compatible with Address Sanitizer])
+ ])
+
+ AS_IF([test "x$enable_msan" != "xno" -a "x$enable_lsan" != "xno"],[
+ AC_MSG_ERROR([Memory Sanitizer is not compatible with Leak Sanitizer])
+ ])
+
+ AS_IF([test "x$enable_msan" != "xno" -a "x$enable_tsan" != "xno"],[
+ AC_MSG_ERROR([Memory Sanitizer is not compatible with Thread Sanitizer])
+ ])
+
+ AS_IF([test "x$enable_asan" != "xno" -o "x$enable_tsan" != "xno" -o "x$enable_lsan" != "xno" -o "x$enable_ubsan" != "xno" -o "x$enable_msan" != "xno"], [
+ gl_WARN_ADD([-fno-omit-frame-pointer])
+ ])
+])
+
+AC_DEFUN([PDNS_ENABLE_ASAN], [
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AC_MSG_CHECKING([whether to enable AddressSanitizer])
+ AC_ARG_ENABLE([asan],
+ AS_HELP_STRING([--enable-asan],
+ [enable AddressSanitizer @<:@default=no@:>@]),
+ [enable_asan=$enableval],
+ [enable_asan=no]
+ )
+ AC_MSG_RESULT([$enable_asan])
+
+ AS_IF([test "x$enable_asan" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fsanitize=address],
+ [SANITIZER_FLAGS="-fsanitize=address $SANITIZER_FLAGS"],
+ [AC_MSG_ERROR([Cannot enable AddressSanitizer])]
+ )
+ ])
+ AC_SUBST([SANITIZER_FLAGS])
+])
+
+AC_DEFUN([PDNS_ENABLE_TSAN], [
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AC_MSG_CHECKING([whether to enable ThreadSanitizer])
+ AC_ARG_ENABLE([tsan],
+ AS_HELP_STRING([--enable-tsan],
+ [enable ThreadSanitizer @<:@default=no@:>@]),
+ [enable_tsan=$enableval],
+ [enable_tsan=no]
+ )
+ AC_MSG_RESULT([$enable_tsan])
+
+ AS_IF([test "x$enable_tsan" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fsanitize=thread],
+ [SANITIZER_FLAGS="-fsanitize=thread $SANITIZER_FLAGS"],
+ [AC_MSG_ERROR([Cannot enable ThreadSanitizer])]
+ )
+ ])
+ AC_SUBST([SANITIZER_FLAGS])
+])
+
+AC_DEFUN([PDNS_ENABLE_LSAN], [
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AC_MSG_CHECKING([whether to enable LeakSanitizer])
+ AC_ARG_ENABLE([lsan],
+ AS_HELP_STRING([--enable-lsan],
+ [enable LeakSanitizer @<:@default=no@:>@]),
+ [enable_lsan=$enableval],
+ [enable_lsan=no]
+ )
+ AC_MSG_RESULT([$enable_lsan])
+
+ AS_IF([test "x$enable_lsan" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fsanitize=leak],
+ [SANITIZER_FLAGS="-fsanitize=leak $SANITIZER_FLAGS"],
+ [AC_MSG_ERROR([Cannot enable LeakSanitizer])]
+ )
+ ])
+ AC_SUBST([SANITIZER_FLAGS])
+])
+
+AC_DEFUN([PDNS_ENABLE_UBSAN], [
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AC_MSG_CHECKING([whether to enable Undefined Behaviour Sanitizer])
+ AC_ARG_ENABLE([ubsan],
+ AS_HELP_STRING([--enable-ubsan],
+ [enable Undefined Behaviour Sanitizer @<:@default=no@:>@]),
+ [enable_ubsan=$enableval],
+ [enable_ubsan=no]
+ )
+ AC_MSG_RESULT([$enable_ubsan])
+
+ AS_IF([test "x$enable_ubsan" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fsanitize=undefined],
+ [SANITIZER_FLAGS="-fsanitize=undefined $SANITIZER_FLAGS"],
+ [AC_MSG_ERROR([Cannot enable Undefined Behaviour Sanitizer])]
+ )
+ ])
+ AC_SUBST([SANITIZER_FLAGS])
+])
+
+AC_DEFUN([PDNS_ENABLE_MSAN], [
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ AC_MSG_CHECKING([whether to enable MemorySanitizer])
+ AC_ARG_ENABLE([msan],
+ AS_HELP_STRING([--enable-msan],
+ [enable MemorySanitizer @<:@default=no@:>@]),
+ [enable_msan=$enableval],
+ [enable_msan=no]
+ )
+ AC_MSG_RESULT([$enable_msan])
+
+ AS_IF([test "x$enable_msan" != "xno"], [
+ gl_COMPILER_OPTION_IF([-fsanitize=memory],
+ [SANITIZER_FLAGS="-fsanitize=memory $SANITIZER_FLAGS"],
+ [AC_MSG_ERROR([Cannot enable MemorySanitizer])]
+ )
+ ])
+ AC_SUBST([SANITIZER_FLAGS])
+])
+
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_UNIT_TESTS], [
+ AC_MSG_CHECKING([whether to enable unit test building])
+ AC_ARG_ENABLE([unit-tests],
+ AS_HELP_STRING([--enable-unit-tests],
+ [enable unit test building @<:@default=no@:>@]),
+ [enable_unit_tests=$enableval],
+ [enable_unit_tests=no]
+ )
+ AC_MSG_RESULT([$enable_unit_tests])
+ AM_CONDITIONAL([UNIT_TESTS], [test "x$enable_unit_tests" != "xno"])
+
+ AC_MSG_CHECKING([whether to enable backend unit test building])
+ AC_ARG_ENABLE([backend-unit-tests],
+ AS_HELP_STRING([--enable-backend-unit-tests],
+ [enable backend unit test building @<:@default=no@:>@]),
+ [enable_backend_unit_tests=$enableval],
+ [enable_backend_unit_tests=no]
+ )
+ AC_MSG_RESULT([$enable_backend_unit_tests])
+ AM_CONDITIONAL([BACKEND_UNIT_TESTS], [test "x$enable_backend_unit_tests" != "xno"])
+
+ AS_IF([test "x$enable_unit_tests" != "xno" || test "x$enable_backend_unit_tests" != "xno"], [
+ BOOST_TEST([mt])
+ AS_IF([test "$boost_cv_lib_unit_test_framework" = "no"], [
+ AC_MSG_ERROR([Boost Unit Test library not found])
+ ])
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_ENABLE_VERBOSE_LOGGING],[
+ AC_MSG_CHECKING([whether to enable verbose logging])
+
+ AC_ARG_ENABLE([verbose-logging],
+ AS_HELP_STRING([--enable-verbose-logging],
+ [enable verbose logging @<:@default=no@:>@]
+ ),
+ [enable_verbose_logging=$enableval],
+ [enable_verbose_logging=no]
+ )
+
+ AS_IF([test "x$enable_verbose_logging" != "xno"],
+ [AC_DEFINE([VERBOSELOG], [1], [Define to 1 if verbose logging is enabled])]
+ )
+
+ AC_MSG_RESULT([$enable_verbose_logging])
+])
--- /dev/null
+AC_DEFUN([PDNS_FROM_GIT], [
+ AM_CONDITIONAL([FROM_GIT], [test -d "$srcdir/.git"])
+])
--- /dev/null
+dnl
+dnl Check for support for ssp parameter buffer size
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_CC_PARAM_SSP_BUFFER_SIZE],[
+ gl_COMPILER_OPTION_IF([--param ssp-buffer-size=$1], [
+ CFLAGS="--param ssp-buffer-size=$1 $CFLAGS"
+ CXXFLAGS="--param ssp-buffer-size=$1 $CXXFLAGS"
+ ])
+])
--- /dev/null
+dnl
+dnl Check for support for position independent executables
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_CC_PIE],[
+ AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+ PIE_CFLAGS=
+ PIE_LDFLAGS=
+ OLD_CXXFLAGS=$CXXFLAGS
+ case "$host" in
+ *-*-mingw* | *-*-msvc* | *-*-cygwin* )
+ ;; dnl All code is position independent on Win32 target
+ *)
+ CXXFLAGS="-fPIE -DPIE"
+ gl_COMPILER_OPTION_IF([-pie], [
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-pie"
+ ], [
+ dnl some versions of clang require -Wl,-pie instead of -pie
+ gl_COMPILER_OPTION_IF([[-Wl,-pie]], [
+ PIE_CFLAGS="-fPIE -DPIE"
+ PIE_LDFLAGS="-Wl,-pie"
+ ], [],
+ [AC_LANG_PROGRAM([[
+#include <pthread.h>
+__thread unsigned int t_id;
+ ]], [[t_id = 1;]])]
+ )
+ ],
+ [AC_LANG_PROGRAM([[
+#include <pthread.h>
+__thread unsigned int t_id;
+ ]], [[t_id = 1;]])]
+ )
+ esac
+ CXXFLAGS=$OLD_CXXFLAGS
+ AC_SUBST([PIE_CFLAGS])
+ AC_SUBST([PIE_LDFLAGS])
+])
--- /dev/null
+dnl
+dnl Check for -z now and -z relro linker flags
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_LD_RELRO],[
+ AC_MSG_CHECKING([for how to force completely read-only GOT table])
+
+ RELRO_LDFLAGS=
+ ld_help=`$CXX -Wl,-help 2>&1`
+ case $ld_help in
+ *"-z relro"*) RELRO_LDFLAGS="-Wl,-z -Wl,relro" ;;
+ esac
+ case $ld_help in
+ *"-z now"*) RELRO_LDFLAGS="$RELRO_LDFLAGS -Wl,-z -Wl,now" ;;
+ esac
+ AC_SUBST([RELRO_LDFLAGS])
+ AS_IF([test "x$RELRO_LDFLAGS" != "x"],
+ [AC_MSG_RESULT([$RELRO_LDFLAGS])],
+ [AC_MSG_RESULT([unknown])]
+ )
+])
--- /dev/null
+dnl
+dnl Check for support for enabling stack protector
+dnl
+dnl Copyright (C) 2013 Red Hat, Inc.
+dnl
+dnl This library is free software; you can redistribute it and/or
+dnl modify it under the terms of the GNU Lesser General Public
+dnl License as published by the Free Software Foundation; either
+dnl version 2.1 of the License, or (at your option) any later version.
+dnl
+dnl This library is distributed in the hope that it will be useful,
+dnl but WITHOUT ANY WARRANTY; without even the implied warranty of
+dnl MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+dnl Lesser General Public License for more details.
+dnl
+dnl You should have received a copy of the GNU Lesser General Public
+dnl License along with this library. If not, see
+dnl <http://www.gnu.org/licenses/>.
+dnl
+
+AC_DEFUN([AC_CC_STACK_PROTECTOR],[
+ gl_COMPILER_OPTION_IF([-fstack-protector], [
+ CFLAGS="-fstack-protector $CFLAGS"
+ CXXFLAGS="-fstack-protector $CXXFLAGS"
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_CHECK_GEOIP], [
+ PKG_CHECK_MODULES([GEOIP], [geoip],[],
+ AC_MSG_ERROR([Could not find libGeoIP])
+ )
+ PKG_CHECK_MODULES([YAML], [yaml-cpp >= 0.5],[],
+ AC_MSG_ERROR([Could not find yaml-cpp])
+ )
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_LUA],[
+ AC_MSG_CHECKING([whether we will be linking in Lua])
+ AC_ARG_WITH([lua],
+ [AS_HELP_STRING([--with-lua], [build Lua Bindings @<:@default=auto@:>@])],
+ [with_lua=$withval],
+ [with_lua=auto]
+ )
+ AC_MSG_RESULT([$with_lua])
+
+ AS_IF([test "x$with_lua" != "xno"],[
+ AS_IF([test "x$with_lua" = "xyes" -o "x$with_lua" = "xauto"],
+ [for LUAPC in lua5.3 lua-5.3 lua53 lua5.2 lua-5.2 lua52 lua5.1 lua-5.1 lua51 lua; do
+ PKG_CHECK_MODULES([LUA], $LUAPC >= 5.1, [
+ AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua])
+ with_lua=yes
+ ], [LUAPC=""]) # otherwise pkg_check will fail
+ if test "x$LUA_LIBS" != "x"; then break; fi
+ done
+ ],
+ [LUAPC="$with_lua"
+ PKG_CHECK_MODULES([LUA], $LUAPC >= 5.1, [
+ AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have lua])
+ with_lua=yes
+ ])
+ ])
+ AC_MSG_CHECKING([for chosen LUA])
+ AS_IF([test "x$LUAPC" = "x"], [
+ AS_IF([test "x$with_lua" = "xyes"],
+ [AC_MSG_ERROR([cannot find lua])],
+ [AC_MSG_RESULT([not found])]
+ )],[
+ AC_MSG_RESULT([$LUAPC])
+ ])
+ ])
+ AM_CONDITIONAL([LUA], [test "x$with_lua" = "xyes"])
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_LUAJIT],[
+ AC_MSG_CHECKING([whether we will be linking in LuaJIT])
+ AC_ARG_WITH([luajit],
+ [AS_HELP_STRING([--with-luajit], [build LuaJIT bindings @<:@default=auto@:>@])],
+ [with_luajit=$withval],
+ [with_luajit=no]
+ )
+ AC_MSG_RESULT([$with_luajit])
+
+ AS_IF([test "x$with_luajit" = "xyes"], [
+ LUAJITPC="$with_luajit"
+ PKG_CHECK_MODULES([LUA], [luajit],
+ [AC_DEFINE([HAVE_LUA], [1], [Define to 1 if you have LuaJIT])],
+ [LUAJITPC=""]
+ )
+ AS_IF([test "x$LUAJITPC" = "x"], [
+ AC_MSG_ERROR([LuaJIT not found])]
+ )
+ ])
+
+ AM_CONDITIONAL([LUA], [test "x$with_luajit" = "xyes"])
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_MYSQL],[
+ AC_ARG_WITH([mysql],
+ [AS_HELP_STRING([--with-mysql=<path>], [root directory path of MySQL installation])],
+ [
+ MYSQL_LIBS_check="$withval/lib/mysql $with_mysql/lib"
+ MYSQL_CFLAGS_check="$withval/include/mysql"
+ MYSQL_config_check="$withval/bin/mysql_config"
+ ],
+ [
+ MYSQL_LIBS_check="/usr/local/mysql/lib/mysql /usr/local/lib/mysql /opt/mysql/lib/mysql \
+ /usr/lib/mysql /usr/lib64/mysql /usr/local/mysql/lib /usr/local/lib /opt/mysql/lib /usr/lib \
+ /usr/sfw/lib/ $full_libdir"
+ MYSQL_CFLAGS_check="/usr/local/mysql/include/mysql /usr/local/include/mysql \
+ /opt/mysql/include/mysql /opt/mysql/include /usr/include/mysql /usr/sfw/include/mysql"
+ ]
+ )
+
+ AC_ARG_WITH([mysql-config],
+ [AS_HELP_STRING([--with-mysql-config=<path>], [file path to mysql_config])],
+ [MYSQL_config_check=$withval]
+ )
+
+ AC_ARG_WITH([mysql-lib],
+ [AS_HELP_STRING([--with-mysql-lib=<path>], [directory path of MySQL library installation])],
+ [
+ MYSQL_LIBS_check="$withval/lib/mysql $withval/mysql $withval"
+ MYSQL_config_check="skip"
+ ]
+ )
+
+ AC_ARG_WITH([mysql-includes],
+ [AS_HELP_STRING([--with-mysql-includes=<path>], [directory path of MySQL header installation])],
+ [
+ MYSQL_CFLAGS_check="$withval/include/mysql $withval/mysql $withval"
+ MYSQL_config_check="skip"
+ ]
+ )
+
+ MYSQL_config=""
+ if test "x$MYSQL_config_check" != "xskip"; then
+ if test "x$MYSQL_config_check" = "x"; then
+ AC_PATH_PROG([MYSQL_config], [mysql_config])
+ else
+ AC_MSG_CHECKING([for $MYSQL_config_check])
+ if test -x $MYSQL_config_check; then
+ MYSQL_config="$MYSQL_config_check"
+ AC_MSG_RESULT([yes])
+ else
+ MYSQL_config=""
+ AC_MSG_ERROR([not found])
+ fi
+ fi
+ fi
+
+ if test "x$MYSQL_config" != "x"; then
+ # use this to configure everything
+ MYSQL_LIBS=`$MYSQL_config --libs`
+ MYSQL_CFLAGS=`$MYSQL_config --include`
+ else
+ AC_MSG_CHECKING([for MySQL library directory])
+ MYSQL_libdir=
+ for m in $MYSQL_LIBS_check; do
+ if test -d "$m" && \
+ (test -f "$m/libmysqlclient.so" || test -f "$m/libmysqlclient.a")
+ then
+ MYSQL_libdir=$m
+ break
+ fi
+ done
+ if test -z "$MYSQL_libdir"; then
+ AC_MSG_ERROR([Did not find the mysql library dir in '$MYSQL_LIBS_check'])
+ fi
+ case "$MYSQL_libdir" in
+ /*) MYSQL_LIBS="-L$MYSQL_libdir -lmysqlclient"
+ ;;
+ *) AC_MSG_ERROR([The MySQL library directory ($MYSQL_libdir) must be an absolute path.])
+ ;;
+ esac
+ AC_MSG_RESULT([$MYSQL_libdir])
+ AC_SUBST(MYSQL_LIBS)
+ AC_MSG_CHECKING([for MySQL include directory])
+ MYSQL_CFLAGS=
+ for m in $MYSQL_CFLAGS_check; do
+ if test -d "$m" && test -f "$m/mysql.h"
+ then
+ MYSQL_CFLAGS="$m"
+ break
+ fi
+ done
+ if test -z "$MYSQL_CFLAGS"; then
+ AC_MSG_ERROR([Did not find the mysql include dir in '$MYSQL_CFLAGS_check'])
+ fi
+
+ case "$MYSQL_CFLAGS" in
+ /*) AC_MSG_RESULT($MYSQL_CFLAGS)
+ ;;
+ *) AC_MSG_ERROR([The MySQL include directory ($MYSQL_CFLAGS) must be an absolute path.])
+ ;;
+ esac
+ MYSQL_CFLAGS="-I$MYSQL_CFLAGS"
+ fi
+ AC_SUBST(MYSQL_LIBS)
+ AC_SUBST(MYSQL_CFLAGS)
+])
+
--- /dev/null
+AC_DEFUN([PDNS_WITH_ORACLE],[
+ AC_ARG_WITH(oracle_includes, AS_HELP_STRING([--with-oracle-includes=<path>],[instantclient sdk include dir]))
+ AC_ARG_WITH(oracle_libs, AS_HELP_STRING([--with-oracle-libs=<path>],[instantclient oracle library dir]))
+
+ if test x"$with_oracle_includes" = "x"; then
+ # check possible locations
+ for p1 in /usr/include/oracle /usr/local/include/oracle; do
+ for p2 in $p1/*/client*; do
+ if test -d "$p2"; then
+ with_oracle_includes=$p2
+ fi
+ done
+ done
+ fi
+
+ if test x"$with_oracle_includes" = x && test "$ORACLE_HOME/rdbms/public" != "/rdbms/public"; then
+ if test -d $ORACLE_HOME/rdbms/public; then
+ with_oracle_includes=$ORACLE_HOME/rdbms/public
+ fi
+ fi
+
+ # test header
+ old_CXXFLAGS="$CXXFLAGS"
+ old_CFLAGS="$CFLAGS"
+ CXXFLAGS="$CXXFLAGS -I$with_oracle_includes"
+ CPPFLAGS="$CPPFLAGS -I$with_oracle_includes"
+ AC_CHECK_HEADER([oci.h], ORACLE_CFLAGS="-I$with_oracle_includes", AC_MSG_ERROR([Could not find oci.h]))
+ CXXFLAGS="$old_CXXFLAGS"
+ CPPFLAGS="$old_CPPFLAGS"
+ AC_SUBST([ORACLE_CFLAGS])
+ AC_SUBST([ORACLE_LIBS])
+
+ if test x"$with_oracle_libs" = "x"; then
+ # check possible locationse
+ for p1 in /usr/lib/oracle /usr/local/lib/oracle; do
+ for p2 in $p1/*/client*/lib; do
+ if test -d "$p2"; then
+ with_oracle_libs=$p2
+ fi
+ done
+ done
+ fi
+
+ if test x"$with_oracle_libs" = x && test "$ORACLE_HOME/lib" != "/lib"; then
+ if test -d $ORACLE_HOME/lib; then
+ with_oracle_libs=$ORACLE_HOME/lib
+ fi
+ fi
+
+ # we have to check for client9 as well...
+ # test -lclntsh
+ old_LDFLAGS="$LDFLAGS"
+ LDFLAGS="-L$with_oracle_libs -locci"
+ AC_CHECK_LIB([clntsh],[OCIEnvInit],
+ [ORACLE_LIBS="-L$with_oracle_libs -lclntsh -locci"],
+ AC_CHECK_LIB([client9], [OCIEnvInit],
+ [ORACLE_LIBS="-L$with_oracle_libs -lclient9 -lclntsh9"],
+ [AC_MSG_ERROR([Could not find client libraries])]
+ )
+ )
+ LDFLAGS="$old_LDFLAGS"
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_POSTGRESQL],[
+ AC_ARG_WITH([pgsql],
+ AS_HELP_STRING([--with-pgsql=<path>],
+ [root directory path of PgSQL installation]
+ ),
+ [PGSQL_lib_check="$withval/lib/pgsql $withval/lib"
+ PGSQL_inc_check="$withval/include/pgsql $withval/include"
+ ]
+ )
+
+ AC_ARG_WITH([pgsql-lib],
+ AS_HELP_STRING([--with-pgsql-lib=<path>],
+ [directory path of PgSQL library installation]
+ ),
+ [PGSQL_lib_check="$withval/lib/pgsql $withval/pgsql $withval"]
+ )
+
+ AC_ARG_WITH([pgsql-includes],
+ AS_HELP_STRING([--with-pgsql-includes=<path>],
+ [directory path of PgSQL header installation]
+ ),
+ [PGSQL_inc_check="$withval/include/pgsql $withval/pgsql $withval"]
+ )
+
+ AC_ARG_WITH([pgsql-config],
+ AS_HELP_STRING([--with-pgsql-config=<path>],
+ [location of pg_config]
+ ),
+ [PGSQL_pg_config="$withval"
+ if test "x$PGSQL_pg_config" = "xyes" || test ! -x "$PGSQL_pg_config"; then
+ AC_MSG_ERROR([--with-pgsql-config must provide a valid path to pg_config executable])
+ fi
+ ],
+ [AC_PATH_PROG([PGSQL_pg_config], [pg_config])]
+ )
+
+ if test "x$PGSQL_pg_config" != "x"; then
+ if test "x$PGSQL_lib_check" = "x"; then
+ PGSQL_lib_check=$($PGSQL_pg_config --libdir)
+ fi
+ if test "x$PGSQL_inc_check" = "x"; then
+ PGSQL_inc_check=$($PGSQL_pg_config --includedir)
+ fi
+ PGSQL_CFLAGS=
+ fi
+
+ if test "x$PGSQL_lib_check" = "x"; then
+ PGSQL_lib_check="/usr/local/pgsql/lib/pgsql /usr/local/lib/pgsql /opt/pgsql/lib/pgsql /usr/lib/pgsql /usr/local/pgsql/lib /usr/local/lib /opt/pgsql/lib /usr/lib /usr/lib64 $full_libdir"
+ fi
+
+ if test "x$PGSQL_inc_check" = "x"; then
+ PGSQL_inc_check="/usr/local/pgsql/include/pgsql /usr/include /usr/local/include/postgresql/ /usr/local/include /opt/pgsql/include/pgsql /opt/pgsql/include /usr/include/pgsql/ /usr/include/postgresql"
+ fi
+
+ AC_SUBST([PGSQL_lib])
+ AC_MSG_CHECKING([for PgSQL library directory])
+ PGSQL_libdir=
+ for m in $PGSQL_lib_check; do
+ if test -d "$m" && (test -f "$m/libpq.a" || test -f "$m/libpq.so"); then
+ PGSQL_libdir=$m
+ break
+ fi
+ done
+ if test -z "$PGSQL_libdir"; then
+ AC_MSG_ERROR([Did not find the pgsql library dir in '$PGSQL_lib_check'])
+ fi
+ case "$PGSQL_libdir" in
+ /usr/lib)
+ PGSQL_lib="-lpq"
+ ;;
+ /usr/lib64)
+ PGSQL_lib="-lpq"
+ ;;
+ $full_libdir)
+ PGSQL_lib="-lpq"
+ ;;
+ /*)
+ PGSQL_lib="-L$PGSQL_libdir -Wl,-rpath,$PGSQL_libdir -lpq"
+ ;;
+ *)
+ AC_MSG_ERROR([The PgSQL library directory ($PGSQL_libdir) must be an absolute path.])
+ ;;
+ esac
+ AC_MSG_RESULT([$PGSQL_libdir])
+
+ AC_SUBST([PGSQL_inc])
+ AC_MSG_CHECKING([for PgSQL include directory])
+ PGSQL_incdir=
+ for m in $PGSQL_inc_check; do
+ if test -d "$m" && test -f "$m/libpq-fe.h"; then
+ PGSQL_incdir=$m
+ break
+ fi
+ done
+ if test -z "$PGSQL_incdir"; then
+ AC_MSG_ERROR([Did not find the PgSQL include dir in '$PGSQL_inc_check'])
+ fi
+ case "$PGSQL_incdir" in
+ /*)
+ PGSQL_inc="-I$PGSQL_incdir"
+ ;;
+ * )
+ AC_MSG_ERROR([The PgSQL include directory ($PGSQL_incdir) must be an absolute path.])
+ ;;
+ esac
+ AC_MSG_RESULT([$PGSQL_incdir])
+])
+
--- /dev/null
+AC_DEFUN([PDNS_WITH_PROTOBUF], [
+ AC_MSG_CHECKING([if we need to link in protobuf])
+ AC_ARG_WITH([protobuf],
+ AS_HELP_STRING([--with-protobuf],[enable protobuf support @<:@default=auto@:>@]),
+ [with_protobuf=$withval],
+ [with_protobuf=auto],
+ )
+ AC_MSG_RESULT([$with_protobuf])
+
+ AS_IF([test "x$with_protobuf" != "xno"], [
+ AS_IF([test "x$with_protobuf" = "xyes" -o "x$with_protobuf" = "xauto"], [
+ PKG_CHECK_MODULES([PROTOBUF], [protobuf], [ : ], [ : ])
+ AC_CHECK_PROG([PROTOC], [protoc], [protoc])
+ ])
+ ])
+ AS_IF([test "x$with_protobuf" = "xyes"], [
+ AS_IF([test x"$PROTOBUF_LIBS" = "x"], [
+ AC_MSG_ERROR([Protobuf requested but libraries were not found])
+ ])
+ AS_IF([test x"$PROTOC" = "x"], [
+ AC_MSG_ERROR([Protobuf requested but the protobuf compiler was not found])
+ ])
+ ])
+ AM_CONDITIONAL([HAVE_PROTOBUF], [test x"$PROTOBUF_LIBS" != "x"])
+ AM_CONDITIONAL([HAVE_PROTOC], [test x"$PROTOC" != "x"])
+ AS_IF([test x"$PROTOBUF_LIBS" != "x"], [AC_DEFINE([HAVE_PROTOBUF], [1], [Define if using protobuf.])])
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_SQLITE3], [
+ AC_MSG_CHECKING([whether user requires sqlite3])
+ AC_ARG_WITH([sqlite3],
+ [AS_HELP_STRING([--with-sqlite3],[include sqlite3 driver @<:@default=no@:>@])],
+ [with_sqlite3=$withval],
+ [with_sqlite3=no]
+ )
+ AC_MSG_RESULT([$with_sqlite3])
+
+ AS_IF([test "x$with_sqlite3" != "xno"], [
+ needsqlite3=yes
+ ])
+])
--- /dev/null
+AC_DEFUN([PDNS_WITH_UNIXODBC],[
+ AC_ARG_WITH([unixodbc],
+ [AS_HELP_STRING([--with-unixodbc=<path>], [root directory path of unixODBC installation])],
+ [
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $with_unixodbc/lib"
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc"
+ UNIXODBC_config_check="$withval/bin/odbc_config"
+ ],
+ [
+ UNIXODBC_LIBS_check="/usr/local/unixodbc/lib/unixodbc /usr/local/lib/unixodbc /opt/unixodbc/lib/unixodbc \
+ /usr/lib/unixodbc /usr/lib64/unixodbc /usr/local/unixodbc/lib /usr/local/lib /opt/unixodbc/lib /usr/lib \
+ /usr/sfw/lib/ /usr/lib/odbc /usr/lib/x86_64-linux-gnu $full_libdir"
+ UNIXODBC_CFLAGS_check="/usr/local/unixodbc/include/unixodbc /usr/local/include/unixodbc \
+ /opt/unixodbc/include/unixodbc /opt/unixodbc/include /usr/include/unixodbc /usr/sfw/include/unixodbc \
+ /usr/include /usr/local/include"
+ ]
+ )
+
+ AC_ARG_WITH([odbc-config],
+ [AS_HELP_STRING([--with-odbc-config=<path>], [file path to odbc_config])],
+ [UNIXODBC_config_check=$withval]
+ )
+
+ AC_ARG_WITH([unixodbc-lib],
+ [AS_HELP_STRING([--with-unixodbc-lib=<path>], [directory path of unixODBC library installation])],
+ [
+ UNIXODBC_LIBS_check="$withval/lib/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+ ]
+ )
+
+ AC_ARG_WITH([unixodbc-includes],
+ [AS_HELP_STRING([--with-unixodbc-includes=<path>], [directory path of unixODBC header installation])],
+ [
+ UNIXODBC_CFLAGS_check="$withval/include/unixodbc $withval/unixodbc $withval"
+ UNIXODBC_config_check="skip"
+ ]
+ )
+
+ UNIXODBC_config=""
+ if test "x$UNIXODBC_config_check" != "xskip"; then
+ if test "x$UNIXODBC_config_check" = "x"; then
+ AC_PATH_PROG([UNIXODBC_config], [odbc_config])
+ else
+ AC_MSG_CHECKING([for $UNIXODBC_config_check])
+ if test -x $UNIXODBC_config_check; then
+ UNIXODBC_config="$UNIXODBC_config_check"
+ AC_MSG_RESULT([yes])
+ else
+ UNIXODBC_config=""
+ AC_MSG_ERROR([not found])
+ fi
+ fi
+ fi
+
+ if test "x$UNIXODBC_config" != "x"; then
+ # use this to configure everything
+ UNIXODBC_LIBS=`$UNIXODBC_config --libs`
+ UNIXODBC_CFLAGS=-I`$UNIXODBC_config --include-prefix`
+ else
+ AC_MSG_CHECKING([for unixODBC library directory])
+ UNIXODBC_libdir=
+ for m in $UNIXODBC_LIBS_check; do
+ if test -d "$m" && \
+ (test -f "$m/libodbc.so" || test -f "$m/libodbc.a")
+ then
+ UNIXODBC_libdir=$m
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_libdir"; then
+ AC_MSG_ERROR([Did not find the unixodbc library dir in '$UNIXODBC_LIBS_check'])
+ fi
+ case "$UNIXODBC_libdir" in
+ /*) UNIXODBC_LIBS="-L$UNIXODBC_libdir -lodbc"
+ ;;
+ *) AC_MSG_ERROR([The unixODBC library directory ($UNIXODBC_libdir) must be an absolute path.])
+ ;;
+ esac
+ AC_MSG_RESULT([$UNIXODBC_libdir])
+
+ AC_MSG_CHECKING([for unixODBC include directory])
+ UNIXODBC_CFLAGS=
+ for m in $UNIXODBC_CFLAGS_check; do
+ if test -d "$m" && test -f "$m/sql.h"
+ then
+ UNIXODBC_CFLAGS="$m"
+ break
+ fi
+ done
+ if test -z "$UNIXODBC_CFLAGS"; then
+ AC_MSG_ERROR([Did not find the unixodbc include dir in '$UNIXODBC_CFLAGS_check'])
+ fi
+
+ case "$UNIXODBC_CFLAGS" in
+ /*) AC_MSG_RESULT($UNIXODBC_CFLAGS)
+ ;;
+ *) AC_MSG_ERROR([The unixODBC include directory ($UNIXODBC_CFLAGS) must be an absolute path.])
+ ;;
+ esac
+ UNIXODBC_CFLAGS="-I$UNIXODBC_CFLAGS"
+ fi
+
+ AC_SUBST(UNIXODBC_CFLAGS)
+ AC_SUBST(UNIXODBC_LIBS)
+])
--- /dev/null
+# systemd.m4 - Macros to check for and enable systemd -*- Autoconf -*-
+#
+# Copyright (C) 2014 Luis R. Rodriguez <mcgrof@suse.com>
+# Copyright (C) 2016 Pieter Lexis <pieter.lexis@powerdns.com>
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation, Inc.,
+# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+
+#serial 2
+
+dnl Some optional path options
+AC_DEFUN([AX_SYSTEMD_OPTIONS], [
+ AC_ARG_WITH(systemd, [ --with-systemd set directory for systemd service files],
+ SYSTEMD_DIR="$withval", SYSTEMD_DIR="")
+ AC_SUBST(SYSTEMD_DIR)
+
+ AC_ARG_WITH(systemd, [ --with-systemd-modules-load set directory for systemd modules load files],
+ SYSTEMD_MODULES_LOAD="$withval", SYSTEMD_MODULES_LOAD="")
+ AC_SUBST(SYSTEMD_MODULES_LOAD)
+])
+
+AC_DEFUN([AX_ENABLE_SYSTEMD_OPTS], [
+ AX_ARG_DEFAULT_ENABLE([systemd], [Disable systemd support])
+ AX_SYSTEMD_OPTIONS()
+])
+
+AC_DEFUN([AX_ALLOW_SYSTEMD_OPTS], [
+ AX_ARG_DEFAULT_DISABLE([systemd], [Enable systemd support])
+ AX_SYSTEMD_OPTIONS()
+])
+
+AC_DEFUN([AX_CHECK_SYSTEMD_LIBS], [
+ AC_REQUIRE([AX_CHECK_SYSTEMD_DETECT_AND_ENABLE])
+ AS_IF([test "x$libsystemd" = x], [
+ AC_MSG_ERROR([Unable to find a suitable libsystemd library])
+ ])
+
+ PKG_CHECK_MODULES([SYSTEMD], [$libsystemd_daemon])
+ dnl pkg-config older than 0.24 does not set these for
+ dnl PKG_CHECK_MODULES() worth also noting is that as of version 208
+ dnl of systemd pkg-config --cflags currently yields no extra flags yet.
+ AC_SUBST([SYSTEMD_CFLAGS])
+ AC_SUBST([SYSTEMD_LIBS])
+
+ AS_IF([test "x$SYSTEMD_DIR" = x], [
+ dnl In order to use the line below we need to fix upstream systemd
+ dnl to properly ${prefix} for child variables in
+ dnl src/core/systemd.pc.in but this is a bit complex at the
+ dnl moment as they depend on another rootprefix, which can vary
+ dnl from prefix in practice. We provide our own definition as we
+ dnl *know* where systemd will dump this to, but this does limit
+ dnl us to stick to a non custom systemdsystemunitdir, dnl to work
+ dnl around this we provide the additional configure option
+ dnl --with-systemd where you can specify the directory for the unit
+ dnl files. It would also be best to just extend the upstream
+ dnl pkg-config pkg.m4 with an AC_DEFUN() to do this neatly.
+ dnl SYSTEMD_DIR="`$PKG_CONFIG --define-variable=prefix=$PREFIX --variable=systemdsystemunitdir systemd`"
+ SYSTEMD_DIR="\$(prefix)/lib/systemd/system/"
+ ], [])
+
+ AS_IF([test "x$SYSTEMD_DIR" = x], [
+ AC_MSG_ERROR([SYSTEMD_DIR is unset])
+ ], [])
+
+ dnl There is no variable for this yet for some reason
+ AS_IF([test "x$SYSTEMD_MODULES_LOAD" = x], [
+ SYSTEMD_MODULES_LOAD="\$(prefix)/lib/modules-load.d/"
+ ], [])
+
+ AS_IF([test "x$SYSTEMD_MODULES_LOAD" = x], [
+ AC_MSG_ERROR([SYSTEMD_MODULES_LOAD is unset])
+ ], [])
+])
+
+AC_DEFUN([AX_CHECK_SYSTEMD], [
+ dnl Respect user override to disable
+ AS_IF([test "x$enable_systemd" != "xno"], [
+ AS_IF([test "x$systemd" = "xy" ], [
+ AC_DEFINE([HAVE_SYSTEMD], [1], [Systemd available and enabled])
+ systemd=y
+ AX_CHECK_SYSTEMD_LIBS()
+ ],[systemd=n])
+ ],[systemd=n])
+])
+
+AC_DEFUN([AX_CHECK_SYSTEMD_DETECT_AND_ENABLE], [
+ AC_CHECK_HEADER([systemd/sd-daemon.h], [
+ for libname in systemd-daemon systemd; do
+ AC_CHECK_LIB([$libname], [sd_listen_fds], [
+ libsystemd_daemon="lib$libname"
+ systemd=y
+ libsystemd=y
+ ])
+ done
+ ])
+])
+
+dnl Enables systemd by default and requires a --disable-systemd option flag
+dnl to configure if you want to disable.
+AC_DEFUN([AX_ENABLE_SYSTEMD], [
+ AX_ENABLE_SYSTEMD_OPTS()
+ AX_CHECK_SYSTEMD()
+])
+
+dnl Systemd will be disabled by default and requires you to run configure with
+dnl --enable-systemd to look for and enable systemd.
+AC_DEFUN([AX_ALLOW_SYSTEMD], [
+ AX_ALLOW_SYSTEMD_OPTS()
+ AX_CHECK_SYSTEMD()
+])
+
+dnl Systemd will be disabled by default but if your build system is detected
+dnl to have systemd build libraries it will be enabled. You can always force
+dnl disable with --disable-systemd
+AC_DEFUN([AX_AVAILABLE_SYSTEMD], [
+ AX_ALLOW_SYSTEMD_OPTS()
+ AX_CHECK_SYSTEMD_DETECT_AND_ENABLE()
+ AX_CHECK_SYSTEMD()
+])
--- /dev/null
+dnl Check for the tm_gmtoff field in struct tm
+dnl (Borrowed from the Gaim project)
+dnl The Gaim Project (now know as Pidgin) is licensed under the GPLv2
+
+AC_DEFUN([MC_TM_GMTOFF],
+[AC_REQUIRE([AC_STRUCT_TM])dnl
+AC_CACHE_CHECK([for tm_gmtoff in struct tm], ac_cv_struct_tm_gmtoff,
+[AC_TRY_COMPILE([#include <sys/types.h>
+#include <$ac_cv_struct_tm>], [struct tm tm; tm.tm_gmtoff;],
+ ac_cv_struct_tm_gmtoff=yes, ac_cv_struct_tm_gmtoff=no)])
+if test "$ac_cv_struct_tm_gmtoff" = yes; then
+ AC_DEFINE(HAVE_TM_GMTOFF, 1, [tm_gmtoff is available.])
+fi
+])
--- /dev/null
+# warnings.m4 serial 11
+dnl Copyright (C) 2008-2015 Free Software Foundation, Inc.
+dnl This file is free software; the Free Software Foundation
+dnl gives unlimited permission to copy and/or distribute it,
+dnl with or without modifications, as long as this notice is preserved.
+
+dnl From Simon Josefsson
+
+# gl_AS_VAR_APPEND(VAR, VALUE)
+# ----------------------------
+# Provide the functionality of AS_VAR_APPEND if Autoconf does not have it.
+m4_ifdef([AS_VAR_APPEND],
+[m4_copy([AS_VAR_APPEND], [gl_AS_VAR_APPEND])],
+[m4_define([gl_AS_VAR_APPEND],
+[AS_VAR_SET([$1], [AS_VAR_GET([$1])$2])])])
+
+
+# gl_COMPILER_OPTION_IF(OPTION, [IF-SUPPORTED], [IF-NOT-SUPPORTED],
+# [PROGRAM = AC_LANG_PROGRAM()])
+# -----------------------------------------------------------------
+# Check if the compiler supports OPTION when compiling PROGRAM.
+#
+# FIXME: gl_Warn must be used unquoted until we can assume Autoconf
+# 2.64 or newer.
+AC_DEFUN([gl_COMPILER_OPTION_IF],
+[AS_VAR_PUSHDEF([gl_Warn], [gl_cv_warn_[]_AC_LANG_ABBREV[]_$1])dnl
+AS_VAR_PUSHDEF([gl_Flags], [_AC_LANG_PREFIX[]FLAGS])dnl
+AS_LITERAL_IF([$1],
+ [m4_pushdef([gl_Positive], m4_bpatsubst([$1], [^-Wno-], [-W]))],
+ [gl_positive="$1"
+case $gl_positive in
+ -Wno-*) gl_positive=-W`expr "X$gl_positive" : 'X-Wno-\(.*\)'` ;;
+esac
+m4_pushdef([gl_Positive], [$gl_positive])])dnl
+AC_CACHE_CHECK([whether _AC_LANG compiler handles $1], m4_defn([gl_Warn]), [
+ gl_save_compiler_FLAGS="$gl_Flags"
+ gl_AS_VAR_APPEND(m4_defn([gl_Flags]),
+ [" $gl_unknown_warnings_are_errors ]m4_defn([gl_Positive])["])
+ AC_LINK_IFELSE([m4_default([$4], [AC_LANG_PROGRAM([])])],
+ [AS_VAR_SET(gl_Warn, [yes])],
+ [AS_VAR_SET(gl_Warn, [no])])
+ gl_Flags="$gl_save_compiler_FLAGS"
+])
+AS_VAR_IF(gl_Warn, [yes], [$2], [$3])
+m4_popdef([gl_Positive])dnl
+AS_VAR_POPDEF([gl_Flags])dnl
+AS_VAR_POPDEF([gl_Warn])dnl
+])
+
+# gl_UNKNOWN_WARNINGS_ARE_ERRORS
+# ------------------------------
+# Clang doesn't complain about unknown warning options unless one also
+# specifies -Wunknown-warning-option -Werror. Detect this.
+AC_DEFUN([gl_UNKNOWN_WARNINGS_ARE_ERRORS],
+[gl_COMPILER_OPTION_IF([-Werror -Wunknown-warning-option],
+ [gl_unknown_warnings_are_errors='-Wunknown-warning-option -Werror'],
+ [gl_unknown_warnings_are_errors=])])
+
+# gl_WARN_ADD(OPTION, [VARIABLE = WARN_CFLAGS],
+# [PROGRAM = AC_LANG_PROGRAM()])
+# ---------------------------------------------
+# Adds parameter to WARN_CFLAGS if the compiler supports it when
+# compiling PROGRAM. For example, gl_WARN_ADD([-Wparentheses]).
+#
+# If VARIABLE is a variable name, AC_SUBST it.
+AC_DEFUN([gl_WARN_ADD],
+[AC_REQUIRE([gl_UNKNOWN_WARNINGS_ARE_ERRORS])
+gl_COMPILER_OPTION_IF([$1],
+ [gl_AS_VAR_APPEND(m4_if([$2], [], [[WARN_CFLAGS]], [[$2]]), [" $1"])],
+ [],
+ [$3])
+m4_ifval([$2],
+ [AS_LITERAL_IF([$2], [AC_SUBST([$2])])],
+ [AC_SUBST([WARN_CFLAGS])])dnl
+])
+
+# Local Variables:
+# mode: autoconf
+# End:
--- /dev/null
+SUBDIRS= @moduledirs@
+
+DIST_SUBDIRS = \
+ bindbackend \
+ geoipbackend \
+ gmysqlbackend \
+ godbcbackend \
+ goraclebackend \
+ gpgsqlbackend \
+ gsqlite3backend \
+ ldapbackend \
+ luabackend \
+ mydnsbackend \
+ opendbxbackend \
+ oraclebackend \
+ pipebackend \
+ randombackend \
+ remotebackend \
+ tinydnsbackend
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+SOURCES =
+DIST_SOURCES =
+RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \
+ ctags-recursive dvi-recursive html-recursive info-recursive \
+ install-data-recursive install-dvi-recursive \
+ install-exec-recursive install-html-recursive \
+ install-info-recursive install-pdf-recursive \
+ install-ps-recursive install-recursive installcheck-recursive \
+ installdirs-recursive pdf-recursive ps-recursive \
+ tags-recursive uninstall-recursive
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+am__recursive_targets = \
+ $(RECURSIVE_TARGETS) \
+ $(RECURSIVE_CLEAN_TARGETS) \
+ $(am__extra_recursive_targets)
+AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \
+ distdir
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+SUBDIRS = @moduledirs@
+DIST_SUBDIRS = \
+ bindbackend \
+ geoipbackend \
+ gmysqlbackend \
+ godbcbackend \
+ goraclebackend \
+ gpgsqlbackend \
+ gsqlite3backend \
+ ldapbackend \
+ luabackend \
+ mydnsbackend \
+ opendbxbackend \
+ oraclebackend \
+ pipebackend \
+ randombackend \
+ remotebackend \
+ tinydnsbackend
+
+all: all-recursive
+
+.SUFFIXES:
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run 'make' without going through this Makefile.
+# To change the values of 'make' variables: instead of editing Makefiles,
+# (1) if the variable is set in 'config.status', edit 'config.status'
+# (which will cause the Makefiles to be regenerated when you run 'make');
+# (2) otherwise, pass the desired values on the 'make' command line.
+$(am__recursive_targets):
+ @fail=; \
+ if $(am__make_keepgoing); then \
+ failcom='fail=yes'; \
+ else \
+ failcom='exit 1'; \
+ fi; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-recursive
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-recursive
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-recursive
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ $(am__make_dryrun) \
+ || test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-recursive
+all-am: Makefile
+installdirs: installdirs-recursive
+installdirs-am:
+install: install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-recursive
+
+clean-am: clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -f Makefile
+distclean-am: clean-am distclean-generic distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am:
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-generic mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am:
+
+.MAKE: $(am__recursive_targets) install-am install-strip
+
+.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am check \
+ check-am clean clean-generic clean-libtool cscopelist-am ctags \
+ ctags-am distclean distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-generic mostlyclean-libtool pdf pdf-am \
+ ps ps-am tags tags-am uninstall uninstall-am
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+pkglib_LTLIBRARIES = libbindbackend.la
+AM_CPPFLAGS += -I../../pdns
+
+AM_LFLAGS = -i
+AM_YFLAGS = -d --verbose --debug
+
+BUILT_SOURCES = \
+ ../../pdns/bind-dnssec.schema.sqlite3.sql.h \
+ ../../pdns/bindlexer.l \
+ ../../pdns/bindparser.yy
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+libbindbackend_la_SOURCES = \
+ bindbackend2.cc bindbackend2.hh \
+ binddnssec.cc
+
+libbindbackend_la_LDFLAGS = -module -avoid-version
+
+../../pdns/bind-dnssec.schema.sqlite3.sql.h: ../../pdns/bind-dnssec.schema.sqlite3.sql
+ ( echo 'static char sqlCreate[] __attribute__((unused))=' ; sed 's/$$/"/g' $< | sed 's/^/"/g' ; echo ';' ) > $@
+
+# for bindparser.h/hh
+.hh.h:
+ cp $< $@
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/bindbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+libbindbackend_la_LIBADD =
+am_libbindbackend_la_OBJECTS = bindbackend2.lo binddnssec.lo
+libbindbackend_la_OBJECTS = $(am_libbindbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libbindbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libbindbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libbindbackend_la_SOURCES)
+DIST_SOURCES = $(libbindbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I../../pdns
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libbindbackend.la
+AM_LFLAGS = -i
+AM_YFLAGS = -d --verbose --debug
+BUILT_SOURCES = \
+ ../../pdns/bind-dnssec.schema.sqlite3.sql.h \
+ ../../pdns/bindlexer.l \
+ ../../pdns/bindparser.yy
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+libbindbackend_la_SOURCES = \
+ bindbackend2.cc bindbackend2.hh \
+ binddnssec.cc
+
+libbindbackend_la_LDFLAGS = -module -avoid-version
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .h .hh .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/bindbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/bindbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libbindbackend.la: $(libbindbackend_la_OBJECTS) $(libbindbackend_la_DEPENDENCIES) $(EXTRA_libbindbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libbindbackend_la_LINK) -rpath $(pkglibdir) $(libbindbackend_la_OBJECTS) $(libbindbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bindbackend2.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/binddnssec.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: all check install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+../../pdns/bind-dnssec.schema.sqlite3.sql.h: ../../pdns/bind-dnssec.schema.sqlite3.sql
+ ( echo 'static char sqlCreate[] __attribute__((unused))=' ; sed 's/$$/"/g' $< | sed 's/^/"/g' ; echo ';' ) > $@
+
+# for bindparser.h/hh
+.hh.h:
+ cp $< $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+bindbackend2.lo binddnssec.lo
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <errno.h>
+#include <string>
+#include <set>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <fstream>
+#include <fcntl.h>
+#include <sstream>
+#include <boost/algorithm/string.hpp>
+#include <system_error>
+
+#include "pdns/dnsseckeeper.hh"
+#include "pdns/dnssecinfra.hh"
+#include "pdns/base32.hh"
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "bindbackend2.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/zoneparser-tng.hh"
+#include "pdns/bindparserclasses.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/qtype.hh"
+#include "pdns/misc.hh"
+#include "pdns/dynlistener.hh"
+#include "pdns/lock.hh"
+#include "pdns/namespaces.hh"
+
+/*
+ All instances of this backend share one s_state, which is indexed by zone name and zone id.
+ The s_state is protected by a read/write lock, and the goal it to only interact with it briefly.
+ When a query comes in, we take a read lock and COPY the best zone to answer from s_state (BB2DomainInfo object)
+ All answers are served from this copy.
+
+ To interact with s_state, use safeGetBBDomainInfo (search on name or id), safePutBBDomainInfo (to update)
+ or safeRemoveBBDomainInfo. These all lock as they should.
+
+ Several functions need to traverse s_state to get data for the rest of PowerDNS. When doing so,
+ you need to manually take the s_state_lock (read).
+
+ Parsing zones happens with parseZone(), which fills a BB2DomainInfo object. This can then be stored with safePutBBDomainInfo.
+
+ Finally, the BB2DomainInfo contains all records as a LookButDontTouch object. This makes sure you only look, but don't touch, since
+ the records might be in use in other places.
+*/
+
+Bind2Backend::state_t Bind2Backend::s_state;
+int Bind2Backend::s_first=1;
+bool Bind2Backend::s_ignore_broken_records=false;
+
+pthread_rwlock_t Bind2Backend::s_state_lock=PTHREAD_RWLOCK_INITIALIZER;
+pthread_mutex_t Bind2Backend::s_supermaster_config_lock=PTHREAD_MUTEX_INITIALIZER; // protects writes to config file
+pthread_mutex_t Bind2Backend::s_startup_lock=PTHREAD_MUTEX_INITIALIZER;
+string Bind2Backend::s_binddirectory;
+
+BB2DomainInfo::BB2DomainInfo()
+{
+ d_loaded=false;
+ d_lastcheck=0;
+ d_checknow=false;
+ d_status="Unknown";
+}
+
+void BB2DomainInfo::setCheckInterval(time_t seconds)
+{
+ d_checkinterval=seconds;
+}
+
+bool BB2DomainInfo::current()
+{
+ if(d_checknow) {
+ return false;
+ }
+
+ if(!d_checkinterval)
+ return true;
+
+ if(time(0) - d_lastcheck < d_checkinterval)
+ return true;
+
+ if(d_filename.empty())
+ return true;
+
+ return (getCtime()==d_ctime);
+}
+
+time_t BB2DomainInfo::getCtime()
+{
+ struct stat buf;
+
+ if(d_filename.empty() || stat(d_filename.c_str(),&buf)<0)
+ return 0;
+ d_lastcheck=time(0);
+ return buf.st_ctime;
+}
+
+void BB2DomainInfo::setCtime()
+{
+ struct stat buf;
+ if(stat(d_filename.c_str(),&buf)<0)
+ return;
+ d_ctime=buf.st_ctime;
+}
+
+bool Bind2Backend::safeGetBBDomainInfo(int id, BB2DomainInfo* bbd)
+{
+ ReadLock rl(&s_state_lock);
+ state_t::const_iterator iter = s_state.find(id);
+ if(iter == s_state.end())
+ return false;
+ *bbd=*iter;
+ return true;
+}
+
+bool Bind2Backend::safeGetBBDomainInfo(const DNSName& name, BB2DomainInfo* bbd)
+{
+ ReadLock rl(&s_state_lock);
+ typedef state_t::index<NameTag>::type nameindex_t;
+ nameindex_t& nameindex = boost::multi_index::get<NameTag>(s_state);
+
+ nameindex_t::const_iterator iter = nameindex.find(name);
+ if(iter == nameindex.end())
+ return false;
+ *bbd=*iter;
+ return true;
+}
+
+bool Bind2Backend::safeRemoveBBDomainInfo(const DNSName& name)
+{
+ WriteLock rl(&s_state_lock);
+ typedef state_t::index<NameTag>::type nameindex_t;
+ nameindex_t& nameindex = boost::multi_index::get<NameTag>(s_state);
+
+ nameindex_t::iterator iter = nameindex.find(name);
+ if(iter == nameindex.end())
+ return false;
+ nameindex.erase(iter);
+ return true;
+}
+
+void Bind2Backend::safePutBBDomainInfo(const BB2DomainInfo& bbd)
+{
+ WriteLock rl(&s_state_lock);
+ replacing_insert(s_state, bbd);
+}
+
+void Bind2Backend::setNotified(uint32_t id, uint32_t serial)
+{
+ BB2DomainInfo bbd;
+ safeGetBBDomainInfo(id, &bbd);
+ bbd.d_lastnotified = serial;
+ safePutBBDomainInfo(bbd);
+}
+
+void Bind2Backend::setFresh(uint32_t domain_id)
+{
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(domain_id, &bbd)) {
+ bbd.d_lastcheck=time(0);
+ safePutBBDomainInfo(bbd);
+ }
+}
+
+bool Bind2Backend::startTransaction(const DNSName &qname, int id)
+{
+ if(id < 0) {
+ d_transaction_tmpname.clear();
+ d_transaction_id=id;
+ return true;
+ }
+ if(id == 0) {
+ throw DBException("domain_id 0 is invalid for this backend.");
+ }
+
+ d_transaction_id=id;
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(id, &bbd)) {
+ d_transaction_tmpname=bbd.d_filename+"."+itoa(random());
+ d_of=new ofstream(d_transaction_tmpname.c_str());
+ if(!*d_of) {
+ throw DBException("Unable to open temporary zonefile '"+d_transaction_tmpname+"': "+stringerror());
+ unlink(d_transaction_tmpname.c_str());
+ delete d_of;
+ d_of=0;
+ }
+
+ *d_of<<"; Written by PowerDNS, don't edit!"<<endl;
+ *d_of<<"; Zone '"<<bbd.d_name<<"' retrieved from master "<<endl<<"; at "<<nowTime()<<endl; // insert master info here again
+
+ return true;
+ }
+ return false;
+}
+
+bool Bind2Backend::commitTransaction()
+{
+ if(d_transaction_id < 0)
+ return true;
+ delete d_of;
+ d_of=0;
+
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(d_transaction_id, &bbd)) {
+ if(rename(d_transaction_tmpname.c_str(), bbd.d_filename.c_str())<0)
+ throw DBException("Unable to commit (rename to: '" + bbd.d_filename+"') AXFRed zone: "+stringerror());
+ queueReloadAndStore(bbd.d_id);
+ }
+
+ d_transaction_id=0;
+
+ return true;
+}
+
+bool Bind2Backend::abortTransaction()
+{
+ // -1 = dnssec speciality
+ // 0 = invalid transact
+ // >0 = actual transaction
+ if(d_transaction_id > 0) {
+ delete d_of;
+ d_of=0;
+ unlink(d_transaction_tmpname.c_str());
+ d_transaction_id=0;
+ }
+
+ return true;
+}
+
+bool Bind2Backend::feedRecord(const DNSResourceRecord &rr, string *ordername)
+{
+ BB2DomainInfo bbd;
+ safeGetBBDomainInfo(d_transaction_id, &bbd);
+
+ string qname;
+ string name = bbd.d_name.toString();
+ if (bbd.d_name.empty()) {
+ qname = rr.qname.toString();
+ }
+ else if (rr.qname.isPartOf(bbd.d_name)) {
+ if (rr.qname == bbd.d_name) {
+ qname = "@";
+ }
+ else {
+ DNSName relName = rr.qname.makeRelative(bbd.d_name);
+ qname = relName.toStringNoDot();
+ }
+ }
+ else {
+ throw DBException("out-of-zone data '"+rr.qname.toLogString()+"' during AXFR of zone '"+bbd.d_name.toLogString()+"'");
+ }
+
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
+ string content = drc->getZoneRepresentation();
+
+ // SOA needs stripping too! XXX FIXME - also, this should not be here I think
+ switch(rr.qtype.getCode()) {
+ case QType::MX:
+ case QType::SRV:
+ case QType::CNAME:
+ case QType::DNAME:
+ case QType::NS:
+ stripDomainSuffix(&content, name);
+ // falltrough
+ default:
+ *d_of<<qname<<"\t"<<rr.ttl<<"\t"<<rr.qtype.getName()<<"\t"<<content<<endl;
+ }
+ return true;
+}
+
+void Bind2Backend::getUpdatedMasters(vector<DomainInfo> *changedDomains)
+{
+ vector<DomainInfo> consider;
+ {
+ ReadLock rl(&s_state_lock);
+
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ if(!i->d_masters.empty() && this->alsoNotify.empty() && i->d_also_notify.empty())
+ continue;
+
+ DomainInfo di;
+ di.id=i->d_id;
+ di.zone=i->d_name;
+ di.last_check=i->d_lastcheck;
+ di.notified_serial=i->d_lastnotified;
+ di.backend=this;
+ di.kind=DomainInfo::Master;
+ consider.push_back(di);
+ }
+ }
+
+ SOAData soadata;
+ for(DomainInfo& di : consider) {
+ soadata.serial=0;
+ try {
+ this->getSOA(di.zone, soadata); // we might not *have* a SOA yet, but this might trigger a load of it
+ }
+ catch(...) {
+ continue;
+ }
+ if(di.notified_serial != soadata.serial) {
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(di.id, &bbd)) {
+ bbd.d_lastnotified=soadata.serial;
+ safePutBBDomainInfo(bbd);
+ }
+ if(di.notified_serial) { // don't do notification storm on startup
+ di.serial=soadata.serial;
+ changedDomains->push_back(di);
+ }
+ }
+ }
+}
+
+void Bind2Backend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
+{
+ SOAData soadata;
+
+ // prevent deadlock by using getSOA() later on
+ {
+ ReadLock rl(&s_state_lock);
+
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ DomainInfo di;
+ di.id=i->d_id;
+ di.zone=i->d_name;
+ di.last_check=i->d_lastcheck;
+ di.kind=i->d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave; //TODO: what about Native?
+ di.backend=this;
+ domains->push_back(di);
+ };
+ }
+
+ for(DomainInfo &di : *domains) {
+ this->getSOA(di.zone, soadata);
+ di.serial=soadata.serial;
+ }
+}
+
+void Bind2Backend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
+{
+ vector<DomainInfo> domains;
+ {
+ ReadLock rl(&s_state_lock);
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ if(i->d_masters.empty())
+ continue;
+ DomainInfo sd;
+ sd.id=i->d_id;
+ sd.zone=i->d_name;
+ sd.masters=i->d_masters;
+ sd.last_check=i->d_lastcheck;
+ sd.backend=this;
+ sd.kind=DomainInfo::Slave;
+ domains.push_back(sd);
+ }
+ }
+
+ for(DomainInfo &sd : domains) {
+ SOAData soadata;
+ soadata.refresh=0;
+ soadata.serial=0;
+ try {
+ getSOA(sd.zone,soadata); // we might not *have* a SOA yet
+ }
+ catch(...){}
+ sd.serial=soadata.serial;
+ if(sd.last_check+soadata.refresh < (unsigned int)time(0))
+ unfreshDomains->push_back(sd);
+ }
+}
+
+bool Bind2Backend::getDomainInfo(const DNSName& domain, DomainInfo &di)
+{
+ BB2DomainInfo bbd;
+ if(!safeGetBBDomainInfo(domain, &bbd))
+ return false;
+
+ di.id=bbd.d_id;
+ di.zone=domain;
+ di.masters=bbd.d_masters;
+ di.last_check=bbd.d_lastcheck;
+ di.backend=this;
+ di.kind=bbd.d_masters.empty() ? DomainInfo::Master : DomainInfo::Slave;
+ di.serial=0;
+ try {
+ SOAData sd;
+ sd.serial=0;
+
+ getSOA(bbd.d_name,sd); // we might not *have* a SOA yet
+ di.serial=sd.serial;
+ }
+ catch(...){}
+
+ return true;
+}
+
+void Bind2Backend::alsoNotifies(const DNSName& domain, set<string> *ips)
+{
+ // combine global list with local list
+ for(set<string>::iterator i = this->alsoNotify.begin(); i != this->alsoNotify.end(); i++) {
+ (*ips).insert(*i);
+ }
+ ReadLock rl(&s_state_lock);
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ if(i->d_name == domain) {
+ for(set<string>::iterator it = i->d_also_notify.begin(); it != i->d_also_notify.end(); it++) {
+ (*ips).insert(*it);
+ }
+ return;
+ }
+ }
+}
+
+// only parses, does NOT add to s_state!
+void Bind2Backend::parseZoneFile(BB2DomainInfo *bbd)
+{
+ NSEC3PARAMRecordContent ns3pr;
+ bool nsec3zone;
+ if (d_hybrid) {
+ DNSSECKeeper dk;
+ nsec3zone=dk.getNSEC3PARAM(bbd->d_name, &ns3pr);
+ } else
+ nsec3zone=getNSEC3PARAM(bbd->d_name, &ns3pr);
+
+ bbd->d_records = shared_ptr<recordstorage_t>(new recordstorage_t());
+
+ ZoneParserTNG zpt(bbd->d_filename, bbd->d_name, s_binddirectory);
+ DNSResourceRecord rr;
+ string hashed;
+ while(zpt.get(rr)) {
+ if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3)
+ continue; // we synthesise NSECs on demand
+
+ insertRecord(*bbd, rr.qname, rr.qtype, rr.content, rr.ttl, "");
+ }
+ fixupOrderAndAuth(*bbd, nsec3zone, ns3pr);
+ doEmptyNonTerminals(*bbd, nsec3zone, ns3pr);
+ bbd->setCtime();
+ bbd->d_loaded=true;
+ bbd->d_checknow=false;
+ bbd->d_status="parsed into memory at "+nowTime();
+}
+
+/** THIS IS AN INTERNAL FUNCTION! It does moadnsparser prio impedance matching
+ Much of the complication is due to the efforts to benefit from std::string reference counting copy on write semantics */
+void Bind2Backend::insertRecord(BB2DomainInfo& bb2, const DNSName &qname, const QType &qtype, const string &content, int ttl, const std::string& hashed, bool *auth)
+{
+ Bind2DNSRecord bdr;
+ shared_ptr<recordstorage_t> records = bb2.d_records.getWRITABLE();
+ bdr.qname=qname;
+
+ if(bb2.d_name.empty())
+ ;
+ else if(bdr.qname.isPartOf(bb2.d_name))
+ bdr.qname = bdr.qname.makeRelative(bb2.d_name);
+ else {
+ string msg = "Trying to insert non-zone data, name='"+bdr.qname.toLogString()+"', qtype="+qtype.getName()+", zone='"+bb2.d_name.toLogString()+"'";
+ if(s_ignore_broken_records) {
+ L<<Logger::Warning<<msg<< " ignored" << endl;
+ return;
+ }
+ else
+ throw PDNSException(msg);
+ }
+
+// bdr.qname.swap(bdr.qname);
+
+ if(!records->empty() && bdr.qname==boost::prior(records->end())->qname)
+ bdr.qname=boost::prior(records->end())->qname;
+
+ bdr.qname=bdr.qname;
+ bdr.qtype=qtype.getCode();
+ bdr.content=content;
+ bdr.nsec3hash = hashed;
+
+ if (auth) // Set auth on empty non-terminals
+ bdr.auth=*auth;
+ else
+ bdr.auth=true;
+
+ bdr.ttl=ttl;
+ records->insert(bdr);
+}
+
+string Bind2Backend::DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ ostringstream ret;
+
+ for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
+ BB2DomainInfo bbd;
+ DNSName zone(*i);
+ if(safeGetBBDomainInfo(zone, &bbd)) {
+ Bind2Backend bb2;
+ bb2.queueReloadAndStore(bbd.d_id);
+ safeGetBBDomainInfo(zone, &bbd); // Read the *new* domain status
+ ret<< *i << ": "<< (bbd.d_wasRejectedLastReload ? "[rejected]": "") <<"\t"<<bbd.d_status<<"\n";
+ }
+ else
+ ret<< *i << " no such domain\n";
+ }
+ if(ret.str().empty())
+ ret<<"no domains reloaded";
+ return ret.str();
+}
+
+
+string Bind2Backend::DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ ostringstream ret;
+
+ if(parts.size() > 1) {
+ for(vector<string>::const_iterator i=parts.begin()+1;i<parts.end();++i) {
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(DNSName(*i), &bbd)) {
+ ret<< *i << ": "<< (bbd.d_loaded ? "": "[rejected]") <<"\t"<<bbd.d_status<<"\n";
+ }
+ else
+ ret<< *i << " no such domain\n";
+ }
+ }
+ else {
+ ReadLock rl(&s_state_lock);
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ ret<< i->d_name << ": "<< (i->d_loaded ? "": "[rejected]") <<"\t"<<i->d_status<<"\n";
+ }
+ }
+
+ if(ret.str().empty())
+ ret<<"no domains passed";
+
+ return ret.str();
+}
+
+string Bind2Backend::DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ ostringstream ret;
+ ReadLock rl(&s_state_lock);
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ if(!i->d_loaded)
+ ret<<i->d_name<<"\t"<<i->d_status<<endl;
+ }
+ return ret.str();
+}
+
+string Bind2Backend::DLAddDomainHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ if(parts.size() < 3)
+ return "ERROR: Domain name and zone filename are required";
+
+ DNSName domainname(parts[1]);
+ const string &filename = parts[2];
+ BB2DomainInfo bbd;
+ if(safeGetBBDomainInfo(domainname, &bbd))
+ return "Already loaded";
+
+ if (!boost::starts_with(filename, "/") && ::arg()["chroot"].empty())
+ return "Unable to load zone " + domainname.toLogString() + " from " + filename + " as the filename is not absolute.";
+
+ struct stat buf;
+ if (stat(filename.c_str(), &buf) != 0)
+ return "Unable to load zone " + domainname.toLogString() + " from " + filename + ": " + strerror(errno);
+
+ Bind2Backend bb2; // createdomainentry needs access to our configuration
+ bbd=bb2.createDomainEntry(domainname, filename);
+ bbd.d_filename=filename;
+ bbd.d_checknow=true;
+ bbd.d_loaded=true;
+ bbd.d_lastcheck=0;
+ bbd.d_status="parsing into memory";
+
+ safePutBBDomainInfo(bbd);
+
+ L<<Logger::Warning<<"Zone "<<domainname<< " loaded"<<endl;
+ return "Loaded zone " + domainname.toLogString() + " from " + filename;
+}
+
+Bind2Backend::Bind2Backend(const string &suffix, bool loadZones)
+{
+ d_getAllDomainMetadataQuery_stmt = NULL;
+ d_getDomainMetadataQuery_stmt = NULL;
+ d_deleteDomainMetadataQuery_stmt = NULL;
+ d_insertDomainMetadataQuery_stmt = NULL;
+ d_getDomainKeysQuery_stmt = NULL;
+ d_deleteDomainKeyQuery_stmt = NULL;
+ d_insertDomainKeyQuery_stmt = NULL;
+ d_activateDomainKeyQuery_stmt = NULL;
+ d_deactivateDomainKeyQuery_stmt = NULL;
+ d_getTSIGKeyQuery_stmt = NULL;
+ d_setTSIGKeyQuery_stmt = NULL;
+ d_deleteTSIGKeyQuery_stmt = NULL;
+ d_getTSIGKeysQuery_stmt = NULL;
+
+ setArgPrefix("bind"+suffix);
+ d_logprefix="[bind"+suffix+"backend]";
+ d_hybrid=mustDo("hybrid");
+ s_ignore_broken_records=mustDo("ignore-broken-records");
+
+ if (!loadZones && d_hybrid)
+ return;
+
+ Lock l(&s_startup_lock);
+
+ d_transaction_id=0;
+ setupDNSSEC();
+ if(!s_first) {
+ return;
+ }
+
+ if(loadZones) {
+ loadConfig();
+ s_first=0;
+ }
+
+ extern DynListener *dl;
+ dl->registerFunc("BIND-RELOAD-NOW", &DLReloadNowHandler, "bindbackend: reload domains", "<domains>");
+ dl->registerFunc("BIND-DOMAIN-STATUS", &DLDomStatusHandler, "bindbackend: list status of all domains", "[domains]");
+ dl->registerFunc("BIND-LIST-REJECTS", &DLListRejectsHandler, "bindbackend: list rejected domains");
+ dl->registerFunc("BIND-ADD-ZONE", &DLAddDomainHandler, "bindbackend: add zone", "<domain> <filename>");
+}
+
+Bind2Backend::~Bind2Backend()
+{ freeStatements(); } // deallocate statements
+
+void Bind2Backend::rediscover(string *status)
+{
+ loadConfig(status);
+}
+
+void Bind2Backend::reload()
+{
+ WriteLock rwl(&s_state_lock);
+ for(state_t::iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ i->d_checknow=true; // being a bit cheeky here, don't index state_t on this (mutable)
+ }
+}
+
+void Bind2Backend::fixupOrderAndAuth(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr)
+{
+ shared_ptr<recordstorage_t> records = bbd.d_records.getWRITABLE();
+ recordstorage_t::const_iterator iter;
+
+ bool skip;
+ DNSName shorter;
+ set<DNSName> nssets, dssets;
+
+ for(const auto& bdr: *records) {
+ if(!bdr.qname.isRoot() && bdr.qtype == QType::NS)
+ nssets.insert(bdr.qname);
+ else if(bdr.qtype == QType::DS)
+ dssets.insert(bdr.qname);
+ }
+
+ for(auto iter = records->begin(); iter != records->end(); iter++) {
+ skip = false;
+ shorter = iter->qname;
+
+ if (!iter->qname.isRoot() && shorter.chopOff() && !iter->qname.isRoot()) {
+ do {
+ if(nssets.count(shorter)) {
+ skip = true;
+ break;
+ }
+ } while(shorter.chopOff() && !iter->qname.isRoot());
+ }
+
+ iter->auth = (!skip && (iter->qtype == QType::DS || iter->qtype == QType::RRSIG || !nssets.count(iter->qname)));
+
+ if(!skip && nsec3zone && iter->qtype != QType::RRSIG && (iter->auth || (iter->qtype == QType::NS && !ns3pr.d_flags) || dssets.count(iter->qname))) {
+ Bind2DNSRecord bdr = *iter;
+ bdr.nsec3hash = toBase32Hex(hashQNameWithSalt(ns3pr, bdr.qname+bbd.d_name));
+ records->replace(iter, bdr);
+ }
+
+ // cerr<<iter->qname<<"\t"<<QType(iter->qtype).getName()<<"\t"<<iter->nsec3hash<<"\t"<<iter->auth<<endl;
+ }
+}
+
+void Bind2Backend::doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr)
+{
+ shared_ptr<const recordstorage_t> records = bbd.d_records.get();
+
+ bool auth;
+ DNSName shorter;
+ set<DNSName> qnames;
+ map<DNSName, bool> nonterm;
+
+ uint32_t maxent = ::arg().asNum("max-ent-entries");
+
+ for(const auto& bdr : *records)
+ qnames.insert(bdr.qname);
+
+ for(const auto& bdr : *records) {
+
+ if (!bdr.auth && bdr.qtype == QType::NS)
+ auth = (!nsec3zone || !ns3pr.d_flags);
+ else
+ auth = bdr.auth;
+
+ shorter = bdr.qname;
+ while(shorter.chopOff())
+ {
+ if(!qnames.count(shorter))
+ {
+ if(!(maxent))
+ {
+ L<<Logger::Error<<"Zone '"<<bbd.d_name<<"' has too many empty non terminals."<<endl;
+ return;
+ }
+
+ if (!nonterm.count(shorter)) {
+ nonterm.insert(pair<DNSName, bool>(shorter, auth));
+ --maxent;
+ } else if (auth)
+ nonterm[shorter] = true;
+ }
+ }
+ }
+
+ DNSResourceRecord rr;
+ rr.qtype = "#0";
+ rr.content = "";
+ rr.ttl = 0;
+ for(auto& nt : nonterm)
+ {
+ string hashed;
+ rr.qname = nt.first + bbd.d_name;
+ if(nsec3zone && nt.second)
+ hashed = toBase32Hex(hashQNameWithSalt(ns3pr, rr.qname));
+ insertRecord(bbd, rr.qname, rr.qtype, rr.content, rr.ttl, hashed, &nt.second);
+
+ // cerr<<rr.qname<<"\t"<<rr.qtype.getName()<<"\t"<<hashed<<"\t"<<nt.second<<endl;
+ }
+}
+
+void Bind2Backend::loadConfig(string* status)
+{
+ static int domain_id=1;
+
+ if(!getArg("config").empty()) {
+ BindParser BP;
+ try {
+ BP.parse(getArg("config"));
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"Error parsing bind configuration: "<<ae.reason<<endl;
+ throw;
+ }
+
+ vector<BindDomainInfo> domains=BP.getDomains();
+ this->alsoNotify = BP.getAlsoNotify();
+
+ s_binddirectory=BP.getDirectory();
+ // ZP.setDirectory(d_binddirectory);
+
+ L<<Logger::Warning<<d_logprefix<<" Parsing "<<domains.size()<<" domain(s), will report when done"<<endl;
+
+ set<DNSName> oldnames, newnames;
+ {
+ ReadLock rl(&s_state_lock);
+ for(const BB2DomainInfo& bbd : s_state) {
+ oldnames.insert(bbd.d_name);
+ }
+ }
+ int rejected=0;
+ int newdomains=0;
+
+ struct stat st;
+
+ for(vector<BindDomainInfo>::iterator i=domains.begin(); i!=domains.end(); ++i)
+ {
+ if(stat(i->filename.c_str(), &st) == 0) {
+ i->d_dev = st.st_dev;
+ i->d_ino = st.st_ino;
+ }
+ }
+
+ sort(domains.begin(), domains.end()); // put stuff in inode order
+ for(vector<BindDomainInfo>::const_iterator i=domains.begin();
+ i!=domains.end();
+ ++i)
+ {
+ if(i->type == "") {
+ L<<Logger::Warning<<d_logprefix<<" Warning! Skipping zone '"<<i->name<<"' because it has no type specified"<<endl;
+ rejected++;
+ continue;
+ }
+ if(i->type!="master" && i->type!="slave") {
+ L<<Logger::Warning<<d_logprefix<<" Warning! Skipping zone '"<<i->name<<"' because type '"<<i->type<<"' is invalid"<<endl;
+ rejected++;
+ continue;
+ }
+
+ BB2DomainInfo bbd;
+ bool isNew = false;
+
+ if(!safeGetBBDomainInfo(i->name, &bbd)) {
+ isNew = true;
+ bbd.d_id=domain_id++;
+ bbd.setCheckInterval(getArgAsNum("check-interval"));
+ bbd.d_lastnotified=0;
+ bbd.d_loaded=false;
+ }
+
+ // overwrite what we knew about the domain
+ bbd.d_name=i->name;
+ bool filenameChanged = (bbd.d_filename!=i->filename);
+ bbd.d_filename=i->filename;
+ bbd.d_masters=i->masters;
+ bbd.d_also_notify=i->alsoNotify;
+
+ newnames.insert(bbd.d_name);
+ if(filenameChanged || !bbd.d_loaded || !bbd.current()) {
+ L<<Logger::Info<<d_logprefix<<" parsing '"<<i->name<<"' from file '"<<i->filename<<"'"<<endl;
+
+ try {
+ parseZoneFile(&bbd);
+ }
+ catch(PDNSException &ae) {
+ ostringstream msg;
+ msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.reason;
+
+ if(status)
+ *status+=msg.str();
+ bbd.d_status=msg.str();
+
+ L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
+ rejected++;
+ }
+ catch(std::system_error &ae) {
+ ostringstream msg;
+ if (ae.code().value() == ENOENT && isNew && i->type == "slave")
+ msg<<" error at "+nowTime()<<" no file found for new slave domain '"<<i->name<<"'. Has not been AXFR'd yet";
+ else
+ msg<<" error at "+nowTime()+" parsing '"<<i->name<<"' from file '"<<i->filename<<"': "<<ae.what();
+
+ if(status)
+ *status+=msg.str();
+ bbd.d_status=msg.str();
+ L<<Logger::Warning<<d_logprefix<<msg.str()<<endl;
+ rejected++;
+ }
+ safePutBBDomainInfo(bbd);
+
+ }
+ }
+ vector<DNSName> diff;
+
+ set_difference(oldnames.begin(), oldnames.end(), newnames.begin(), newnames.end(), back_inserter(diff));
+ unsigned int remdomains=diff.size();
+
+ for(const DNSName& name: diff) {
+ safeRemoveBBDomainInfo(name);
+ }
+
+ // count number of entirely new domains
+ diff.clear();
+ set_difference(newnames.begin(), newnames.end(), oldnames.begin(), oldnames.end(), back_inserter(diff));
+ newdomains=diff.size();
+
+ ostringstream msg;
+ msg<<" Done parsing domains, "<<rejected<<" rejected, "<<newdomains<<" new, "<<remdomains<<" removed";
+ if(status)
+ *status=msg.str();
+
+ L<<Logger::Error<<d_logprefix<<msg.str()<<endl;
+ }
+}
+
+void Bind2Backend::queueReloadAndStore(unsigned int id)
+{
+ BB2DomainInfo bbold;
+ try {
+ if(!safeGetBBDomainInfo(id, &bbold))
+ return;
+ BB2DomainInfo bbnew(bbold);
+ parseZoneFile(&bbnew);
+ bbnew.d_checknow=false;
+ bbnew.d_wasRejectedLastReload=false;
+ safePutBBDomainInfo(bbnew);
+ L<<Logger::Warning<<"Zone '"<<bbnew.d_name<<"' ("<<bbnew.d_filename<<") reloaded"<<endl;
+ }
+ catch(PDNSException &ae) {
+ ostringstream msg;
+ msg<<" error at "+nowTime()+" parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.reason;
+ L<<Logger::Warning<<" error parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.reason<<endl;
+ bbold.d_status=msg.str();
+ bbold.d_wasRejectedLastReload=true;
+ safePutBBDomainInfo(bbold);
+ }
+ catch(std::exception &ae) {
+ ostringstream msg;
+ msg<<" error at "+nowTime()+" parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.what();
+ L<<Logger::Warning<<" error parsing '"<<bbold.d_name<<"' from file '"<<bbold.d_filename<<"': "<<ae.what()<<endl;
+ bbold.d_status=msg.str();
+ bbold.d_wasRejectedLastReload=true;
+ safePutBBDomainInfo(bbold);
+ }
+}
+
+bool Bind2Backend::findBeforeAndAfterUnhashed(BB2DomainInfo& bbd, const DNSName& qname, DNSName& unhashed, string& before, string& after)
+{
+ shared_ptr<const recordstorage_t> records = bbd.d_records.get();
+ recordstorage_t::const_iterator iter = records->upper_bound(qname);
+
+ if (before.empty()){
+ //cout<<"starting before for: '"<<domain<<"'"<<endl;
+ iter = records->upper_bound(qname);
+
+ while(iter == records->end() || (qname.canonCompare(iter->qname)) || (!(iter->auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype)))
+ iter--;
+
+ if(iter->qname.empty())
+ before.clear();
+ else {
+ before=iter->qname.labelReverse().toString(" ",false);
+ }
+ }
+ else {
+ if(qname.empty())
+ before.clear();
+ else
+ before=qname.labelReverse().toString(" ",false);
+ }
+
+ //cerr<<"Now after"<<endl;
+ iter = records->upper_bound(qname);
+
+ if(iter == records->end()) {
+ //cerr<<"\tFound the end, begin storage: '"<<bbd.d_records->begin()->qname<<"', '"<<bbd.d_name<<"'"<<endl;
+ after.clear(); // this does the right thing (i.e. point to apex, which is sure to have auth records)
+ } else {
+ //cerr<<"\tFound: '"<<(iter->qname)<<"' (nsec3hash='"<<(iter->nsec3hash)<<"')"<<endl;
+ // this iteration is theoretically unnecessary - glue always sorts right behind a delegation
+ // so we will never get here. But let's do it anyway.
+ while((!(iter->auth) && (!(iter->qtype == QType::NS))) || (!(iter->qtype)))
+ {
+ iter++;
+ if(iter == records->end())
+ {
+ after.clear();
+ break;
+ }
+ }
+ if(iter != records->end())
+ after = (iter)->qname.labelReverse().toString(" ",false);
+ }
+
+ // cerr<<"Before: '"<<before<<"', after: '"<<after<<"'\n";
+ return true;
+}
+
+bool Bind2Backend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, DNSName& unhashed, std::string& before, std::string& after)
+{
+ BB2DomainInfo bbd;
+ safeGetBBDomainInfo(id, &bbd);
+
+ NSEC3PARAMRecordContent ns3pr;
+ DNSName auth=bbd.d_name;
+
+ bool nsec3zone;
+ if (d_hybrid) {
+ DNSSECKeeper dk;
+ nsec3zone=dk.getNSEC3PARAM(auth, &ns3pr);
+ } else
+ nsec3zone=getNSEC3PARAM(auth, &ns3pr);
+
+ if(!nsec3zone) {
+ DNSName dqname = DNSName(labelReverse(qname));
+ //cerr<<"in bind2backend::getBeforeAndAfterAbsolute: no nsec3 for "<<auth<<endl;
+ return findBeforeAndAfterUnhashed(bbd, dqname, unhashed, before, after);
+ }
+ else {
+ typedef recordstorage_t::index<HashedTag>::type records_by_hashindex_t;
+ records_by_hashindex_t& hashindex=boost::multi_index::get<HashedTag>(*bbd.d_records.getWRITABLE());
+
+ records_by_hashindex_t::const_iterator iter, first;
+ first = hashindex.upper_bound(""); // skip records without a hash
+
+ // for(auto iter = first; iter != hashindex.end(); iter++)
+ // cerr<<iter->nsec3hash<<endl;
+
+ iter = hashindex.upper_bound(toLower(qname));
+ if (iter == hashindex.end()) {
+ --iter;
+ before = iter->nsec3hash;
+ after = first->nsec3hash;
+ } else {
+ after = iter->nsec3hash;
+ if (iter != first)
+ --iter;
+ else
+ iter = --hashindex.end();
+ before = iter->nsec3hash;
+ }
+ unhashed = iter->qname+bbd.d_name;
+
+ return true;
+ }
+}
+
+void Bind2Backend::lookup(const QType &qtype, const DNSName &qname, DNSPacket *pkt_p, int zoneId )
+{
+ d_handle.reset();
+ DNSName domain(qname);
+
+ static bool mustlog=::arg().mustDo("query-logging");
+ if(mustlog)
+ L<<Logger::Warning<<"Lookup for '"<<qtype.getName()<<"' of '"<<domain<<"' within zoneID "<<zoneId<<endl;
+ bool found=false;
+ BB2DomainInfo bbd;
+
+ do {
+ found = safeGetBBDomainInfo(domain, &bbd);
+ } while ((!found || (zoneId != (int)bbd.d_id && zoneId != -1)) && domain.chopOff());
+
+ if(!found) {
+ if(mustlog)
+ L<<Logger::Warning<<"Found no authoritative zone for "<<qname<<endl;
+ d_handle.d_list=false;
+ return;
+ }
+
+ if(mustlog)
+ L<<Logger::Warning<<"Found a zone '"<<domain<<"' (with id " << bbd.d_id<<") that might contain data "<<endl;
+
+ d_handle.id=bbd.d_id;
+
+ DLOG(L<<"Bind2Backend constructing handle for search for "<<qtype.getName()<<" for "<<
+ qname<<endl);
+
+ if(domain.empty())
+ d_handle.qname=qname;
+ else if(qname.isPartOf(domain))
+ d_handle.qname=qname.makeRelative(domain); // strip domain name
+
+ d_handle.qtype=qtype;
+ d_handle.domain=domain;
+
+ if(!bbd.d_loaded) {
+ d_handle.reset();
+ throw DBException("Zone for '"+bbd.d_name.toLogString()+"' in '"+bbd.d_filename+"' temporarily not available (file missing, or master dead)"); // fsck
+ }
+
+ if(!bbd.current()) {
+ L<<Logger::Warning<<"Zone '"<<bbd.d_name<<"' ("<<bbd.d_filename<<") needs reloading"<<endl;
+ queueReloadAndStore(bbd.d_id);
+ if (!safeGetBBDomainInfo(domain, &bbd))
+ throw DBException("Zone '"+bbd.d_name.toLogString()+"' ("+bbd.d_filename+") gone after reload"); // if we don't throw here, we crash for some reason
+ }
+
+ d_handle.d_records = bbd.d_records.get();
+
+ if(d_handle.d_records->empty())
+ DLOG(L<<"Query with no results"<<endl);
+
+ pair<recordstorage_t::const_iterator, recordstorage_t::const_iterator> range;
+
+ range = d_handle.d_records->equal_range(d_handle.qname);
+ //cout<<"End equal range"<<endl;
+ d_handle.mustlog = mustlog;
+
+ if(range.first==range.second) {
+ // cerr<<"Found nothing!"<<endl;
+ d_handle.d_list=false;
+ d_handle.d_iter = d_handle.d_end_iter = range.first;
+ return;
+ }
+ else {
+ // cerr<<"Found something!"<<endl;
+ d_handle.d_iter=range.first;
+ d_handle.d_end_iter=range.second;
+ }
+
+ d_handle.d_list=false;
+}
+
+Bind2Backend::handle::handle()
+{
+ mustlog=false;
+}
+
+bool Bind2Backend::get(DNSResourceRecord &r)
+{
+ if(!d_handle.d_records) {
+ if(d_handle.mustlog)
+ L<<Logger::Warning<<"There were no answers"<<endl;
+ return false;
+ }
+
+ if(!d_handle.get(r)) {
+ if(d_handle.mustlog)
+ L<<Logger::Warning<<"End of answers"<<endl;
+
+ d_handle.reset();
+
+ return false;
+ }
+ if(d_handle.mustlog)
+ L<<Logger::Warning<<"Returning: '"<<r.qtype.getName()<<"' of '"<<r.qname<<"', content: '"<<r.content<<"'"<<endl;
+ return true;
+}
+
+bool Bind2Backend::handle::get(DNSResourceRecord &r)
+{
+ if(d_list)
+ return get_list(r);
+ else
+ return get_normal(r);
+}
+
+void Bind2Backend::handle::reset()
+{
+ d_records.reset();
+ qname.clear();
+ mustlog=false;
+}
+
+//#define DLOG(x) x
+bool Bind2Backend::handle::get_normal(DNSResourceRecord &r)
+{
+ DLOG(L << "Bind2Backend get() was called for "<<qtype.getName() << " record for '"<<
+ qname<<"' - "<<d_records->size()<<" available in total!"<<endl);
+
+ if(d_iter==d_end_iter) {
+ return false;
+ }
+
+ while(d_iter!=d_end_iter && !(qtype.getCode()==QType::ANY || (d_iter)->qtype==qtype.getCode())) {
+ DLOG(L<<Logger::Warning<<"Skipped "<<qname<<"/"<<QType(d_iter->qtype).getName()<<": '"<<d_iter->content<<"'"<<endl);
+ d_iter++;
+ }
+ if(d_iter==d_end_iter) {
+ return false;
+ }
+ DLOG(L << "Bind2Backend get() returning a rr with a "<<QType(d_iter->qtype).getCode()<<endl);
+
+ r.qname=qname.empty() ? domain : (qname+domain);
+ r.domain_id=id;
+ r.content=(d_iter)->content;
+ // r.domain_id=(d_iter)->domain_id;
+ r.qtype=(d_iter)->qtype;
+ r.ttl=(d_iter)->ttl;
+
+ //if(!d_iter->auth && r.qtype.getCode() != QType::A && r.qtype.getCode()!=QType::AAAA && r.qtype.getCode() != QType::NS)
+ // cerr<<"Warning! Unauth response for qtype "<< r.qtype.getName() << " for '"<<r.qname<<"'"<<endl;
+ r.auth = d_iter->auth;
+
+ d_iter++;
+
+ return true;
+}
+
+bool Bind2Backend::list(const DNSName& target, int id, bool include_disabled)
+{
+ BB2DomainInfo bbd;
+
+ if(!safeGetBBDomainInfo(id, &bbd))
+ return false;
+
+ d_handle.reset();
+ DLOG(L<<"Bind2Backend constructing handle for list of "<<id<<endl);
+
+ d_handle.d_records=bbd.d_records.get(); // give it a copy, which will stay around
+ d_handle.d_qname_iter= d_handle.d_records->begin();
+ d_handle.d_qname_end=d_handle.d_records->end(); // iter now points to a vector of pointers to vector<BBResourceRecords>
+
+ d_handle.id=id;
+ d_handle.domain=bbd.d_name;
+ d_handle.d_list=true;
+ return true;
+}
+
+bool Bind2Backend::handle::get_list(DNSResourceRecord &r)
+{
+ if(d_qname_iter!=d_qname_end) {
+ r.qname=d_qname_iter->qname.empty() ? domain : (d_qname_iter->qname+domain);
+ r.domain_id=id;
+ r.content=(d_qname_iter)->content;
+ r.qtype=(d_qname_iter)->qtype;
+ r.ttl=(d_qname_iter)->ttl;
+ r.auth = d_qname_iter->auth;
+ d_qname_iter++;
+ return true;
+ }
+ return false;
+}
+
+bool Bind2Backend::isMaster(const DNSName& name, const string &ip)
+{
+ BB2DomainInfo bbd;
+ if(!safeGetBBDomainInfo(name, &bbd))
+ return false;
+
+ for(vector<string>::const_iterator iter = bbd.d_masters.begin(); iter != bbd.d_masters.end(); ++iter)
+ if(*iter==ip)
+ return true;
+
+ return false;
+}
+
+bool Bind2Backend::superMasterBackend(const string &ip, const DNSName& domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
+{
+ // Check whether we have a configfile available.
+ if (getArg("supermaster-config").empty())
+ return false;
+
+ ifstream c_if(getArg("supermasters").c_str(), std::ios::in); // this was nocreate?
+ if (!c_if) {
+ L << Logger::Error << "Unable to open supermasters file for read: " << stringerror() << endl;
+ return false;
+ }
+
+ // Format:
+ // <ip> <accountname>
+ string line, sip, saccount;
+ while (getline(c_if, line)) {
+ std::istringstream ii(line);
+ ii >> sip;
+ if (sip == ip) {
+ ii >> saccount;
+ break;
+ }
+ }
+ c_if.close();
+
+ if (sip != ip) // ip not found in authorization list - reject
+ return false;
+
+ // ip authorized as supermaster - accept
+ *db = this;
+ if (saccount.length() > 0)
+ *account = saccount.c_str();
+
+ return true;
+}
+
+BB2DomainInfo Bind2Backend::createDomainEntry(const DNSName& domain, const string &filename)
+{
+ int newid=1;
+ { // Find a free zone id nr.
+ ReadLock rl(&s_state_lock);
+ if (!s_state.empty()) {
+ newid = s_state.rbegin()->d_id+1;
+ }
+ }
+
+ BB2DomainInfo bbd;
+ bbd.d_id = newid;
+ bbd.d_records = shared_ptr<recordstorage_t >(new recordstorage_t);
+ bbd.d_name = domain;
+ bbd.setCheckInterval(getArgAsNum("check-interval"));
+ bbd.d_filename = filename;
+ return bbd;
+}
+
+bool Bind2Backend::createSlaveDomain(const string &ip, const DNSName& domain, const string &nameserver, const string &account)
+{
+ string filename = getArg("supermaster-destdir")+'/'+domain.toStringNoDot();
+
+ L << Logger::Warning << d_logprefix
+ << " Writing bind config zone statement for superslave zone '" << domain
+ << "' from supermaster " << ip << endl;
+
+ {
+ Lock l2(&s_supermaster_config_lock);
+
+ ofstream c_of(getArg("supermaster-config").c_str(), std::ios::app);
+ if (!c_of) {
+ L << Logger::Error << "Unable to open supermaster configfile for append: " << stringerror() << endl;
+ throw DBException("Unable to open supermaster configfile for append: "+stringerror());
+ }
+
+ c_of << endl;
+ c_of << "# Superslave zone '" << domain.toString() << "' (added: " << nowTime() << ") (account: " << account << ')' << endl;
+ c_of << "zone \"" << domain.toStringNoDot() << "\" {" << endl;
+ c_of << "\ttype slave;" << endl;
+ c_of << "\tfile \"" << filename << "\";" << endl;
+ c_of << "\tmasters { " << ip << "; };" << endl;
+ c_of << "};" << endl;
+ c_of.close();
+ }
+
+ BB2DomainInfo bbd = createDomainEntry(domain, filename);
+ bbd.d_masters.push_back(ip);
+ safePutBBDomainInfo(bbd);
+ return true;
+}
+
+bool Bind2Backend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
+{
+ SimpleMatch sm(pattern,true);
+ static bool mustlog=::arg().mustDo("query-logging");
+ if(mustlog)
+ L<<Logger::Warning<<"Search for pattern '"<<pattern<<"'"<<endl;
+
+ {
+ ReadLock rl(&s_state_lock);
+
+ for(state_t::const_iterator i = s_state.begin(); i != s_state.end() ; ++i) {
+ BB2DomainInfo h;
+ safeGetBBDomainInfo(i->d_id, &h);
+ shared_ptr<const recordstorage_t> handle = h.d_records.get();
+
+ for(recordstorage_t::const_iterator ri = handle->begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && ri != handle->end(); ri++) {
+ DNSName name = ri->qname.empty() ? i->d_name : (ri->qname+i->d_name);
+ if (sm.match(name) || sm.match(ri->content)) {
+ DNSResourceRecord r;
+ r.qname=name;
+ r.domain_id=i->d_id;
+ r.content=ri->content;
+ r.qtype=ri->qtype;
+ r.ttl=ri->ttl;
+ r.auth = ri->auth;
+ result.push_back(r);
+ }
+ }
+ }
+ }
+
+ return true;
+}
+
+class Bind2Factory : public BackendFactory
+{
+ public:
+ Bind2Factory() : BackendFactory("bind") {}
+
+ void declareArguments(const string &suffix="")
+ {
+ declare(suffix,"ignore-broken-records","Ignore records that are out-of-bound for the zone.","no");
+ declare(suffix,"config","Location of named.conf","");
+ declare(suffix,"check-interval","Interval for zonefile changes","0");
+ declare(suffix,"supermaster-config","Location of (part of) named.conf where pdns can write zone-statements to","");
+ declare(suffix,"supermasters","List of IP-addresses of supermasters","");
+ declare(suffix,"supermaster-destdir","Destination directory for newly added slave zones",::arg()["config-dir"]);
+ declare(suffix,"dnssec-db","Filename to store & access our DNSSEC metadatabase, empty for none", "");
+ declare(suffix,"hybrid","Store DNSSEC metadata in other backend","no");
+ }
+
+ DNSBackend *make(const string &suffix="")
+ {
+ return new Bind2Backend(suffix);
+ }
+
+ DNSBackend *makeMetadataOnly(const string &suffix="")
+ {
+ return new Bind2Backend(suffix, false);
+ }
+};
+
+//! Magic class that is activated when the dynamic library is loaded
+class Bind2Loader
+{
+public:
+ Bind2Loader()
+ {
+ BackendMakers().report(new Bind2Factory);
+ L << Logger::Info << "[bind2backend] This is the bind backend version " << VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+static Bind2Loader bind2loader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PDNS_BINDBACKEND_HH
+#define PDNS_BINDBACKEND_HH
+
+#include <string>
+#include <map>
+#include <set>
+#include <pthread.h>
+#include <time.h>
+#include <fstream>
+#include <boost/utility.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/member.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "pdns/lock.hh"
+#include "pdns/misc.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/namespaces.hh"
+#include "pdns/backends/gsql/ssql.hh"
+
+using namespace ::boost::multi_index;
+
+/**
+ This struct is used within the Bind2Backend to store DNS information. It is
+ almost identical to a DNSResourceRecord, but then a bit smaller and with
+ different sorting rules, which make sure that the SOA record comes up front.
+*/
+
+struct Bind2DNSRecord
+{
+ DNSName qname;
+ string content;
+ string nsec3hash;
+ uint32_t ttl;
+ uint16_t qtype;
+ mutable bool auth;
+ bool operator<(const Bind2DNSRecord& rhs) const
+ {
+ if(qname.canonCompare(rhs.qname))
+ return true;
+ if(rhs.qname.canonCompare(qname))
+ return false;
+ if(qtype==QType::SOA && rhs.qtype!=QType::SOA)
+ return true;
+ return tie(qtype,content, ttl) < tie(rhs.qtype, rhs.content, rhs.ttl);
+ }
+};
+
+struct Bind2DNSCompare : std::less<Bind2DNSRecord>
+{
+ using std::less<Bind2DNSRecord>::operator();
+ // use operator<
+ bool operator() (const DNSName& a, const Bind2DNSRecord& b) const
+ {return a.canonCompare(b.qname);}
+ bool operator() (const Bind2DNSRecord& a, const DNSName& b) const
+ {return a.qname.canonCompare(b);}
+ bool operator() (const Bind2DNSRecord& a, const Bind2DNSRecord& b) const
+ {return a.qname.canonCompare(b.qname);}
+};
+
+struct HashedTag{};
+
+typedef multi_index_container<
+ Bind2DNSRecord,
+ indexed_by <
+ ordered_non_unique<identity<Bind2DNSRecord>, Bind2DNSCompare >,
+ ordered_non_unique<tag<HashedTag>, member<Bind2DNSRecord, std::string, &Bind2DNSRecord::nsec3hash> >
+ >
+> recordstorage_t;
+
+template <typename T>
+class LookButDontTouch // : public boost::noncopyable
+{
+public:
+ LookButDontTouch()
+ {
+ pthread_mutex_init(&d_lock, 0);
+ pthread_mutex_init(&d_swaplock, 0);
+ }
+ LookButDontTouch(shared_ptr<T> records) : d_records(records)
+ {
+ pthread_mutex_init(&d_lock, 0);
+ pthread_mutex_init(&d_swaplock, 0);
+ }
+
+ shared_ptr<const T> get()
+ {
+ shared_ptr<const T> ret;
+ {
+ Lock l(&d_lock);
+ ret = d_records;
+ }
+ return ret;
+ }
+
+ shared_ptr<T> getWRITABLE()
+ {
+ shared_ptr<T> ret;
+ {
+ Lock l(&d_lock);
+ ret = d_records;
+ }
+ return ret;
+ }
+
+
+ void swap(shared_ptr<T> records)
+ {
+ Lock l(&d_lock);
+ Lock l2(&d_swaplock);
+ d_records.swap(records);
+ }
+ pthread_mutex_t d_lock;
+ pthread_mutex_t d_swaplock;
+private:
+ shared_ptr<T> d_records;
+};
+
+
+/** Class which describes all metadata of a domain for storage by the Bind2Backend, and also contains a pointer to a vector of Bind2DNSRecord's */
+class BB2DomainInfo
+{
+public:
+ BB2DomainInfo();
+ void setCtime();
+ bool current();
+ //! configure how often this domain should be checked for changes (on disk)
+ void setCheckInterval(time_t seconds);
+
+ DNSName d_name; //!< actual name of the domain
+ string d_filename; //!< full absolute filename of the zone on disk
+ string d_status; //!< message describing status of a domain, for human consumption
+ vector<string> d_masters; //!< IP address of the master of this domain
+ set<string> d_also_notify; //!< IP list of hosts to also notify
+ LookButDontTouch<recordstorage_t> d_records; //!< the actual records belonging to this domain
+ time_t d_ctime; //!< last known ctime of the file on disk
+ time_t d_lastcheck; //!< last time domain was checked for freshness
+ uint32_t d_lastnotified; //!< Last serial number we notified our slaves of
+ unsigned int d_id; //!< internal id of the domain
+ mutable bool d_checknow; //!< if this domain has been flagged for a check
+ bool d_loaded; //!< if a domain is loaded
+ bool d_wasRejectedLastReload{false}; //!< if the domain was rejected during Bind2Backend::queueReloadAndStore
+
+private:
+ time_t getCtime();
+ time_t d_checkinterval;
+};
+
+class SSQLite3;
+class NSEC3PARAMRecordContent;
+
+struct NameTag
+{};
+
+class Bind2Backend : public DNSBackend
+{
+public:
+ Bind2Backend(const string &suffix="", bool loadZones=true);
+ ~Bind2Backend();
+ void getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains);
+ void getUpdatedMasters(vector<DomainInfo> *changedDomains);
+ bool getDomainInfo(const DNSName &domain, DomainInfo &di);
+ time_t getCtime(const string &fname);
+ // DNSSEC
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, string& before, string& after);
+ void lookup(const QType &, const DNSName &qdomain, DNSPacket *p=0, int zoneId=-1);
+ bool list(const DNSName &target, int id, bool include_disabled=false);
+ bool get(DNSResourceRecord &);
+ void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false);
+
+ static DNSBackend *maker();
+ static pthread_mutex_t s_startup_lock;
+
+ void setFresh(uint32_t domain_id);
+ void setNotified(uint32_t id, uint32_t serial);
+ bool startTransaction(const DNSName &qname, int id);
+ bool feedRecord(const DNSResourceRecord &rr, string *ordername=0);
+ bool commitTransaction();
+ bool abortTransaction();
+ void alsoNotifies(const DNSName &domain, set<string> *ips);
+ bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
+
+// the DNSSEC related (getDomainMetadata has broader uses too)
+ virtual bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta);
+ virtual bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys);
+ virtual bool removeDomainKey(const DNSName& name, unsigned int id);
+ virtual int addDomainKey(const DNSName& name, const KeyData& key);
+ virtual bool activateDomainKey(const DNSName& name, unsigned int id);
+ virtual bool deactivateDomainKey(const DNSName& name, unsigned int id);
+ virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content);
+ virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
+ virtual bool deleteTSIGKey(const DNSName& name);
+ virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys);
+ virtual bool doesDNSSEC();
+ // end of DNSSEC
+
+ typedef multi_index_container < BB2DomainInfo ,
+ indexed_by < ordered_unique<member<BB2DomainInfo, unsigned int, &BB2DomainInfo::d_id> >,
+ ordered_unique<tag<NameTag>, member<BB2DomainInfo, DNSName, &BB2DomainInfo::d_name> >
+ > > state_t;
+ static state_t s_state;
+ static pthread_rwlock_t s_state_lock;
+
+ void parseZoneFile(BB2DomainInfo *bbd);
+ void insertRecord(BB2DomainInfo& bbd, const DNSName &qname, const QType &qtype, const string &content, int ttl, const std::string& hashed=string(), bool *auth=0);
+ void rediscover(string *status=0);
+
+ bool isMaster(const DNSName &name, const string &ip);
+
+ // for supermaster support
+ bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db);
+ static pthread_mutex_t s_supermaster_config_lock;
+ bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account);
+
+private:
+ void setupDNSSEC();
+ void setupStatements();
+ void freeStatements();
+ void release(SSqlStatement**);
+ static bool safeGetBBDomainInfo(int id, BB2DomainInfo* bbd);
+ static void safePutBBDomainInfo(const BB2DomainInfo& bbd);
+ static bool safeGetBBDomainInfo(const DNSName& name, BB2DomainInfo* bbd);
+ static bool safeRemoveBBDomainInfo(const DNSName& name);
+ bool GetBBDomainInfo(int id, BB2DomainInfo** bbd);
+ shared_ptr<SSQLite3> d_dnssecdb;
+ bool getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p);
+ class handle
+ {
+ public:
+ bool get(DNSResourceRecord &);
+ void reset();
+
+ handle();
+
+ shared_ptr<const recordstorage_t > d_records;
+ recordstorage_t::const_iterator d_iter, d_end_iter;
+ recordstorage_t::const_iterator d_qname_iter;
+ recordstorage_t::const_iterator d_qname_end;
+ DNSName qname;
+ DNSName domain;
+
+ int id;
+ QType qtype;
+ bool d_list;
+ bool mustlog;
+
+ private:
+ bool get_normal(DNSResourceRecord &);
+ bool get_list(DNSResourceRecord &);
+
+ void operator=(const handle& ); // don't go copying this
+ handle(const handle &);
+ };
+
+ SSqlStatement* d_getAllDomainMetadataQuery_stmt;
+ SSqlStatement* d_getDomainMetadataQuery_stmt;
+ SSqlStatement* d_deleteDomainMetadataQuery_stmt;
+ SSqlStatement* d_insertDomainMetadataQuery_stmt;
+ SSqlStatement* d_getDomainKeysQuery_stmt;
+ SSqlStatement* d_deleteDomainKeyQuery_stmt;
+ SSqlStatement* d_insertDomainKeyQuery_stmt;
+ SSqlStatement* d_activateDomainKeyQuery_stmt;
+ SSqlStatement* d_deactivateDomainKeyQuery_stmt;
+ SSqlStatement* d_getTSIGKeyQuery_stmt;
+ SSqlStatement* d_setTSIGKeyQuery_stmt;
+ SSqlStatement* d_deleteTSIGKeyQuery_stmt;
+ SSqlStatement* d_getTSIGKeysQuery_stmt;
+
+ string d_transaction_tmpname;
+ string d_logprefix;
+ set<string> alsoNotify; //!< this is used to store the also-notify list of interested peers.
+ ofstream *d_of;
+ handle d_handle;
+ static string s_binddirectory; //!< this is used to store the 'directory' setting of the bind configuration
+ static int s_first; //!< this is raised on construction to prevent multiple instances of us being generated
+ int d_transaction_id;
+ static bool s_ignore_broken_records;
+ bool d_hybrid;
+
+ BB2DomainInfo createDomainEntry(const DNSName& domain, const string &filename); //!< does not insert in s_state
+
+ void queueReloadAndStore(unsigned int id);
+ bool findBeforeAndAfterUnhashed(BB2DomainInfo& bbd, const DNSName& qname, DNSName& unhashed, string& before, string& after);
+ void reload();
+ static string DLDomStatusHandler(const vector<string>&parts, Utility::pid_t ppid);
+ static string DLListRejectsHandler(const vector<string>&parts, Utility::pid_t ppid);
+ static string DLReloadNowHandler(const vector<string>&parts, Utility::pid_t ppid);
+ static string DLAddDomainHandler(const vector<string>&parts, Utility::pid_t ppid);
+ static void fixupOrderAndAuth(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr);
+ void doEmptyNonTerminals(BB2DomainInfo& bbd, bool nsec3zone, NSEC3PARAMRecordContent ns3pr);
+ void loadConfig(string *status=0);
+ static void nukeZoneRecords(BB2DomainInfo *bbd);
+
+};
+
+#endif /* PDNS_BINDBACKEND_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "bindbackend2.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnsrecords.hh"
+
+#ifndef HAVE_SQLITE3
+
+void Bind2Backend::setupDNSSEC()
+{
+ if(!getArg("dnssec-db").empty())
+ throw runtime_error("bind-dnssec-db requires building PowerDNS with SQLite3");
+}
+
+bool Bind2Backend::doesDNSSEC()
+{ return d_hybrid; }
+
+bool Bind2Backend::getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p)
+{ return false; }
+
+bool Bind2Backend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
+{ return false; }
+
+bool Bind2Backend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
+{ return false; }
+
+bool Bind2Backend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
+{ return false; }
+
+bool Bind2Backend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys)
+{ return false; }
+
+bool Bind2Backend::removeDomainKey(const DNSName& name, unsigned int id)
+{ return false; }
+
+int Bind2Backend::addDomainKey(const DNSName& name, const KeyData& key)
+{ return -1; }
+
+bool Bind2Backend::activateDomainKey(const DNSName& name, unsigned int id)
+{ return false; }
+
+bool Bind2Backend::deactivateDomainKey(const DNSName& name, unsigned int id)
+{ return false; }
+
+bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
+{ return false; }
+
+bool Bind2Backend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
+{ return false; }
+
+bool Bind2Backend::deleteTSIGKey(const DNSName& name)
+{ return false; }
+
+bool Bind2Backend::getTSIGKeys(std::vector<struct TSIGKey> &keys)
+{ return false; }
+
+void Bind2Backend::setupStatements()
+{ return; }
+
+void Bind2Backend::freeStatements()
+{ return; }
+
+#else
+
+#include "pdns/bind-dnssec.schema.sqlite3.sql.h"
+#include "pdns/logger.hh"
+#include "pdns/ssqlite3.hh"
+
+void Bind2Backend::setupDNSSEC()
+{
+ if(getArg("dnssec-db").empty() || d_hybrid)
+ return;
+ try {
+ d_dnssecdb = shared_ptr<SSQLite3>(new SSQLite3(getArg("dnssec-db")));
+ setupStatements();
+ }
+ catch(SSqlException& se) {
+ // this error is meant to kill the server dead - it makes no sense to continue..
+ throw runtime_error("Error opening DNSSEC database in BIND backend: "+se.txtReason());
+ }
+
+ d_dnssecdb->setLog(::arg().mustDo("query-logging"));
+}
+
+void Bind2Backend::setupStatements()
+{
+ d_getAllDomainMetadataQuery_stmt = d_dnssecdb->prepare("select kind, content from domainmetadata where domain=:domain",1);
+ d_getDomainMetadataQuery_stmt = d_dnssecdb->prepare("select content from domainmetadata where domain=:domain and kind=:kind",2);
+ d_deleteDomainMetadataQuery_stmt = d_dnssecdb->prepare("delete from domainmetadata where domain=:domain and kind=:kind",2);
+ d_insertDomainMetadataQuery_stmt = d_dnssecdb->prepare("insert into domainmetadata (domain, kind, content) values (:domain,:kind,:content)",3);
+ d_getDomainKeysQuery_stmt = d_dnssecdb->prepare("select id,flags, active, content from cryptokeys where domain=:domain",1);
+ d_deleteDomainKeyQuery_stmt = d_dnssecdb->prepare("delete from cryptokeys where domain=:domain and id=:key_id",2);
+ d_insertDomainKeyQuery_stmt = d_dnssecdb->prepare("insert into cryptokeys (domain, flags, active, content) values (:domain, :flags, :active, :content)", 4);
+ d_activateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=1 where domain=:domain and id=:key_id", 2);
+ d_deactivateDomainKeyQuery_stmt = d_dnssecdb->prepare("update cryptokeys set active=0 where domain=:domain and id=:key_id", 2);
+ d_getTSIGKeyQuery_stmt = d_dnssecdb->prepare("select algorithm, secret from tsigkeys where name=:key_name", 1);
+ d_setTSIGKeyQuery_stmt = d_dnssecdb->prepare("replace into tsigkeys (name,algorithm,secret) values(:key_name, :algorithm, :content)", 3);
+ d_deleteTSIGKeyQuery_stmt = d_dnssecdb->prepare("delete from tsigkeys where name=:key_name", 1);
+ d_getTSIGKeysQuery_stmt = d_dnssecdb->prepare("select name,algorithm,secret from tsigkeys", 0);
+}
+
+void Bind2Backend::release(SSqlStatement** stmt) {
+ delete *stmt;
+ *stmt = NULL;
+}
+
+void Bind2Backend::freeStatements()
+{
+ release(&d_getAllDomainMetadataQuery_stmt);
+ release(&d_getDomainMetadataQuery_stmt);
+ release(&d_deleteDomainMetadataQuery_stmt);
+ release(&d_insertDomainMetadataQuery_stmt);
+ release(&d_getDomainKeysQuery_stmt);
+ release(&d_deleteDomainKeyQuery_stmt);
+ release(&d_insertDomainKeyQuery_stmt);
+ release(&d_activateDomainKeyQuery_stmt);
+ release(&d_deactivateDomainKeyQuery_stmt);
+ release(&d_getTSIGKeyQuery_stmt);
+ release(&d_setTSIGKeyQuery_stmt);
+ release(&d_deleteTSIGKeyQuery_stmt);
+ release(&d_getTSIGKeysQuery_stmt);
+}
+
+bool Bind2Backend::doesDNSSEC()
+{
+ return d_dnssecdb || d_hybrid;
+}
+
+bool Bind2Backend::getNSEC3PARAM(const DNSName& name, NSEC3PARAMRecordContent* ns3p)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ string value;
+ vector<string> meta;
+ getDomainMetadata(name, "NSEC3PARAM", meta);
+ if(!meta.empty())
+ value=*meta.begin();
+ else
+ return false; // No NSEC3 zone
+
+ static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
+ if(ns3p) {
+ NSEC3PARAMRecordContent* tmp=dynamic_cast<NSEC3PARAMRecordContent*>(DNSRecordContent::mastermake(QType::NSEC3PARAM, 1, value));
+ *ns3p = *tmp;
+ delete tmp;
+
+ if (ns3p->d_iterations > maxNSEC3Iterations) {
+ ns3p->d_iterations = maxNSEC3Iterations;
+ L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<name<<"' is above 'max-nsec3-iterations'. Value adjsted to: "<<maxNSEC3Iterations<<endl;
+ }
+
+ if (ns3p->d_algorithm != 1) {
+ L<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<name<<"'."<<endl;
+ ns3p->d_algorithm = 1;
+ }
+ }
+
+ return true;
+}
+
+bool Bind2Backend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_getAllDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ execute();
+
+ SSqlStatement::row_t row;
+ while(d_getAllDomainMetadataQuery_stmt->hasNextRow()) {
+ d_getAllDomainMetadataQuery_stmt->nextRow(row);
+ meta[row[0]].push_back(row[1]);
+ }
+
+ d_getAllDomainMetadataQuery_stmt->reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, getAllDomainMetadata(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_getDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ execute();
+
+ SSqlStatement::row_t row;
+ while(d_getDomainMetadataQuery_stmt->hasNextRow()) {
+ d_getDomainMetadataQuery_stmt->nextRow(row);
+ meta.push_back(row[0]);
+ }
+
+ d_getDomainMetadataQuery_stmt->reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainMetadata(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_deleteDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ execute()->
+ reset();
+ if(!meta.empty()) {
+ for(const auto& value: meta) {
+ d_insertDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ bind("content", value)->
+ execute()->
+ reset();
+ }
+ }
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, setDomainMetadata(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_getDomainKeysQuery_stmt->
+ bind("domain", name)->
+ execute();
+
+ KeyData kd;
+ SSqlStatement::row_t row;
+ while(d_getDomainKeysQuery_stmt->hasNextRow()) {
+ d_getDomainKeysQuery_stmt->nextRow(row);
+ kd.id = pdns_stou(row[0]);
+ kd.flags = pdns_stou(row[1]);
+ kd.active = (row[2] == "1");
+ kd.content = row[3];
+ keys.push_back(kd);
+ }
+
+ d_getDomainKeysQuery_stmt->reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, getDomainKeys(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::removeDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_deleteDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, removeDomainKeys(): "+se.txtReason());
+ }
+ return true;
+}
+
+int Bind2Backend::addDomainKey(const DNSName& name, const KeyData& key)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return -1;
+
+ try {
+ d_insertDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("flags", key.flags)->
+ bind("active", key.active)->
+ bind("content", key.content)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, addDomainKey(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::activateDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_activateDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, activateDomainKey(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::deactivateDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_deactivateDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, deactivateDomainKey(): "+se.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_getTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ execute();
+
+ SSqlStatement::row_t row;
+ content->clear();
+ while(d_getTSIGKeyQuery_stmt->hasNextRow()) {
+ d_getTSIGKeyQuery_stmt->nextRow(row);
+ if(row.size() >= 2 && (algorithm->empty() || *algorithm == DNSName(row[0]))) {
+ *algorithm = DNSName(row[0]);
+ *content = row[1];
+ }
+ }
+
+ d_getTSIGKeyQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKey(): "+e.txtReason());
+ }
+ return !content->empty();
+}
+
+bool Bind2Backend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_setTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ bind("algorithm", algorithm)->
+ bind("content", content)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, setTSIGKey(): "+e.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::deleteTSIGKey(const DNSName& name)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_deleteTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, deleteTSIGKey(): "+e.txtReason());
+ }
+ return true;
+}
+
+bool Bind2Backend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
+{
+ if(!d_dnssecdb || d_hybrid)
+ return false;
+
+ try {
+ d_getTSIGKeysQuery_stmt->
+ execute();
+
+ SSqlStatement::row_t row;
+ while(d_getTSIGKeysQuery_stmt->hasNextRow()) {
+ d_getTSIGKeysQuery_stmt->nextRow(row);
+ struct TSIGKey key;
+ key.name = DNSName(row[0]);
+ key.algorithm = DNSName(row[1]);
+ key.key = row[2];
+ keys.push_back(key);
+ }
+
+ d_getTSIGKeysQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Error accessing DNSSEC database in BIND backend, getTSIGKeys(): "+e.txtReason());
+ }
+ return !keys.empty();
+}
+
+#endif
--- /dev/null
+AM_CPPFLAGS += $(YAML_CFLAGS) $(GEOIP_CFLAGS)
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+pkglib_LTLIBRARIES = libgeoipbackend.la
+
+libgeoipbackend_la_SOURCES = geoipbackend.cc geoipbackend.hh
+libgeoipbackend_la_LDFLAGS = -module -avoid-version
+libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/geoipbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgeoipbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1)
+am_libgeoipbackend_la_OBJECTS = geoipbackend.lo
+libgeoipbackend_la_OBJECTS = $(am_libgeoipbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgeoipbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgeoipbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgeoipbackend_la_SOURCES)
+DIST_SOURCES = $(libgeoipbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(YAML_CFLAGS) $(GEOIP_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+pkglib_LTLIBRARIES = libgeoipbackend.la
+libgeoipbackend_la_SOURCES = geoipbackend.cc geoipbackend.hh
+libgeoipbackend_la_LDFLAGS = -module -avoid-version
+libgeoipbackend_la_LIBADD = $(YAML_LIBS) $(GEOIP_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/geoipbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/geoipbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgeoipbackend.la: $(libgeoipbackend_la_OBJECTS) $(libgeoipbackend_la_DEPENDENCIES) $(EXTRA_libgeoipbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgeoipbackend_la_LINK) -rpath $(pkglibdir) $(libgeoipbackend_la_OBJECTS) $(libgeoipbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/geoipbackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+geoipbackend.lo
--- /dev/null
+$(YAML_LIBS) $(GEOIP_LIBS)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "geoipbackend.hh"
+#include <sstream>
+#include <regex.h>
+#include <glob.h>
+#include <boost/algorithm/string/replace.hpp>
+
+pthread_rwlock_t GeoIPBackend::s_state_lock=PTHREAD_RWLOCK_INITIALIZER;
+
+struct GeoIPDNSResourceRecord: DNSResourceRecord {
+public:
+ int weight;
+ bool has_weight;
+};
+
+class GeoIPDomain {
+public:
+ int id;
+ DNSName domain;
+ int ttl;
+ map<DNSName, NetmaskTree<vector<string> > > services;
+ map<DNSName, vector<GeoIPDNSResourceRecord> > records;
+};
+
+static vector<GeoIPDomain> s_domains;
+static int s_rc = 0; // refcount
+
+struct geoip_deleter {
+ void operator()(GeoIP* ptr) {
+ if (ptr) GeoIP_delete(ptr);
+ };
+};
+
+static vector<GeoIPBackend::geoip_file_t> s_geoip_files;
+
+static string GeoIP_WEEKDAYS[] = { "mon", "tue", "wed", "thu", "fri", "sat", "sun" };
+static string GeoIP_MONTHS[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" };
+
+/* So how does it work - we have static records and services. Static records "win".
+ We also insert empty non terminals for records and services.
+
+ If a service makes an internal reference to a domain also hosted within geoip, we give a direct
+ answers, no CNAMEs involved.
+
+ If the reference is external, we spoof up a CNAME, and good luck with that
+*/
+
+GeoIPBackend::GeoIPBackend(const string& suffix) {
+ WriteLock wl(&s_state_lock);
+ d_dnssec = false;
+ setArgPrefix("geoip" + suffix);
+ if (getArg("dnssec-keydir").empty() == false) {
+ DIR *d = opendir(getArg("dnssec-keydir").c_str());
+ if (d == NULL) {
+ throw PDNSException("dnssec-keydir " + getArg("dnssec-keydir") + " does not exist");
+ }
+ d_dnssec = true;
+ closedir(d);
+ }
+ if (s_rc == 0) { // first instance gets to open everything
+ initialize();
+ }
+ s_rc++;
+}
+
+void GeoIPBackend::initialize() {
+ YAML::Node config;
+ vector<GeoIPDomain> tmp_domains;
+
+ string mode = getArg("database-cache");
+ int flags;
+ if (mode == "standard")
+ flags = GEOIP_STANDARD;
+ else if (mode == "memory")
+ flags = GEOIP_MEMORY_CACHE;
+ else if (mode == "index")
+ flags = GEOIP_INDEX_CACHE;
+#ifdef HAVE_MMAP
+ else if (mode == "mmap")
+ flags = GEOIP_MMAP_CACHE;
+#endif
+ else
+ throw PDNSException("Invalid cache mode " + mode + " for GeoIP backend");
+
+ s_geoip_files.clear(); // reset pointers
+
+ if (getArg("database-files").empty() == false) {
+ vector<string> files;
+ stringtok(files, getArg("database-files"), " ,\t\r\n");
+ for(auto const& file: files) {
+ GeoIP *fptr;
+ int mode;
+ fptr = GeoIP_open(file.c_str(), flags);
+ if (!fptr)
+ throw PDNSException("Cannot open GeoIP database " + file);
+ mode = GeoIP_database_edition(fptr);
+ s_geoip_files.emplace_back(geoip_file_t(mode, unique_ptr<GeoIP,geoip_deleter>(fptr)));
+ }
+ }
+
+ if (s_geoip_files.empty())
+ L<<Logger::Warning<<"No GeoIP database files loaded!"<<endl;
+
+ config = YAML::LoadFile(getArg("zones-file"));
+
+ for(YAML::Node domain : config["domains"]) {
+ GeoIPDomain dom;
+ dom.id = tmp_domains.size();
+ dom.domain = DNSName(domain["domain"].as<string>());
+ dom.ttl = domain["ttl"].as<int>();
+
+ for(YAML::const_iterator recs = domain["records"].begin(); recs != domain["records"].end(); recs++) {
+ DNSName qname = DNSName(recs->first.as<string>());
+ vector<GeoIPDNSResourceRecord> rrs;
+
+ for(YAML::Node item : recs->second) {
+ YAML::const_iterator rec = item.begin();
+ GeoIPDNSResourceRecord rr;
+ rr.domain_id = dom.id;
+ rr.ttl = dom.ttl;
+ rr.qname = qname;
+ if (rec->first.IsNull()) {
+ rr.qtype = QType(0);
+ } else {
+ string qtype = boost::to_upper_copy(rec->first.as<string>());
+ rr.qtype = qtype;
+ }
+ rr.has_weight = false;
+ rr.weight = 100;
+ if (rec->second.IsNull()) {
+ rr.content = "";
+ } else if (rec->second.IsMap()) {
+ for(YAML::const_iterator iter = rec->second.begin(); iter != rec->second.end(); iter++) {
+ string attr = iter->first.as<string>();
+ if (attr == "content") {
+ string content = iter->second.as<string>();
+ rr.content = content;
+ } else if (attr == "weight") {
+ rr.weight = iter->second.as<int>();
+ if (rr.weight < 0) {
+ L<<Logger::Error<<"Weight cannot be negative for " << rr.qname << endl;
+ throw PDNSException(string("Weight cannot be negative for ") + rr.qname.toLogString());
+ }
+ rr.has_weight = true;
+ } else if (attr == "ttl") {
+ rr.ttl = iter->second.as<int>();
+ } else {
+ L<<Logger::Error<<"Unsupported record attribute " << attr << " for " << rr.qname << endl;
+ throw PDNSException(string("Unsupported record attribute ") + attr + string(" for ") + rr.qname.toLogString());
+ }
+ }
+ } else {
+ string content=rec->second.as<string>();
+ rr.content = content;
+ rr.weight = 100;
+ }
+ rr.auth = 1;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rrs.push_back(rr);
+ }
+ std::swap(dom.records[qname], rrs);
+ }
+
+ for(YAML::const_iterator service = domain["services"].begin(); service != domain["services"].end(); service++) {
+ NetmaskTree<vector<string> > nmt;
+
+ // if it's an another map, we need to iterate it again, otherwise we just add two root entries.
+ if (service->second.IsMap()) {
+ for(YAML::const_iterator net = service->second.begin(); net != service->second.end(); net++) {
+ vector<string> value;
+ if (net->second.IsSequence()) {
+ value = net->second.as<vector<string> >();
+ } else {
+ value.push_back(net->second.as<string>());
+ }
+ if (net->first.as<string>() == "default") {
+ nmt.insert(Netmask("0.0.0.0/0")).second.assign(value.begin(),value.end());
+ nmt.insert(Netmask("::/0")).second.swap(value);
+ } else {
+ nmt.insert(Netmask(net->first.as<string>())).second.swap(value);
+ }
+ }
+ } else {
+ vector<string> value;
+ if (service->second.IsSequence()) {
+ value = service->second.as<vector<string> >();
+ } else {
+ value.push_back(service->second.as<string>());
+ }
+ nmt.insert(Netmask("0.0.0.0/0")).second.assign(value.begin(),value.end());
+ nmt.insert(Netmask("::/0")).second.swap(value);
+ }
+ dom.services[DNSName(service->first.as<string>())].swap(nmt);
+ }
+
+ // rectify the zone, first static records
+ for(auto &item : dom.records) {
+ // ensure we have parent in records
+ DNSName name = item.first;
+ while(name.chopOff() && name.isPartOf(dom.domain)) {
+ if (dom.records.find(name) == dom.records.end() && !dom.services.count(name)) { // don't ENT out a service!
+ GeoIPDNSResourceRecord rr;
+ vector<GeoIPDNSResourceRecord> rrs;
+ rr.domain_id = dom.id;
+ rr.ttl = dom.ttl;
+ rr.qname = name;
+ rr.qtype = QType(0); // empty non terminal
+ rr.content = "";
+ rr.auth = 1;
+ rr.weight = 100;
+ rr.has_weight = false;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rrs.push_back(rr);
+ std::swap(dom.records[name], rrs);
+ }
+ }
+ }
+
+ // then services
+ for(auto &item : dom.services) {
+ // ensure we have parent in records
+ DNSName name = item.first;
+ while(name.chopOff() && name.isPartOf(dom.domain)) {
+ if (dom.records.find(name) == dom.records.end()) {
+ GeoIPDNSResourceRecord rr;
+ vector<GeoIPDNSResourceRecord> rrs;
+ rr.domain_id = dom.id;
+ rr.ttl = dom.ttl;
+ rr.qname = name;
+ rr.qtype = QType(0);
+ rr.content = "";
+ rr.auth = 1;
+ rr.weight = 100;
+ rr.has_weight = false;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rrs.push_back(rr);
+ std::swap(dom.records[name], rrs);
+ }
+ }
+ }
+
+ // finally fix weights
+ for(auto &item: dom.records) {
+ float weight=0;
+ float sum=0;
+ bool has_weight=false;
+ // first we look for used weight
+ for(const auto &rr: item.second) {
+ weight+=rr.weight;
+ if (rr.has_weight) has_weight = true;
+ }
+ if (has_weight) {
+ // put them back as probabilities and values..
+ for(auto &rr: item.second) {
+ rr.weight=static_cast<int>((static_cast<float>(rr.weight) / weight)*1000.0);
+ sum += rr.weight;
+ rr.has_weight = has_weight;
+ }
+ // remove rounding gap
+ if (sum < 1000)
+ item.second.back().weight += (1000-sum);
+ }
+ }
+
+ tmp_domains.push_back(dom);
+ }
+
+ s_domains.clear();
+ std::swap(s_domains, tmp_domains);
+}
+
+GeoIPBackend::~GeoIPBackend() {
+ try {
+ WriteLock wl(&s_state_lock);
+ s_rc--;
+ if (s_rc == 0) { // last instance gets to cleanup
+ s_geoip_files.clear();
+ s_domains.clear();
+ }
+ }
+ catch(...) {
+ }
+}
+
+void GeoIPBackend::lookup(const QType &qtype, const DNSName& qdomain, DNSPacket *pkt_p, int zoneId) {
+ ReadLock rl(&s_state_lock);
+ GeoIPDomain dom;
+ GeoIPLookup gl;
+ bool found = false;
+ int probability_rnd = 1+(random() % 1000); // setting probability=0 means it never is used
+ int cumul_probability = 0;
+
+ if (d_result.size()>0)
+ throw PDNSException("Cannot perform lookup while another is running");
+
+ DNSName search = qdomain;
+
+ d_result.clear();
+
+ if (zoneId > -1 && zoneId < static_cast<int>(s_domains.size()))
+ dom = s_domains[zoneId];
+ else {
+ for(const GeoIPDomain& i : s_domains) { // this is arguably wrong, we should probably find the most specific match
+ if (search.isPartOf(i.domain)) {
+ dom = i;
+ found = true;
+ break;
+ }
+ }
+ if (!found) return; // not found
+ }
+
+ string ip = "0.0.0.0";
+ bool v6 = false;
+ if (pkt_p != NULL) {
+ ip = pkt_p->getRealRemote().toStringNoMask();
+ v6 = pkt_p->getRealRemote().isIpv6();
+ }
+
+ gl.netmask = 0;
+
+ auto i = dom.records.find(search);
+ if (i != dom.records.end()) { // return static value
+ for(const auto& rr : i->second) {
+ if (rr.has_weight) {
+ gl.netmask = (v6?128:32);
+ int comp = cumul_probability;
+ cumul_probability += rr.weight;
+ if (rr.weight == 0 || probability_rnd < comp || probability_rnd > (comp + rr.weight))
+ continue;
+ }
+ if (qtype == QType::ANY || rr.qtype == qtype) {
+ d_result.push_back(rr);
+ d_result.back().content = format2str(rr.content, ip, v6, &gl);
+ d_result.back().qname = qdomain;
+ }
+ }
+ // ensure we get most strict netmask
+ for(DNSResourceRecord& rr: d_result) {
+ rr.scopeMask = gl.netmask;
+ }
+ return; // no need to go further
+ }
+
+ auto target = dom.services.find(search);
+ if (target == dom.services.end()) return; // no hit
+
+ const NetmaskTree<vector<string> >::node_type* node = target->second.lookup(ComboAddress(ip));
+ if (node == NULL) return; // no hit, again.
+
+ string format;
+ gl.netmask = node->first.getBits();
+
+ // note that this means the array format won't work with indirect
+ for(auto it = node->second.begin(); it != node->second.end(); it++) {
+ format = format2str(*it, ip, v6, &gl);
+
+ // see if the record can be found
+ auto ri = dom.records.find(DNSName(format));
+ if (ri != dom.records.end()) { // return static value
+ for(const auto& rr: ri->second) {
+ if (qtype == QType::ANY || rr.qtype == qtype) {
+ d_result.push_back(rr);
+ d_result.back().content = format2str(rr.content, ip, v6, &gl);
+ d_result.back().qname = qdomain;
+ }
+ }
+ // ensure we get most strict netmask
+ for(DNSResourceRecord& rr: d_result) {
+ rr.scopeMask = gl.netmask;
+ }
+ return; // no need to go further
+ }
+ }
+
+ // we need this line since we otherwise claim to have NS records etc
+ if (!(qtype == QType::ANY || qtype == QType::CNAME)) return;
+
+ DNSResourceRecord rr;
+ rr.domain_id = dom.id;
+ rr.qtype = QType::CNAME;
+ rr.qname = qdomain;
+ rr.content = format;
+ rr.auth = 1;
+ rr.ttl = dom.ttl;
+ rr.scopeMask = gl.netmask;
+ d_result.push_back(rr);
+}
+
+bool GeoIPBackend::get(DNSResourceRecord &r) {
+ if (d_result.empty()) return false;
+
+ r = d_result.back();
+ d_result.pop_back();
+
+ return true;
+}
+
+bool GeoIPBackend::queryCountry(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_COUNTRY_EDITION ||
+ gi.first == GEOIP_LARGE_COUNTRY_EDITION) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl));
+ return true;
+ } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
+ gi.first == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code3;
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryCountryV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_COUNTRY_EDITION_V6 ||
+ gi.first == GEOIP_LARGE_COUNTRY_EDITION_V6) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
+ return true;
+ } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = GeoIP_code3_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
+ gi.first == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = gir->country_code3;
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryContinent(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_COUNTRY_EDITION ||
+ gi.first == GEOIP_LARGE_COUNTRY_EDITION) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_addr_gl(gi.second.get(), ip.c_str(), gl));
+ return true;
+ } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (gi.first == GEOIP_CITY_EDITION_REV0 ||
+ gi.first == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryContinentV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_COUNTRY_EDITION_V6 ||
+ gi.first == GEOIP_LARGE_COUNTRY_EDITION_V6) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
+ return true;
+ } else if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion* gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ return true;
+ }
+ } else if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
+ gi.first == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = GeoIP_continent_by_id(GeoIP_id_by_code(gir->country_code));
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryName(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_ISP_EDITION ||
+ gi.first == GEOIP_ORG_EDITION) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(gi.second.get(), ip.c_str(), gl));
+ if (!val.empty()) {
+ // reduce space to dash
+ ret = boost::replace_all_copy(val, " ", "-");
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryNameV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_ISP_EDITION_V6 ||
+ gi.first == GEOIP_ORG_EDITION_V6) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
+ if (!val.empty()) {
+ // reduce space to dash
+ ret = boost::replace_all_copy(val, " ", "-");
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryASnum(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_ASNUM_EDITION) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_gl(gi.second.get(), ip.c_str(), gl));
+ if (!val.empty()) {
+ vector<string> asnr;
+ stringtok(asnr, val);
+ if(asnr.size()>0) {
+ ret = asnr[0];
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_ASNUM_EDITION_V6) {
+ string val = valueOrEmpty<char*,string>(GeoIP_name_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl));
+ if (!val.empty()) {
+ vector<string> asnr;
+ stringtok(asnr, val);
+ if(asnr.size()>0) {
+ ret = asnr[0];
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryRegion(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion *gir = GeoIP_region_by_addr_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->region);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_REGION_EDITION_REV0 ||
+ gi.first == GEOIP_REGION_EDITION_REV1) {
+ GeoIPRegion *gir = GeoIP_region_by_addr_v6_gl(gi.second.get(), ip.c_str(), gl);
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->region);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryCity(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_CITY_EDITION_REV0 ||
+ gi.first == GEOIP_CITY_EDITION_REV1) {
+ GeoIPRecord *gir = GeoIP_record_by_addr(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->city);
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::queryCityV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi) {
+ if (gi.first == GEOIP_CITY_EDITION_REV0_V6 ||
+ gi.first == GEOIP_CITY_EDITION_REV1_V6) {
+ GeoIPRecord *gir = GeoIP_record_by_addr_v6(gi.second.get(), ip.c_str());
+ if (gir) {
+ ret = valueOrEmpty<char*,string>(gir->city);
+ gl->netmask = gir->netmask;
+ return true;
+ }
+ }
+ return false;
+}
+
+
+string GeoIPBackend::queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute attribute, GeoIPLookup* gl) {
+ string ret = "unknown";
+
+ for(auto const& gi: s_geoip_files) {
+ string val;
+ bool found = false;
+
+ switch(attribute) {
+ case ASn:
+ if (v6) found = queryASnumV6(val, gl, ip, gi);
+ else found = queryASnum(val, gl, ip, gi);
+ break;
+ case Name:
+ if (v6) found = queryNameV6(val, gl, ip, gi);
+ else found = queryName(val, gl, ip, gi);
+ break;
+ case Continent:
+ if (v6) found = queryContinentV6(val, gl, ip, gi);
+ else found = queryContinent(val, gl, ip, gi);
+ break;
+ case Region:
+ if (v6) found = queryRegionV6(val, gl, ip, gi);
+ else found = queryRegion(val, gl, ip, gi);
+ break;
+ case Country:
+ if (v6) found = queryCountryV6(val, gl, ip, gi);
+ else found = queryCountry(val, gl, ip, gi);
+ break;
+ case City:
+ if (v6) found = queryCityV6(val, gl, ip, gi);
+ else found = queryCity(val, gl, ip, gi);
+ break;
+ }
+
+ if (!found || val.empty() || val == "--") continue; // try next database
+ ret = val;
+ std::transform(ret.begin(), ret.end(), ret.begin(), ::tolower);
+ break;
+ }
+
+ if (ret == "unknown") gl->netmask = (v6?128:32); // prevent caching
+ return ret;
+}
+
+string GeoIPBackend::format2str(string format, const string& ip, bool v6, GeoIPLookup* gl) {
+ string::size_type cur,last;
+ time_t t = time((time_t*)NULL);
+ GeoIPLookup tmp_gl; // largest wins
+ struct tm gtm;
+ gmtime_r(&t, >m);
+ last=0;
+
+ while((cur = format.find("%", last)) != string::npos) {
+ string rep;
+ int nrep=3;
+ tmp_gl.netmask = 0;
+ if (!format.compare(cur,3,"%cn")) {
+ rep = queryGeoIP(ip, v6, Continent, &tmp_gl);
+ } else if (!format.compare(cur,3,"%co")) {
+ rep = queryGeoIP(ip, v6, Country, &tmp_gl);
+ } else if (!format.compare(cur,3,"%af")) {
+ rep = (v6?"v6":"v4");
+ } else if (!format.compare(cur,3,"%as")) {
+ rep = queryGeoIP(ip, v6, ASn, &tmp_gl);
+ } else if (!format.compare(cur,3,"%re")) {
+ rep = queryGeoIP(ip, v6, Region, &tmp_gl);
+ } else if (!format.compare(cur,3,"%na")) {
+ rep = queryGeoIP(ip, v6, Name, &tmp_gl);
+ } else if (!format.compare(cur,3,"%ci")) {
+ rep = queryGeoIP(ip, v6, City, &tmp_gl);
+ } else if (!format.compare(cur,3,"%hh")) {
+ rep = boost::str(boost::format("%02d") % gtm.tm_hour);
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,3,"%yy")) {
+ rep = boost::str(boost::format("%02d") % (gtm.tm_year + 1900));
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,3,"%dd")) {
+ rep = boost::str(boost::format("%02d") % (gtm.tm_yday + 1));
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,4,"%wds")) {
+ nrep=4;
+ rep = GeoIP_WEEKDAYS[gtm.tm_wday];
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,4,"%mos")) {
+ nrep=4;
+ rep = GeoIP_MONTHS[gtm.tm_mon];
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,3,"%wd")) {
+ rep = boost::str(boost::format("%02d") % (gtm.tm_wday + 1));
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,3,"%mo")) {
+ rep = boost::str(boost::format("%02d") % (gtm.tm_mon + 1));
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,3,"%ip")) {
+ rep = ip;
+ tmp_gl.netmask = (v6?128:32);
+ } else if (!format.compare(cur,2,"%%")) {
+ last = cur + 2; continue;
+ } else {
+ last = cur + 1; continue;
+ }
+ if (tmp_gl.netmask > gl->netmask) gl->netmask = tmp_gl.netmask;
+ format.replace(cur, nrep, rep);
+ last = cur + rep.size(); // move to next attribute
+ }
+ return format;
+}
+
+void GeoIPBackend::reload() {
+ WriteLock wl(&s_state_lock);
+
+ try {
+ initialize();
+ } catch (PDNSException &pex) {
+ L<<Logger::Error<<"GeoIP backend reload failed: " << pex.reason << endl;
+ } catch (std::exception &stex) {
+ L<<Logger::Error<<"GeoIP backend reload failed: " << stex.what() << endl;
+ } catch (...) {
+ L<<Logger::Error<<"GeoIP backend reload failed" << endl;
+ }
+}
+
+void GeoIPBackend::rediscover(string* status) {
+ reload();
+}
+
+bool GeoIPBackend::getDomainInfo(const DNSName& domain, DomainInfo &di) {
+ ReadLock rl(&s_state_lock);
+
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == domain) {
+ SOAData sd;
+ this->getSOA(domain, sd);
+ di.id = dom.id;
+ di.zone = dom.domain;
+ di.serial = sd.serial;
+ di.kind = DomainInfo::Native;
+ di.backend = this;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) {
+ if (!d_dnssec) return false;
+
+ ReadLock rl(&s_state_lock);
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ if (hasDNSSECkey(dom.domain)) {
+ meta[string("NSEC3NARROW")].push_back("1");
+ meta[string("NSEC3PARAM")].push_back("1 0 1 f95a");
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) {
+ if (!d_dnssec) return false;
+
+ ReadLock rl(&s_state_lock);
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ if (hasDNSSECkey(dom.domain)) {
+ if (kind == "NSEC3NARROW")
+ meta.push_back(string("1"));
+ if (kind == "NSEC3PARAM")
+ meta.push_back(string("1 0 1 f95a"));
+ }
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys) {
+ if (!d_dnssec) return false;
+ ReadLock rl(&s_state_lock);
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ regex_t reg;
+ regmatch_t regm[5];
+ regcomp(®, "(.*)[.]([0-9]+)[.]([0-9]+)[.]([01])[.]key$", REG_ICASE|REG_EXTENDED);
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ for(size_t i=0;i<glob_result.gl_pathc;i++) {
+ if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) {
+ DNSBackend::KeyData kd;
+ kd.id = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
+ kd.active = !strncmp(glob_result.gl_pathv[i]+regm[4].rm_so, "1", 1);
+ kd.flags = pdns_stou(glob_result.gl_pathv[i]+regm[2].rm_so);
+ ifstream ifs(glob_result.gl_pathv[i]);
+ ostringstream content;
+ char buffer[1024];
+ while(ifs.good()) {
+ ifs.read(buffer, sizeof buffer);
+ if (ifs.gcount()>0) {
+ content << string(buffer, ifs.gcount());
+ }
+ }
+ ifs.close();
+ kd.content = content.str();
+ keys.push_back(kd);
+ }
+ }
+ }
+ regfree(®);
+ globfree(&glob_result);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::removeDomainKey(const DNSName& name, unsigned int id) {
+ if (!d_dnssec) return false;
+ WriteLock rl(&s_state_lock);
+ ostringstream path;
+
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ regex_t reg;
+ regmatch_t regm[5];
+ regcomp(®, "(.*)[.]([0-9]+)[.]([0-9]+)[.]([01])[.]key$", REG_ICASE|REG_EXTENDED);
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ for(size_t i=0;i<glob_result.gl_pathc;i++) {
+ if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) {
+ unsigned int kid = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
+ if (kid == id) {
+ if (unlink(glob_result.gl_pathv[i])) {
+ cerr << "Cannot delete key:" << strerror(errno) << endl;
+ }
+ break;
+ }
+ }
+ }
+ }
+ regfree(®);
+ globfree(&glob_result);
+ return true;
+ }
+ }
+ return false;
+}
+
+int GeoIPBackend::addDomainKey(const DNSName& name, const KeyData& key) {
+ if (!d_dnssec) return false;
+ WriteLock rl(&s_state_lock);
+ unsigned int nextid=1;
+
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ regex_t reg;
+ regmatch_t regm[5];
+ regcomp(®, "(.*)[.]([0-9]+)[.]([0-9]+)[.]([01])[.]key$", REG_ICASE|REG_EXTENDED);
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ for(size_t i=0;i<glob_result.gl_pathc;i++) {
+ if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) {
+ unsigned int kid = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
+ if (kid >= nextid) nextid = kid+1;
+ }
+ }
+ }
+ regfree(®);
+ globfree(&glob_result);
+ pathname.str("");
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << key.flags << "." << nextid << "." << (key.active?"1":"0") << ".key";
+ ofstream ofs(pathname.str().c_str());
+ ofs.write(key.content.c_str(), key.content.size());
+ ofs.close();
+ return nextid;
+ }
+ }
+ return false;
+
+}
+
+bool GeoIPBackend::activateDomainKey(const DNSName& name, unsigned int id) {
+ if (!d_dnssec) return false;
+ WriteLock rl(&s_state_lock);
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ regex_t reg;
+ regmatch_t regm[5];
+ regcomp(®, "(.*)[.]([0-9]+)[.]([0-9]+)[.]([01])[.]key$", REG_ICASE|REG_EXTENDED);
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ for(size_t i=0;i<glob_result.gl_pathc;i++) {
+ if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) {
+ unsigned int kid = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
+ if (kid == id && !strcmp(glob_result.gl_pathv[i]+regm[4].rm_so,"0")) {
+ ostringstream newpath;
+ newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns_stou(glob_result.gl_pathv[i]+regm[2].rm_so) << "." << kid << ".1.key";
+ if (rename(glob_result.gl_pathv[i], newpath.str().c_str())) {
+ cerr << "Cannot active key: " << strerror(errno) << endl;
+ }
+ }
+ }
+ }
+ }
+ globfree(&glob_result);
+ regfree(®);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::deactivateDomainKey(const DNSName& name, unsigned int id) {
+ if (!d_dnssec) return false;
+ WriteLock rl(&s_state_lock);
+ for(GeoIPDomain dom : s_domains) {
+ if (dom.domain == name) {
+ regex_t reg;
+ regmatch_t regm[5];
+ regcomp(®, "(.*)[.]([0-9]+)[.]([0-9]+)[.]([01])[.]key$", REG_ICASE|REG_EXTENDED);
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ for(size_t i=0;i<glob_result.gl_pathc;i++) {
+ if (regexec(®, glob_result.gl_pathv[i], 5, regm, 0) == 0) {
+ unsigned int kid = pdns_stou(glob_result.gl_pathv[i]+regm[3].rm_so);
+ if (kid == id && !strcmp(glob_result.gl_pathv[i]+regm[4].rm_so,"1")) {
+ ostringstream newpath;
+ newpath << getArg("dnssec-keydir") << "/" << dom.domain.toStringNoDot() << "." << pdns_stou(glob_result.gl_pathv[i]+regm[2].rm_so) << "." << kid << ".0.key";
+ if (rename(glob_result.gl_pathv[i], newpath.str().c_str())) {
+ cerr << "Cannot deactive key: " << strerror(errno) << endl;
+ }
+ }
+ }
+ }
+ }
+ globfree(&glob_result);
+ regfree(®);
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GeoIPBackend::hasDNSSECkey(const DNSName& name) {
+ ostringstream pathname;
+ pathname << getArg("dnssec-keydir") << "/" << name.toStringNoDot() << "*.key";
+ glob_t glob_result;
+ if (glob(pathname.str().c_str(),GLOB_ERR,NULL,&glob_result) == 0) {
+ globfree(&glob_result);
+ return true;
+ }
+ return false;
+}
+
+class GeoIPFactory : public BackendFactory{
+public:
+ GeoIPFactory() : BackendFactory("geoip") {}
+
+ void declareArguments(const string &suffix = "") {
+ declare(suffix, "zones-file", "YAML file to load zone(s) configuration", "");
+ declare(suffix, "database-files", "File(s) to load geoip data from", "");
+ declare(suffix, "database-cache", "Cache mode (standard, memory, index, mmap)", "standard");
+ declare(suffix, "dnssec-keydir", "Directory to hold dnssec keys (also turns DNSSEC on)", "");
+ }
+
+ DNSBackend *make(const string &suffix) {
+ return new GeoIPBackend(suffix);
+ }
+};
+
+class GeoIPLoader {
+public:
+ GeoIPLoader() {
+ BackendMakers().report(new GeoIPFactory);
+ L << Logger::Info << "[geoipbackend] This is the geoip backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static GeoIPLoader geoiploader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GEOIPBACKEND_HH
+#define PDNS_GEOIPBACKEND_HH
+
+#include "pdns/namespaces.hh"
+
+#include <vector>
+#include <map>
+#include <string>
+#include <fstream>
+#include <yaml-cpp/yaml.h>
+#include <pthread.h>
+
+#include <GeoIP.h>
+#include <GeoIPCity.h>
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "pdns/dnspacket.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/lock.hh"
+
+struct geoip_deleter;
+
+class GeoIPDomain;
+
+class GeoIPBackend: public DNSBackend {
+public:
+ typedef pair<int,unique_ptr<GeoIP,geoip_deleter> > geoip_file_t;
+ GeoIPBackend(const std::string& suffix="");
+ ~GeoIPBackend();
+
+ virtual void lookup(const QType &qtype, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1);
+ virtual bool list(const DNSName &target, int domain_id, bool include_disabled=false) { return false; } // not supported
+ virtual bool get(DNSResourceRecord &r);
+ virtual void reload();
+ virtual void rediscover(string *status = 0);
+ virtual bool getDomainInfo(const DNSName& domain, DomainInfo &di);
+
+ // dnssec support
+ virtual bool doesDNSSEC() { return d_dnssec; };
+ virtual bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ virtual bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys);
+ virtual bool removeDomainKey(const DNSName& name, unsigned int id);
+ virtual int addDomainKey(const DNSName& name, const KeyData& key);
+ virtual bool activateDomainKey(const DNSName& name, unsigned int id);
+ virtual bool deactivateDomainKey(const DNSName& name, unsigned int id);
+
+ enum GeoIPQueryAttribute {
+ ASn,
+ City,
+ Continent,
+ Country,
+ Name,
+ Region
+ };
+
+private:
+ static pthread_rwlock_t s_state_lock;
+
+ void initialize();
+ void ip2geo(const GeoIPDomain& dom, const string& qname, const string& ip);
+ string queryGeoIP(const string &ip, bool v6, GeoIPQueryAttribute attribute, GeoIPLookup* gl);
+ bool queryCountry(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryCountryV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryContinent(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryContinentV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryName(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryNameV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryASnum(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryASnumV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryRegion(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryRegionV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryCity(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ bool queryCityV6(string &ret, GeoIPLookup* gl, const string &ip, const geoip_file_t& gi);
+ string format2str(string format, const string& ip, bool v6, GeoIPLookup* gl);
+ bool d_dnssec;
+ bool hasDNSSECkey(const DNSName& name);
+
+ vector<DNSResourceRecord> d_result;
+};
+
+#endif /* PDNS_GEOIPBACKEND_HH */
--- /dev/null
+AM_CPPFLAGS += $(MYSQL_CFLAGS)
+
+pkglib_LTLIBRARIES = libgmysqlbackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.mysql.sql \
+ nodnssec-3.x_to_3.4.0_schema.mysql.sql \
+ schema.mysql.sql
+
+dist_doc_DATA = \
+ dnssec-3.x_to_3.4.0_schema.mysql.sql \
+ nodnssec-3.x_to_3.4.0_schema.mysql.sql \
+ schema.mysql.sql
+
+libgmysqlbackend_la_SOURCES = \
+ gmysqlbackend.cc gmysqlbackend.hh \
+ smysql.cc smysql.hh
+
+libgmysqlbackend_la_LDFLAGS = -module -avoid-version
+libgmysqlbackend_la_LIBADD = $(MYSQL_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/gmysqlbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgmysqlbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libgmysqlbackend_la_OBJECTS = gmysqlbackend.lo smysql.lo
+libgmysqlbackend_la_OBJECTS = $(am_libgmysqlbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgmysqlbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgmysqlbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgmysqlbackend_la_SOURCES)
+DIST_SOURCES = $(libgmysqlbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(MYSQL_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libgmysqlbackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.mysql.sql \
+ nodnssec-3.x_to_3.4.0_schema.mysql.sql \
+ schema.mysql.sql
+
+dist_doc_DATA = \
+ dnssec-3.x_to_3.4.0_schema.mysql.sql \
+ nodnssec-3.x_to_3.4.0_schema.mysql.sql \
+ schema.mysql.sql
+
+libgmysqlbackend_la_SOURCES = \
+ gmysqlbackend.cc gmysqlbackend.hh \
+ smysql.cc smysql.hh
+
+libgmysqlbackend_la_LDFLAGS = -module -avoid-version
+libgmysqlbackend_la_LIBADD = $(MYSQL_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/gmysqlbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/gmysqlbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgmysqlbackend.la: $(libgmysqlbackend_la_OBJECTS) $(libgmysqlbackend_la_DEPENDENCIES) $(EXTRA_libgmysqlbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgmysqlbackend_la_LINK) -rpath $(pkglibdir) $(libgmysqlbackend_la_OBJECTS) $(libgmysqlbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gmysqlbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/smysql.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+gmysqlbackend.lo smysql.lo
--- /dev/null
+$(MYSQL_LIBS)
--- /dev/null
+/* Uncomment next 3 lines for versions <= 3.1 */
+/* DROP INDEX rec_name_index ON records; */
+/* DROP INDEX orderindex ON records; */
+/* CREATE INDEX recordorder ON records (domain_id, ordername); */
+
+ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0 AFTER change_date;
+ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
+ALTER TABLE records MODIFY ordername VARCHAR(255) BINARY DEFAULT NULL;
+ALTER TABLE records MODIFY auth TINYINT(1) DEFAULT 1;
+ALTER TABLE records MODIFY type VARCHAR(10);
+ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
+ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);
+ALTER TABLE supermasters MODIFY account VARCHAR(40) NOT NULL;
+ALTER TABLE domainmetadata MODIFY kind VARCHAR(32);
+ALTER TABLE tsigkeys MODIFY algorithm VARCHAR(50);
+ALTER TABLE domainmetadata ENGINE=InnoDB;
+ALTER TABLE cryptokeys ENGINE=InnoDB;
+ALTER TABLE tsigkeys ENGINE=InnoDB;
+
+DROP INDEX domainmetaidindex ON domainmetadata;
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+CREATE TABLE comments (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ comment VARCHAR(64000) NOT NULL,
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <map>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "gmysqlbackend.hh"
+#include "smysql.hh"
+#include <sstream>
+
+gMySQLBackend::gMySQLBackend(const string &mode, const string &suffix) : GSQLBackend(mode,suffix)
+{
+ try {
+ setDB(new SMySQL(getArg("dbname"),
+ getArg("host"),
+ getArgAsNum("port"),
+ getArg("socket"),
+ getArg("user"),
+ getArg("password"),
+ getArg("group"),
+ mustDo("innodb-read-committed"),
+ getArgAsNum("timeout")));
+ }
+
+ catch(SSqlException &e) {
+ L<<Logger::Error<<mode<<" Connection failed: "<<e.txtReason()<<endl;
+ throw PDNSException("Unable to launch "+mode+" connection: "+e.txtReason());
+ }
+ L<<Logger::Info<<mode<<" Connection successful. Connected to database '"<<getArg("dbname")<<"' on '"<<(getArg("host").empty() ? getArg("socket") : getArg("host"))<<"'."<<endl;
+}
+
+class gMySQLFactory : public BackendFactory
+{
+public:
+ gMySQLFactory(const string &mode) : BackendFactory(mode),d_mode(mode) {}
+
+ void declareArguments(const string &suffix="")
+ {
+ declare(suffix,"dbname","Pdns backend database name to connect to","powerdns");
+ declare(suffix,"user","Database backend user to connect as","powerdns");
+ declare(suffix,"host","Database backend host to connect to","");
+ declare(suffix,"port","Database backend port to connect to","0");
+ declare(suffix,"socket","Pdns backend socket to connect to","");
+ declare(suffix,"password","Pdns backend password to connect with","");
+ declare(suffix,"group", "Pdns backend MySQL 'group' to connect as", "client");
+ declare(suffix,"innodb-read-committed","Use InnoDB READ-COMMITTED transaction isolation level","yes");
+ declare(suffix,"timeout", "The timeout in seconds for each attempt to read/write to the server", "10");
+
+ declare(suffix,"dnssec","Enable DNSSEC processing","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=? and name=?");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=? and name=? and domain_id=?");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=?");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=? and domain_id=?");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR ?) and domain_id=? order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=? OR name like ?) and domain_id=?");
+
+ declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
+ declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null");
+
+ declare(suffix,"master-zone-query","Data", "select master from domains where name=? and type='SLAVE'");
+
+ declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type,account from domains where name=?");
+
+ declare(suffix,"info-all-slaves-query","","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix,"supermaster-query","", "select account from supermasters where ip=? and nameserver=?");
+ declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
+
+ declare(suffix,"insert-zone-query","", "insert into domains (type,name,master,account,last_check,notified_serial) values(?,?,?,?,NULL,NULL)");
+
+ declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth,change_date) values (?,?,?,?,?,?,?,?,?,NULL)");
+ declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth,change_date,content,ttl,prio) values (null,?,0,?,?,?,NULL,NULL,NULL,NULL)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername from records where domain_id=? and disabled=0 and ordername is not null order by 1 asc limit 1");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where ordername <= ? and domain_id=? and disabled=0 and ordername is not null order by 1 desc limit 1");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select ordername from records where ordername > ? and domain_id=? and disabled=0 and ordername is not null order by 1 asc limit 1");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where ordername != '' and domain_id=? and disabled=0 and ordername is not null order by 1 desc limit 1");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=?,auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=?,auth=? where domain_id=? and name=? and type=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0");
+
+ declare(suffix,"update-master-query","", "update domains set master=? where name=?");
+ declare(suffix,"update-kind-query","", "update domains set type=? where name=?");
+ declare(suffix,"update-account-query","", "update domains set account=? where name=?");
+ declare(suffix,"update-serial-query","", "update domains set notified_serial=? where id=?");
+ declare(suffix,"update-lastcheck-query","", "update domains set last_check=? where id=?");
+ declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=?");
+ declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix,"delete-domain-query","", "delete from domains where name=?");
+ declare(suffix,"delete-zone-query","", "delete from records where domain_id=?");
+ declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?");
+ declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?");
+
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
+ declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?");
+ declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?)");
+ declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?");
+ declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)");
+ declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?");
+ declare(suffix,"set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values(?,?,?)");
+ declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=?");
+ declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR ?");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=? AND name=? AND type=?");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=?");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE ? OR content LIKE ? LIMIT ?");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE ? OR comment LIKE ? LIMIT ?");
+ }
+
+ DNSBackend *make(const string &suffix="")
+ {
+ return new gMySQLBackend(d_mode,suffix);
+ }
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gMySQLLoader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gMySQLLoader()
+ {
+ BackendMakers().report(new gMySQLFactory("gmysql"));
+ L << Logger::Info << "[gmysqlbackend] This is the gmysql backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+static gMySQLLoader gmysqlloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GMYSQLBACKEND_HH
+#define PDNS_GMYSQLBACKEND_HH
+
+#include <string>
+#include <map>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+#include "pdns/namespaces.hh"
+
+/** The gMySQLBackend is a DNSBackend that can answer DNS related questions. It looks up data
+ in MySQL */
+class gMySQLBackend : public GSQLBackend
+{
+public:
+ gMySQLBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails.
+};
+
+#endif /* PDNS_GMYSQLBACKEND_HH */
--- /dev/null
+/* Uncomment next line for versions <= 3.1 */
+/* DROP INDEX rec_name_index ON records; */
+
+ALTER TABLE records ADD disabled TINYINT(1) DEFAULT 0;
+ALTER TABLE records MODIFY content VARCHAR(64000) DEFAULT NULL;
+ALTER TABLE records ADD ordername VARCHAR(255) BINARY DEFAULT NULL;
+ALTER TABLE records ADD auth TINYINT(1) DEFAULT 1;
+ALTER TABLE records MODIFY type VARCHAR(10);
+ALTER TABLE supermasters MODIFY ip VARCHAR(64) NOT NULL;
+ALTER TABLE supermasters MODIFY account VARCHAR(40) NOT NULL;
+ALTER TABLE supermasters ADD PRIMARY KEY(ip, nameserver);
+
+CREATE INDEX recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE domainmetadata (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32),
+ content TEXT,
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+
+CREATE TABLE cryptokeys (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active TINYINT(1),
+ content TEXT,
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INT AUTO_INCREMENT,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ comment VARCHAR(64000) NOT NULL,
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
--- /dev/null
+CREATE TABLE domains (
+ id INT AUTO_INCREMENT,
+ name VARCHAR(255) NOT NULL,
+ master VARCHAR(128) DEFAULT NULL,
+ last_check INT DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INT DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ PRIMARY KEY (id)
+) Engine=InnoDB;
+
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+
+CREATE TABLE records (
+ id INT AUTO_INCREMENT,
+ domain_id INT DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(64000) DEFAULT NULL,
+ ttl INT DEFAULT NULL,
+ prio INT DEFAULT NULL,
+ change_date INT DEFAULT NULL,
+ disabled TINYINT(1) DEFAULT 0,
+ ordername VARCHAR(255) BINARY DEFAULT NULL,
+ auth TINYINT(1) DEFAULT 1,
+ PRIMARY KEY (id)
+) Engine=InnoDB;
+
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+CREATE INDEX recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ PRIMARY KEY (ip, nameserver)
+) Engine=InnoDB;
+
+
+CREATE TABLE comments (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ comment VARCHAR(64000) NOT NULL,
+ PRIMARY KEY (id)
+) Engine=InnoDB;
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32),
+ content TEXT,
+ PRIMARY KEY (id)
+) Engine=InnoDB;
+
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+
+CREATE TABLE cryptokeys (
+ id INT AUTO_INCREMENT,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT,
+ PRIMARY KEY(id)
+) Engine=InnoDB;
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INT AUTO_INCREMENT,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ PRIMARY KEY (id)
+) Engine=InnoDB;
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "smysql.hh"
+#include <string>
+#include <iostream>
+#include "pdns/misc.hh"
+#include "pdns/logger.hh"
+#include "pdns/dns.hh"
+#include "pdns/namespaces.hh"
+#include "pdns/lock.hh"
+
+bool SMySQL::s_dolog;
+pthread_mutex_t SMySQL::s_myinitlock = PTHREAD_MUTEX_INITIALIZER;
+
+class SMySQLStatement: public SSqlStatement
+{
+public:
+ SMySQLStatement(const string& query, bool dolog, int nparams, MYSQL* db) : d_prepared(false)
+ {
+ d_db = db;
+ d_dolog = dolog;
+ d_query = query;
+ d_paridx = d_fnum = d_resnum = d_residx = 0;
+ d_parnum = nparams;
+ d_req_bind = d_res_bind = NULL;
+ d_stmt = NULL;
+
+ if (query.empty()) {
+ return;
+ }
+ }
+
+ SSqlStatement* bind(const string& name, bool value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_TINY;
+ d_req_bind[d_paridx].buffer = new char[1];
+ *((char*)d_req_bind[d_paridx].buffer) = (value?1:0);
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, int value) {
+ return bind(name, (long)value);
+ }
+ SSqlStatement* bind(const string& name, uint32_t value) {
+ return bind(name, (unsigned long)value);
+ }
+ SSqlStatement* bind(const string& name, long value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
+ d_req_bind[d_paridx].buffer = new long[1];
+ *((long*)d_req_bind[d_paridx].buffer) = value;
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, unsigned long value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONG;
+ d_req_bind[d_paridx].buffer = new unsigned long[1];
+ d_req_bind[d_paridx].is_unsigned = 1;
+ *((unsigned long*)d_req_bind[d_paridx].buffer) = value;
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, long long value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
+ d_req_bind[d_paridx].buffer = new long long[1];
+ *((long long*)d_req_bind[d_paridx].buffer) = value;
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, unsigned long long value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_LONGLONG;
+ d_req_bind[d_paridx].buffer = new unsigned long long[1];
+ d_req_bind[d_paridx].is_unsigned = 1;
+ *((unsigned long long*)d_req_bind[d_paridx].buffer) = value;
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, const std::string& value) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_STRING;
+ d_req_bind[d_paridx].buffer = new char[value.size()+1];
+ d_req_bind[d_paridx].length = new unsigned long[1];
+ *d_req_bind[d_paridx].length = value.size();
+ d_req_bind[d_paridx].buffer_length = *d_req_bind[d_paridx].length+1;
+ memset(d_req_bind[d_paridx].buffer, 0, value.size()+1);
+ value.copy((char*)d_req_bind[d_paridx].buffer, value.size());
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bindNull(const string& name) {
+ prepareStatement();
+ if (d_paridx >= d_parnum) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ d_req_bind[d_paridx].buffer_type = MYSQL_TYPE_NULL;
+ d_paridx++;
+ return this;
+ }
+
+ SSqlStatement* execute() {
+ int err;
+
+ prepareStatement();
+
+ if (!d_stmt) return this;
+
+ if (d_dolog) {
+ L<<Logger::Warning<<"Query: " << d_query <<endl;
+ }
+
+ if ((err = mysql_stmt_bind_param(d_stmt, d_req_bind))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not bind mysql statement: " + d_query + string(": ") + error);
+ }
+
+ if ((err = mysql_stmt_execute(d_stmt))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not execute mysql statement: " + d_query + string(": ") + error);
+ }
+
+ // MySQL documentation says you can call this safely for all queries
+ if ((err = mysql_stmt_store_result(d_stmt))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not store mysql statement: " + d_query + string(": ") + error);
+ }
+
+ if ((d_fnum = static_cast<int>(mysql_stmt_field_count(d_stmt)))>0) {
+ // prepare for result
+ d_resnum = mysql_stmt_num_rows(d_stmt);
+
+ if (d_resnum>0 && d_res_bind == NULL) {
+ MYSQL_RES* meta = mysql_stmt_result_metadata(d_stmt);
+ d_fnum = static_cast<int>(mysql_num_fields(meta)); // ensure correct number of fields
+ d_res_bind = new MYSQL_BIND[d_fnum];
+ memset(d_res_bind, 0, sizeof(MYSQL_BIND)*d_fnum);
+ MYSQL_FIELD* fields = mysql_fetch_fields(meta);
+
+ for(int i = 0; i < d_fnum; i++) {
+ unsigned long len = std::max(fields[i].max_length, fields[i].length)+1;
+ if (len > 128 * 1024) len = 128 * 1024; // LONGTEXT may tell us it needs 4GB!
+ d_res_bind[i].is_null = new my_bool[1];
+ d_res_bind[i].error = new my_bool[1];
+ d_res_bind[i].length = new unsigned long[1];
+ d_res_bind[i].buffer = new char[len];
+ d_res_bind[i].buffer_length = len;
+ d_res_bind[i].buffer_type = MYSQL_TYPE_STRING;
+ }
+
+ mysql_free_result(meta);
+
+ if ((err = mysql_stmt_bind_result(d_stmt, d_res_bind))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not bind parameters to mysql statement: " + d_query + string(": ") + error);
+ }
+ }
+ }
+
+ return this;
+ }
+
+ bool hasNextRow() {
+ return d_residx < d_resnum;
+ }
+
+ SSqlStatement* nextRow(row_t& row) {
+ int err;
+ row.clear();
+ if (!hasNextRow()) return this;
+
+ if ((err =mysql_stmt_fetch(d_stmt))) {
+ if (err != MYSQL_DATA_TRUNCATED) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not fetch result: " + d_query + string(": ") + error);
+ }
+ }
+
+ row.reserve(d_fnum);
+
+ for(int i=0;i<d_fnum;i++) {
+ if (*d_res_bind[i].error) {
+ L<<Logger::Warning<<"Result field at row " << d_residx << " column " << i << " has errno " << *d_res_bind[i].error << endl;
+ }
+ if (*d_res_bind[i].is_null) {
+ row.push_back("");
+ continue;
+ } else {
+ row.push_back(string((char*)d_res_bind[i].buffer, std::min(d_res_bind[i].buffer_length, *d_res_bind[i].length)));
+ }
+ }
+
+ d_residx++;
+#if MYSQL_VERSION_ID >= 50500
+ if (d_residx >= d_resnum) {
+ mysql_stmt_free_result(d_stmt);
+ while(!mysql_stmt_next_result(d_stmt)) {
+ if ((err = mysql_stmt_store_result(d_stmt))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not store mysql statement: " + d_query + string(": ") + error);
+ }
+ d_resnum = mysql_stmt_num_rows(d_stmt);
+ // XXX: For some reason mysql_stmt_result_metadata returns NULL here, so we cannot
+ // ensure row field count matches first result set.
+ if (d_resnum>0) { // ignore empty result set
+ if ((err = mysql_stmt_bind_result(d_stmt, d_res_bind))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not bind parameters to mysql statement: " + d_query + string(": ") + error);
+ }
+ d_residx = 0;
+ break;
+ }
+ mysql_stmt_free_result(d_stmt);
+ }
+ }
+#endif
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ result.reserve(d_resnum);
+ row_t row;
+
+ while(hasNextRow()) {
+ nextRow(row);
+ result.push_back(row);
+ }
+
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ if (!d_stmt) return this;
+ int err=0;
+ mysql_stmt_free_result(d_stmt);
+#if MYSQL_VERSION_ID >= 50500
+ while((err = mysql_stmt_next_result(d_stmt)) == 0) {
+ mysql_stmt_free_result(d_stmt);
+ }
+#endif
+ if (err>0) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not get next result from mysql statement: " + d_query + string(": ") + error);
+ }
+ mysql_stmt_reset(d_stmt);
+ if (d_req_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_req_bind[i].buffer) delete [] (char*)d_req_bind[i].buffer;
+ if (d_req_bind[i].length) delete [] d_req_bind[i].length;
+ }
+ memset(d_req_bind, 0, sizeof(MYSQL_BIND)*d_parnum);
+ }
+ d_residx = d_resnum = 0;
+ d_paridx = 0;
+ return this;
+ }
+
+ const std::string& getQuery() { return d_query; }
+
+ ~SMySQLStatement() {
+ releaseStatement();
+ }
+private:
+
+ void prepareStatement() {
+ int err;
+
+ if (d_prepared) return;
+ if (d_query.empty()) {
+ d_prepared = true;
+ return;
+ }
+
+ if ((d_stmt = mysql_stmt_init(d_db))==NULL)
+ throw SSqlException("Could not initialize mysql statement, out of memory: " + d_query);
+
+ if ((err = mysql_stmt_prepare(d_stmt, d_query.c_str(), d_query.size()))) {
+ string error(mysql_stmt_error(d_stmt));
+ releaseStatement();
+ throw SSqlException("Could not prepare statement: " + d_query + string(": ") + error);
+ }
+
+ if (static_cast<int>(mysql_stmt_param_count(d_stmt)) != d_parnum) {
+ releaseStatement();
+ throw SSqlException("Provided parameter count does not match statement: " + d_query);
+ }
+
+ if (d_parnum>0) {
+ d_req_bind = new MYSQL_BIND[d_parnum];
+ memset(d_req_bind, 0, sizeof(MYSQL_BIND)*d_parnum);
+ }
+
+ d_prepared = true;
+ }
+
+ void releaseStatement() {
+ d_prepared = false;
+ if (d_stmt)
+ mysql_stmt_close(d_stmt);
+ d_stmt = NULL;
+ if (d_req_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_req_bind[i].buffer) delete [] (char*)d_req_bind[i].buffer;
+ if (d_req_bind[i].length) delete [] d_req_bind[i].length;
+ }
+ delete [] d_req_bind;
+ d_req_bind = NULL;
+ }
+ if (d_res_bind) {
+ for(int i=0;i<d_fnum;i++) {
+ if (d_res_bind[i].buffer) delete [] (char*)d_res_bind[i].buffer;
+ if (d_res_bind[i].length) delete [] d_res_bind[i].length;
+ if (d_res_bind[i].error) delete [] d_res_bind[i].error;
+ if (d_res_bind[i].is_null) delete [] d_res_bind[i].is_null;
+ }
+ delete [] d_res_bind;
+ d_res_bind = NULL;
+ }
+ d_paridx = d_fnum = d_resnum = d_residx = 0;
+ }
+ MYSQL* d_db;
+
+ MYSQL_STMT* d_stmt;
+ MYSQL_BIND* d_req_bind;
+ MYSQL_BIND* d_res_bind;
+
+ string d_query;
+
+ bool d_prepared;
+ bool d_dolog;
+ int d_parnum;
+ int d_paridx;
+ int d_fnum;
+ int d_resnum;
+ int d_residx;
+};
+
+SMySQL::SMySQL(const string &database, const string &host, uint16_t port, const string &msocket, const string &user,
+ const string &password, const string &group, bool setIsolation, unsigned int timeout)
+{
+ int retry=1;
+
+ Lock l(&s_myinitlock);
+ if (!mysql_init(&d_db))
+ throw sPerrorException("Unable to initialize mysql driver");
+
+ do {
+
+#if MYSQL_VERSION_ID >= 50013
+ my_bool reconnect = 0;
+ mysql_options(&d_db, MYSQL_OPT_RECONNECT, &reconnect);
+#endif
+
+#if MYSQL_VERSION_ID >= 50100
+ if(timeout) {
+ mysql_options(&d_db, MYSQL_OPT_READ_TIMEOUT, &timeout);
+ mysql_options(&d_db, MYSQL_OPT_WRITE_TIMEOUT, &timeout);
+ }
+#endif
+
+#if MYSQL_VERSION_ID >= 50500
+ mysql_options(&d_db, MYSQL_SET_CHARSET_NAME, MYSQL_AUTODETECT_CHARSET_NAME);
+#endif
+
+ if (setIsolation && (retry == 1))
+ mysql_options(&d_db, MYSQL_INIT_COMMAND,"SET SESSION tx_isolation='READ-COMMITTED'");
+
+ mysql_options(&d_db, MYSQL_READ_DEFAULT_GROUP, group.c_str());
+
+ if (!mysql_real_connect(&d_db, host.empty() ? NULL : host.c_str(),
+ user.empty() ? NULL : user.c_str(),
+ password.empty() ? NULL : password.c_str(),
+ database.empty() ? NULL : database.c_str(),
+ port,
+ msocket.empty() ? NULL : msocket.c_str(),
+ CLIENT_MULTI_RESULTS)) {
+
+ if (retry == 0)
+ throw sPerrorException("Unable to connect to database");
+ --retry;
+ } else {
+ if (retry == 0) {
+ mysql_close(&d_db);
+ throw sPerrorException("Please add '(gmysql-)innodb-read-committed=no' to your PowerDNS configuration, and reconsider your storage engine if it does not support transactions.");
+ }
+ retry=-1;
+ }
+ } while (retry >= 0);
+}
+
+void SMySQL::setLog(bool state)
+{
+ s_dolog=state;
+}
+
+SMySQL::~SMySQL()
+{
+ mysql_close(&d_db);
+}
+
+SSqlException SMySQL::sPerrorException(const string &reason)
+{
+ return SSqlException(reason+string(": ")+mysql_error(&d_db));
+}
+
+SSqlStatement* SMySQL::prepare(const string& query, int nparams)
+{
+ return new SMySQLStatement(query, s_dolog, nparams, &d_db);
+}
+
+void SMySQL::execute(const string& query)
+{
+ if(s_dolog)
+ L<<Logger::Warning<<"Query: "<<query<<endl;
+
+ int err;
+ if((err=mysql_query(&d_db,query.c_str())))
+ throw sPerrorException("Failed to execute mysql_query '" + query + "' Err="+itoa(err));
+}
+
+void SMySQL::startTransaction() {
+ execute("begin");
+}
+
+void SMySQL::commit() {
+ execute("commit");
+}
+
+void SMySQL::rollback() {
+ execute("rollback");
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SMYSQL_HH
+#define SMYSQL_HH
+
+#include <mysql.h>
+#include "pdns/backends/gsql/ssql.hh"
+#include "pdns/utility.hh"
+
+class SMySQL : public SSql
+{
+public:
+ SMySQL(const string &database, const string &host="", uint16_t port=0,
+ const string &msocket="",const string &user="",
+ const string &password="", const string &group="",
+ bool setIsolation=false, unsigned int timeout=10);
+
+ ~SMySQL();
+
+ SSqlException sPerrorException(const string &reason);
+ void setLog(bool state);
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+
+ void startTransaction();
+ void commit();
+ void rollback();
+
+private:
+ MYSQL d_db;
+ static bool s_dolog;
+ static pthread_mutex_t s_myinitlock;
+};
+
+#endif /* SSMYSQL_HH */
--- /dev/null
+AM_CPPFLAGS += $(UNIXODBC_CFLAGS)
+pkglib_LTLIBRARIES = libgodbcbackend.la
+
+EXTRA_DIST=OBJECTFILES OBJECTLIBS
+
+dist_doc_DATA=schema.mssql.sql
+
+libgodbcbackend_la_SOURCES=godbcbackend.cc godbcbackend.hh \
+ sodbc.hh sodbc.cc
+
+libgodbcbackend_la_LDFLAGS=-module -avoid-version
+libgodbcbackend_la_LIBADD=$(UNIXODBC_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/godbcbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgodbcbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libgodbcbackend_la_OBJECTS = godbcbackend.lo sodbc.lo
+libgodbcbackend_la_OBJECTS = $(am_libgodbcbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgodbcbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgodbcbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgodbcbackend_la_SOURCES)
+DIST_SOURCES = $(libgodbcbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(UNIXODBC_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libgodbcbackend.la
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+dist_doc_DATA = schema.mssql.sql
+libgodbcbackend_la_SOURCES = godbcbackend.cc godbcbackend.hh \
+ sodbc.hh sodbc.cc
+
+libgodbcbackend_la_LDFLAGS = -module -avoid-version
+libgodbcbackend_la_LIBADD = $(UNIXODBC_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/godbcbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/godbcbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgodbcbackend.la: $(libgodbcbackend_la_OBJECTS) $(libgodbcbackend_la_DEPENDENCIES) $(EXTRA_libgodbcbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgodbcbackend_la_LINK) -rpath $(pkglibdir) $(libgodbcbackend_la_OBJECTS) $(libgodbcbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/godbcbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sodbc.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+godbcbackend.lo sodbc.lo
\ No newline at end of file
--- /dev/null
+-lodbc
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "pdns/utility.hh"
+#include <map>
+#include <sstream>
+#include <string>
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "sodbc.hh"
+#include "godbcbackend.hh"
+
+
+// Connects to the database.
+gODBCBackend::gODBCBackend (const std::string & mode, const std::string & suffix) : GSQLBackend( mode, suffix )
+{
+ try
+ {
+ setDB( new SODBC( getArg( "datasource" ), getArg( "username" ), getArg( "password" )));
+ }
+ catch( SSqlException & e )
+ {
+ L<<Logger::Error<< mode << " Connection failed: " << e.txtReason() << std::endl;
+ throw PDNSException( "Unable to launch " + mode + " connection: " + e.txtReason());
+ }
+
+ L << Logger::Warning << mode << " Connection successful" << std::endl;
+}
+
+
+//! Constructs a gODBCBackend
+class gODBCFactory : public BackendFactory
+{
+public:
+ //! Constructor.
+ gODBCFactory( const std::string & mode ) : BackendFactory( mode ), d_mode( mode )
+ {
+ }
+
+ //! Declares all needed arguments.
+ void declareArguments( const std::string & suffix = "" )
+ {
+ declare( suffix, "datasource", "Datasource (DSN) to use","PowerDNS");
+ declare( suffix, "username", "User to connect as","powerdns");
+ declare( suffix, "password", "Password to connect with","");
+ declare(suffix,"dnssec","Enable DNSSEC processing","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=? and name=?");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=? and name=? and domain_id=?");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=?");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=? and domain_id=?");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR disabled=?) and domain_id=? order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=? OR name like ?) and domain_id=?");
+
+ declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=? and type is null");
+ declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=? and name=? and type is null");
+
+ declare(suffix,"master-zone-query","Data", "select master from domains where name=? and type='SLAVE'");
+
+ declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type,account from domains where name=?");
+
+ declare(suffix,"info-all-slaves-query","","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix,"supermaster-query","", "select account from supermasters where ip=? and nameserver=?");
+ declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=? and account=?");
+
+ declare(suffix,"insert-zone-query","", "insert into domains (type,name,master,account,last_check,notified_serial) values(?,?,?,?,null,null)");
+
+ declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth,change_date) values (?,?,?,?,?,?,?,convert(varbinary(255),?),?,null)");
+ declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth,ttl,prio,change_date,content) values (null,?,0,?,convert(varbinary(255),?),?,null,null,null,null)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select top 1 convert(varchar(255), ordername) from records where domain_id=? and disabled=0 and ordername is not null order by 1 asc");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select top 1 convert(varchar(255), ordername), name from records where ordername <= convert(varbinary(255),?) and domain_id=? and disabled=0 and ordername is not null order by 1 desc");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select convert(varchar(255), min(ordername)) from records where ordername > convert(varbinary(255),?) and domain_id=? and disabled=0 and ordername is not null");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select top 1 convert(varchar(255), ordername), name from records where ordername != convert(varbinary(255),'') and domain_id=? and disabled=0 and ordername is not null order by 1 desc");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=convert(varbinary(255),?),auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=convert(varbinary(255),?),auth=? where domain_id=? and name=? and type=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=? where domain_id=? and name=? and type=? and disabled=0");
+
+ declare(suffix,"update-master-query","", "update domains set master=? where name=?");
+ declare(suffix,"update-kind-query","", "update domains set type=? where name=?");
+ declare(suffix,"update-account-query","", "update domains set account=? where name=?");
+ declare(suffix,"update-serial-query","", "update domains set notified_serial=? where id=?");
+ declare(suffix,"update-lastcheck-query","", "update domains set last_check=? where id=?");
+ declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=?");
+ declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix,"delete-domain-query","", "delete from domains where name=?");
+ declare(suffix,"delete-zone-query","", "delete from records where domain_id=?");
+ declare(suffix,"delete-rrset-query","","delete from records where domain_id=? and name=? and type=?");
+ declare(suffix,"delete-names-query","","delete from records where domain_id=? and name=?");
+
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, ?, ?, ? from domains where name=?");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=?");
+ declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=?");
+ declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=? and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?) and domainmetadata.kind=?");
+ declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=?)");
+ declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, ?, ? from domains where name=?");
+ declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?) and cryptokeys.id=?");
+ declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=?)");
+ declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=?");
+ /* FIXME: set-tsig-key-query only works on an empty database right now. For MySQL we use the "update into" statement..
+ According to the internet, we need to construct a pretty hefty "merge" query: https://msdn.microsoft.com/en-us/library/bb510625.aspx
+ */
+ declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (name,algorithm,secret) values(?,?,?)");
+ declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=?");
+ declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR records.disabled=?");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=?");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (?, ?, ?, ?, ?, ?)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=? AND name=? AND type=?");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=?");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE ? OR content LIKE ? LIMIT ?");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE ? OR comment LIKE ? LIMIT ?");
+ }
+
+ //! Constructs a new gODBCBackend object.
+ DNSBackend *make(const string & suffix = "" )
+ {
+ return new gODBCBackend( d_mode, suffix );
+ }
+
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gODBCLoader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gODBCLoader()
+ {
+ BackendMakers().report( new gODBCFactory("godbc"));
+ L<<Logger::Warning << "This is module godbcbackend reporting" << std::endl;
+ }
+};
+
+//! Reports the backendloader to the UeberBackend.
+static gODBCLoader godbcloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <string>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+class gODBCBackend : public GSQLBackend
+{
+public:
+ //! Constructor that connects to the database, throws an exception if something went wrong.
+ gODBCBackend( const std::string & mode, const std::string & suffix );
+
+};
+
--- /dev/null
+CREATE TABLE domains (
+ id INT IDENTITY,
+ name VARCHAR(255) NOT NULL,
+ master VARCHAR(128) DEFAULT NULL,
+ last_check INT DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INT DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+CREATE TABLE records (
+ id INT IDENTITY,
+ domain_id INT DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(MAX) DEFAULT NULL,
+ ttl INT DEFAULT NULL,
+ prio INT DEFAULT NULL,
+ change_date INT DEFAULT NULL,
+ disabled BIT DEFAULT 0,
+ ordername VARBINARY(255) DEFAULT NULL,
+ auth BIT DEFAULT 1,
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+CREATE INDEX recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ PRIMARY KEY (ip, nameserver)
+);
+
+
+CREATE TABLE comments (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ comment VARCHAR(MAX) NOT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32),
+ content VARCHAR(MAX),
+ PRIMARY KEY (id)
+);
+
+CREATE INDEX domainmetadata_idx ON domainmetadata (domain_id, kind);
+
+CREATE TABLE cryptokeys (
+ id INT IDENTITY,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active BIT,
+ content VARCHAR(MAX),
+ PRIMARY KEY(id)
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INT IDENTITY,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ PRIMARY KEY (id)
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "pdns/logger.hh"
+#include "pdns/utility.hh"
+#include <sstream>
+#include "sodbc.hh"
+#include <string.h>
+
+static bool realTestResult( SQLRETURN result, SQLSMALLINT type, SQLHANDLE handle, const std::string & message, std::string & errorMessage)
+{
+ // cerr<<"result = "<<result<<endl;
+ if ( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )
+ return true;
+
+ ostringstream errmsg;
+
+ errmsg << message << ": ";
+
+ if ( result != SQL_ERROR && result != SQL_SUCCESS_WITH_INFO ) {
+ cerr<<"handle "<<handle<<" got result "<<result<<endl;
+ errmsg << "SQL function returned "<<result<<", no additional information available"<<endl;
+ errorMessage = errmsg.str();
+ return false;
+ }
+
+ SQLINTEGER i = 0;
+ SQLINTEGER native;
+ SQLCHAR state[ 7 ];
+ SQLCHAR text[256];
+ SQLSMALLINT len;
+ SQLRETURN ret;
+
+ do
+ {
+ // cerr<<"getting sql diag record "<<i<<endl;
+ ret = SQLGetDiagRec(type, handle, ++i, state, &native, text,
+ sizeof(text), &len );
+ // cerr<<"getdiagrec said "<<ret<<endl;
+ if (SQL_SUCCEEDED(ret)) { // cerr<<"got it"<<endl;
+ errmsg<<state<<i<<native<<text<<"/";
+ }
+ }
+ while( ret == SQL_SUCCESS );
+ errorMessage = errmsg.str();
+ return false;
+}
+
+class SODBCStatement: public SSqlStatement
+{
+public:
+ SODBCStatement(const string& query, bool dolog, int nparams, SQLHDBC connection)
+ {
+ d_query = query;
+ d_conn = connection;
+ d_dolog = dolog;
+ d_residx = 0;
+ d_paridx = 0;
+ d_result = SQL_NO_DATA;
+ d_statement = NULL;
+ d_prepared = false;
+ m_columncount = 0;
+ d_parnum = nparams;
+ }
+
+ struct ODBCParam {
+ SQLPOINTER ParameterValuePtr;
+ SQLLEN* LenPtr;
+ SQLSMALLINT ParameterType;
+ SQLSMALLINT ValueType;
+ };
+
+ vector<ODBCParam> d_req_bind;
+
+ SSqlStatement* bind(const string& name, ODBCParam& p) {
+ prepareStatement();
+ d_req_bind.push_back(p);
+ SQLRETURN result = SQLBindParameter(
+ d_statement, // StatementHandle,
+ d_paridx+1, // ParameterNumber,
+ SQL_PARAM_INPUT, // InputOutputType,
+ p.ValueType, // ValueType,
+ p.ParameterType, // ParameterType,
+ 0, // ColumnSize,
+ 0, // DecimalDigits,
+ p.ParameterValuePtr, // ParameterValuePtr,
+ 0, // BufferLength,
+ p.LenPtr // StrLen_or_IndPtr
+ );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not bind parameter.");
+ d_paridx++;
+
+ return this;
+ }
+
+ SSqlStatement* bind(const string& name, bool value) { prepareStatement(); return bind(name, (uint32_t)value); }
+
+ SSqlStatement* bind(const string& name, long value) { prepareStatement(); return bind(name, (unsigned long)value); }
+
+ SSqlStatement* bind(const string& name, int value) { prepareStatement(); return bind(name, (uint32_t)value); }
+
+ SSqlStatement* bind(const string& name, long long value) { prepareStatement(); return bind(name, (unsigned long long)value); }
+
+ SSqlStatement* bind(const string& name, uint32_t value) {
+ prepareStatement();
+ ODBCParam p;
+ p.ParameterValuePtr = new UDWORD {value};
+ p.LenPtr = new SQLLEN {sizeof(UDWORD)};
+ p.ParameterType = SQL_INTEGER;
+ p.ValueType = SQL_INTEGER;
+ return bind(name, p);
+ }
+
+ SSqlStatement* bind(const string& name, unsigned long value) {
+ prepareStatement();
+ ODBCParam p;
+ p.ParameterValuePtr = new ULONG {value};
+ p.LenPtr = new SQLLEN {sizeof(ULONG)};
+ p.ParameterType = SQL_INTEGER;
+ p.ValueType = SQL_INTEGER;
+ return bind(name, p);
+ }
+
+ SSqlStatement* bind(const string& name, unsigned long long value) {
+ prepareStatement();
+ ODBCParam p;
+ p.ParameterValuePtr = new unsigned long long {value};
+ p.LenPtr = new SQLLEN {sizeof(unsigned long long)};
+ p.ParameterType = SQL_BIGINT;
+ p.ValueType = SQL_C_UBIGINT;
+ return bind(name, p);
+ }
+
+ SSqlStatement* bind(const string& name, const std::string& value) {
+
+ // cerr<<"asked to bind string "<<value<<endl;
+
+ if(d_req_bind.size() > (d_parnum+1)) throw SSqlException("Trying to bind too many parameters.");
+ prepareStatement();
+ ODBCParam p;
+
+ p.ParameterValuePtr = (char*) new char[value.size()+1];
+ value.copy((char*)p.ParameterValuePtr, value.size());
+ ((char*)p.ParameterValuePtr)[value.size()]=0;
+ p.LenPtr=new SQLLEN;
+ *(p.LenPtr)=value.size();
+ p.ParameterType = SQL_VARCHAR;
+ p.ValueType = SQL_C_CHAR;
+
+ return bind(name, p);
+ }
+
+ SSqlStatement* bindNull(const string& name) {
+ if(d_req_bind.size() > (d_parnum+1)) throw SSqlException("Trying to bind too many parameters.");
+
+ prepareStatement();
+ ODBCParam p;
+
+ p.ParameterValuePtr = NULL;
+ p.LenPtr=new SQLLEN;
+ *(p.LenPtr)=SQL_NULL_DATA;
+ p.ParameterType = SQL_VARCHAR;
+ p.ValueType = SQL_C_CHAR;
+
+ return bind(name, p);
+ }
+
+ SSqlStatement* execute()
+ {
+ prepareStatement();
+ SQLRETURN result;
+ // cerr<<"execute("<<d_query<<")"<<endl;
+ if (d_dolog) {
+ L<<Logger::Warning<<"Query: "<<d_query<<endl;
+ }
+
+ result = SQLExecute(d_statement);
+ if(result != SQL_NO_DATA) // odbc+sqlite returns this on 'no rows updated'
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not execute query ("+d_query+")." );
+
+ // Determine the number of columns.
+ result = SQLNumResultCols( d_statement, &m_columncount );
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not determine the number of columns." );
+ // cerr<<"got "<<m_columncount<<" columns"<<endl;
+
+ if(m_columncount) {
+ // cerr<<"first SQLFetch"<<endl;
+ d_result = SQLFetch(d_statement);
+ // cerr<<"first SQLFetch done, d_result="<<d_result<<endl;
+ }
+ else
+ d_result = SQL_NO_DATA;
+
+ if(d_result != SQL_NO_DATA)
+ testResult( d_result, SQL_HANDLE_STMT, d_statement, "Could not do first SQLFetch for ("+d_query+")." );
+ return this;
+ }
+
+ bool hasNextRow() {
+ // cerr<<"hasNextRow d_result="<<d_result<<endl;
+ return d_result!=SQL_NO_DATA;
+ }
+ SSqlStatement* nextRow(row_t& row);
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ // if (d_res == NULL) return this;
+ row_t row;
+ while(hasNextRow()) { nextRow(row); result.push_back(row); }
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ SQLCloseCursor(d_statement); // hack, this probably violates some state transitions
+
+ for(auto &i: d_req_bind) {
+ if (i.ParameterType == SQL_VARCHAR) delete [] (char*)i.ParameterValuePtr;
+ else if (i.ParameterType == SQL_INTEGER) delete (ULONG*)i.ParameterValuePtr;
+ else if (i.ParameterType == SQL_C_UBIGINT) delete (unsigned long long*)i.ParameterValuePtr;
+ delete i.LenPtr;
+ }
+ d_req_bind.clear();
+ d_residx = 0;
+ d_paridx = 0;
+ return this;
+ }
+ const std::string& getQuery() { return d_query; }
+
+ ~SODBCStatement() {
+ releaseStatement();
+ }
+private:
+
+ void testResult(SQLRETURN result, SQLSMALLINT type, SQLHANDLE handle, const std::string & message) {
+ std::string errorMessage;
+ if (!realTestResult(result, type, handle, message, errorMessage)) {
+ releaseStatement();
+ throw SSqlException(errorMessage);
+ }
+ }
+
+ void releaseStatement() {
+ reset();
+ if (d_statement != NULL)
+ SQLFreeHandle(SQL_HANDLE_STMT, d_statement);
+ d_prepared = false;
+ }
+
+ void prepareStatement() {
+ if (d_prepared) return;
+
+ SQLRETURN result;
+
+ // Allocate statement handle.
+ result = SQLAllocHandle( SQL_HANDLE_STMT, d_conn, &d_statement );
+ testResult( result, SQL_HANDLE_DBC, d_conn, "Could not allocate a statement handle." );
+
+ result = SQLPrepare(d_statement, (SQLCHAR *) d_query.c_str(), SQL_NTS);
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not prepare query." );
+
+ SQLSMALLINT paramcount;
+ result = SQLNumParams(d_statement, ¶mcount);
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not get parameter count." );
+
+ if (paramcount != static_cast<SQLSMALLINT>(d_parnum)) {
+ releaseStatement();
+ throw SSqlException("Provided parameter count does not match statement: " + d_query);
+ }
+
+ // cerr<<"prepared ("<<query<<")"<<endl;
+ d_prepared = true;
+ }
+
+ string d_query;
+ bool d_dolog;
+ bool d_prepared;
+ int d_residx;
+ size_t d_paridx,d_parnum;
+ SQLRETURN d_result;
+
+ SQLHDBC d_conn;
+ SQLHSTMT d_statement; //!< Database statement handle.
+
+ //! Column type.
+ struct column_t
+ {
+ SQLSMALLINT m_type; //!< Type of the column.
+ SQLULEN m_size; //!< Column size.
+ SQLPOINTER m_pData; //!< Pointer to the memory where to store the data.
+ bool m_canBeNull; //!< Can this column be null?
+ };
+
+ //! Column info.
+ SQLSMALLINT m_columncount;
+
+};
+
+SSqlStatement* SODBCStatement::nextRow(row_t& row)
+{
+ SQLRETURN result;
+
+ row.clear();
+
+ result = d_result;
+ // cerr<<"at start of nextRow, previous SQLFetch result is "<<result<<endl;
+ // FIXME handle errors (SQL_NO_DATA==100, anything other than the two SUCCESS options below is bad news)
+ if ( result == SQL_SUCCESS || result == SQL_SUCCESS_WITH_INFO )
+ {
+ // cerr<<"got row"<<endl;
+ // We've got a data row, now lets get the results.
+ for ( int i = 0; i < m_columncount; i++ )
+ {
+ SQLLEN len;
+ SQLCHAR coldata[128*1024];
+ std::string strres = "";
+ result = SQLGetData( d_statement, i + 1, SQL_C_CHAR, (SQLPOINTER) coldata, sizeof(coldata), &len);
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not get data." );
+ if (len > SQL_NULL_DATA)
+ strres = std::string(reinterpret_cast<const char*>(coldata), std::min<SQLLEN>(sizeof(coldata)-1,len)); // do not use nil byte
+ row.push_back(strres);
+ }
+
+ // Done!
+ d_residx++;
+ // cerr<<"SQLFetch"<<endl;
+ d_result = SQLFetch(d_statement);
+ // cerr<<"subsequent SQLFetch done, d_result="<<d_result<<endl;
+ if(d_result == SQL_NO_DATA) {
+ SQLRETURN result = SQLMoreResults(d_statement);
+ // cerr<<"SQLMoreResults done, result="<<d_result<<endl;
+ if (result == SQL_NO_DATA) {
+ d_result = result;
+ }
+ else {
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not fetch next result set for ("+d_query+").");
+ d_result = SQLFetch(d_statement);
+ }
+ }
+ testResult( result, SQL_HANDLE_STMT, d_statement, "Could not do subsequent SQLFetch for ("+d_query+")." );
+
+ return this;
+ }
+
+ SQLFreeStmt( d_statement, SQL_CLOSE );
+ throw SSqlException( "Should not get here." );
+ return this;
+}
+
+// Constructor.
+SODBC::SODBC(
+ const std::string & dsn,
+ const std::string & username,
+ const std::string & password
+ )
+{
+ SQLRETURN result;
+
+ // Allocate an environment handle.
+ result = SQLAllocHandle( SQL_HANDLE_ENV, SQL_NULL_HANDLE, &m_environment );
+ testResult( result, SQL_NULL_HANDLE, NULL, "Could not allocate an environment handle." );
+
+ // Set ODBC version. (IEUW!)
+ result = SQLSetEnvAttr( m_environment, SQL_ATTR_ODBC_VERSION, reinterpret_cast< void * >( SQL_OV_ODBC3 ), 0 );
+ testResult( result, SQL_HANDLE_ENV, m_environment, "Could not set the ODBC version." );
+
+ // Allocate connection handle.
+ result = SQLAllocHandle( SQL_HANDLE_DBC, m_environment, &m_connection );
+ testResult( result, SQL_HANDLE_ENV, m_environment, "Could not allocate a connection handle." );
+
+ // Connect to the database.
+ char *l_dsn = strdup( dsn.c_str());
+ char *l_username = strdup( username.c_str());
+ char *l_password = strdup( password.c_str());
+
+ result = SQLConnect( m_connection,
+ reinterpret_cast< SQLTCHAR * >( l_dsn ), dsn.length(),
+ reinterpret_cast< SQLTCHAR * >( l_username ), username.length(),
+ reinterpret_cast< SQLTCHAR * >( l_password ), password.length());
+
+ free( l_dsn );
+ free( l_username );
+ free( l_password );
+
+ testResult( result, SQL_HANDLE_DBC, m_connection, "Could not connect to ODBC datasource." );
+
+
+ m_busy = false;
+ m_log = false;
+}
+
+
+// Destructor.
+SODBC::~SODBC( void )
+{
+ // Disconnect from database and free all used resources.
+ // SQLFreeHandle( SQL_HANDLE_STMT, m_statement );
+
+ SQLDisconnect( m_connection );
+
+ SQLFreeHandle( SQL_HANDLE_DBC, m_connection );
+ SQLFreeHandle( SQL_HANDLE_ENV, m_environment );
+
+ // Free all allocated column memory.
+ // for ( int i = 0; i < m_columnInfo.size(); i++ )
+ // {
+ // if ( m_columnInfo[ i ].m_pData )
+ // delete m_columnInfo[ i ].m_pData;
+ // }
+}
+
+// Executes a command.
+void SODBC::execute( const std::string & command )
+{
+ SODBCStatement stmt(command, m_log, 0, m_connection);
+
+ stmt.execute()->reset();
+}
+
+// Sets the log state.
+void SODBC::setLog( bool state )
+{
+ m_log = state;
+}
+
+// Returns an exception.
+SSqlException SODBC::sPerrorException( const std::string & reason )
+{
+ return SSqlException( reason );
+}
+
+SSqlStatement* SODBC::prepare(const string& query, int nparams)
+{
+ return new SODBCStatement(query, m_log, nparams, m_connection);
+}
+
+
+void SODBC::startTransaction() {
+ // cerr<<"starting transaction"<<endl;
+ SQLRETURN result;
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "startTransaction (enable autocommit) failed" );
+}
+
+void SODBC::commit() {
+ // cerr<<"commit!"<<endl;
+ SQLRETURN result;
+
+ result = SQLEndTran(SQL_HANDLE_DBC, m_connection, SQL_COMMIT); // don't really need this, AUTOCOMMIT_OFF below will also commit
+ testResult( result, SQL_HANDLE_DBC, m_connection, "commit failed" );
+
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "disabling autocommit after commit failed" );
+}
+
+void SODBC::rollback() {
+ // cerr<<"rollback!"<<endl;
+ SQLRETURN result;
+
+ result = SQLEndTran(SQL_HANDLE_DBC, m_connection, SQL_ROLLBACK);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "rollback failed" );
+
+ result = SQLSetConnectAttr(m_connection, SQL_ATTR_AUTOCOMMIT, SQL_AUTOCOMMIT_OFF, 0);
+ testResult( result, SQL_HANDLE_DBC, m_connection, "disabling autocommit after rollback failed" );
+}
+
+void SODBC::testResult(SQLRETURN result, SQLSMALLINT type, SQLHANDLE handle, const std::string & message) {
+ std::string errorMessage;
+ if (!realTestResult(result, type, handle, message, errorMessage)) throw SSqlException(errorMessage);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SODBC_HH
+#define SODBC_HH
+
+#include <string>
+#include <vector>
+
+#include <sql.h>
+#include <sqlext.h>
+
+#include "pdns/backends/gsql/ssql.hh"
+
+//! ODBC SSql implementation for use with the Generic ODBC Backend.
+class SODBC : public SSql
+{
+private:
+
+
+ bool m_log; //!< Should we log?
+ bool m_busy; //!< Are we busy executing a query?
+
+ SQLHDBC m_connection; //!< Database connection handle.
+ SQLHENV m_environment; //!< Database environment handle
+
+ void testResult(SQLRETURN result, SQLSMALLINT type, SQLHANDLE handle, const std::string & message);
+
+public:
+ //! Default constructor.
+ /*!
+ This constructor connects to an ODBC datasource and makes sure it's ready to use.
+
+ \param dsn The ODBC DSN to use.
+ \param username Username to use.
+ \param password Password to use.
+ */
+ SODBC(
+ const std::string & dsn,
+ const std::string & username,
+ const std::string & password
+ );
+
+ //! Destructor.
+ virtual ~SODBC( void );
+
+ //! Sets the logging state.
+ void setLog( bool state );
+
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+ void startTransaction();
+ void rollback();
+ void commit();
+
+ //! Returns an exception.
+ SSqlException sPerrorException( const std::string & reason );
+
+};
+
+
+#endif // SODBC_HH
--- /dev/null
+AM_CPPFLAGS += $(ORACLE_CFLAGS)
+
+pkglib_LTLIBRARIES = libgoraclebackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ drop-schema.goracle.sql \
+ schema.goracle.sql
+
+dist_doc_DATA = \
+ drop-schema.goracle.sql \
+ schema.goracle.sql
+
+libgoraclebackend_la_SOURCES = \
+ goraclebackend.cc goraclebackend.hh \
+ soracle.cc soracle.hh
+
+libgoraclebackend_la_LDFLAGS = -module -avoid-version
+libgoraclebackend_la_LIBADD = $(ORACLE_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/goraclebackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgoraclebackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libgoraclebackend_la_OBJECTS = goraclebackend.lo soracle.lo
+libgoraclebackend_la_OBJECTS = $(am_libgoraclebackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgoraclebackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgoraclebackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgoraclebackend_la_SOURCES)
+DIST_SOURCES = $(libgoraclebackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(ORACLE_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libgoraclebackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ drop-schema.goracle.sql \
+ schema.goracle.sql
+
+dist_doc_DATA = \
+ drop-schema.goracle.sql \
+ schema.goracle.sql
+
+libgoraclebackend_la_SOURCES = \
+ goraclebackend.cc goraclebackend.hh \
+ soracle.cc soracle.hh
+
+libgoraclebackend_la_LDFLAGS = -module -avoid-version
+libgoraclebackend_la_LIBADD = $(ORACLE_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/goraclebackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/goraclebackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgoraclebackend.la: $(libgoraclebackend_la_OBJECTS) $(libgoraclebackend_la_DEPENDENCIES) $(EXTRA_libgoraclebackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgoraclebackend_la_LINK) -rpath $(pkglibdir) $(libgoraclebackend_la_OBJECTS) $(libgoraclebackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/goraclebackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/soracle.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+goraclebackend.lo soracle.lo
--- /dev/null
+DROP TABLE records;
+DROP SEQUENCE records_id_sequence;
+
+DROP TABLE supermasters;
+
+DROP TABLE comments;
+DROP SEQUENCE comments_id_sequence;
+
+DROP TABLE domainmetadata;
+DROP SEQUENCE domainmetadata_id_sequence;
+
+DROP TABLE cryptokeys;
+DROP SEQUENCE cryptokeys_id_sequence;
+
+DROP TABLE tsigkeys;
+DROP SEQUENCE tsigkeys_id_sequence;
+
+DROP TABLE domains;
+DROP SEQUENCE domains_id_sequence;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <map>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/lock.hh"
+#include "goraclebackend.hh"
+#include "soracle.hh"
+#include <sstream>
+
+static OCIEnv* d_environmentHandle = 0;
+static pthread_mutex_t s_goracle_lock=PTHREAD_MUTEX_INITIALIZER;
+
+gOracleBackend::gOracleBackend(const string &mode, const string &suffix) : GSQLBackend(mode, suffix)
+{
+ Lock gl(&s_goracle_lock);
+ if (d_environmentHandle == 0) {
+ setenv("ORACLE_HOME", getArg("home").c_str(), 1);
+ setenv("ORACLE_SID", getArg("sid").c_str(), 1);
+ setenv("NLS_LANG", getArg("nls-lang").c_str(), 1);
+
+ int err = OCIEnvCreate(&d_environmentHandle, OCI_THREADED, NULL, NULL, NULL, NULL, 0, NULL);
+
+ if (err) {
+ throw PDNSException("OCIEnvCraete failed");
+ }
+ }
+
+ try {
+ // set Oracle envionment variables
+ setDB(new SOracle(getArg("tnsname"),
+ getArg("user"),
+ getArg("password"),
+ mustDo("release-statements"),
+ d_environmentHandle));
+ }
+
+ catch (SSqlException &e) {
+ L<<Logger::Error << mode << " Connection failed: " << e.txtReason() << endl;
+ throw PDNSException("Unable to launch " + mode + " connection: " + e.txtReason());
+ }
+ L<<Logger::Info << mode << " Connection successful" << endl;
+}
+
+class gOracleFactory : public BackendFactory
+{
+public:
+ gOracleFactory(const string &mode) : BackendFactory(mode), d_mode(mode) {}
+
+ void declareArguments(const string &suffix="") {
+ declare(suffix,"home", "Oracle home path", "");
+ declare(suffix,"sid", "Oracle sid", "XE");
+ declare(suffix,"nls-lang", "Oracle language", "AMERICAN_AMERICA.AL32UTF8");
+
+ declare(suffix,"tnsname","Generic Oracle backend TNSNAME to connect to","powerdns");
+ declare(suffix,"user","Database backend user to connect as","powerdns");
+ declare(suffix,"password","Pdns backend password to connect with","");
+
+ declare(suffix,"dnssec","Enable DNSSEC processing","no");
+ declare(suffix,"release-statements","Release statements between executions, uses less resources","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=:qtype and name=:qname");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=:qtype and name=:qname and domain_id=:domain_id");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=:qname");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=:qname and domain_id=:domain_id");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR disabled=:include_disabled) and domain_id=:domain_id order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id");
+
+ declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null");
+ declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=:domain_id and name=:qname and type is null");
+
+ declare(suffix, "master-zone-query", "Data", "select master from domains where name=:domain and type='SLAVE'");
+
+ declare(suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type,account from domains where name=:domain");
+
+ declare(suffix, "info-all-slaves-query", "","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver");
+ declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account");
+ declare(suffix, "insert-zone-query", "", "insert into domains (id,type,name,master,account,last_check_notified_serial) values(domains_id_sequence.nextval,:type,:domain,:masters,:account, null, null)");
+ declare(suffix, "insert-record-query", "", "insert into records (id,content,ttl,prio,type,domain_id,disabled,name,ordername,auth,change_date) values (records_id_sequence.nextval,:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:ordername || ' ',:auth, null)");
+ declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (id,type,domain_id,disabled,name,ordername,auth,ttl,prio,change_date,content) values (records_id_sequence.nextval,null,:domain_id,0,:qname,:ordername,:auth,null,null,null,null)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select * FROM (select trim(ordername) from records where disabled=0 and domain_id=:domain_id and ordername is not null order by ordername asc) where rownum=1");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select * FROM (select trim(ordername), name from records where disabled=0 and ordername <= :ordername || ' ' and domain_id=:domain_id and ordername is not null order by ordername desc) where rownum=1");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select trim(min(ordername)) from records where disabled=0 and ordername > :ordername || ' ' and domain_id=:domain_id and ordername is not null");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select * from (select trim(ordername), name from records where disabled=0 and ordername != ' ' and domain_id=:domain_id and ordername is not null order by ordername desc) where rownum=1");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=:ordername || ' ',auth=:auth where domain_id=:domain_id and name=:qname and disabled=0");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=:ordername || ' ',auth=:auth where domain_id=:domain_id and name=:qname and type=:qtype and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and type=:qtype and disabled=0");
+
+ declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain");
+ declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain");
+ declare(suffix, "update-account-query", "", "update domains set account=:account where name=:domain");
+ declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
+ declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
+ declare(suffix, "zone-lastchange-query", "", "select max(change_date) from records where domain_id=:domain_id");
+ declare(suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix, "delete-domain-query","", "delete from domains where name=:domain");
+ declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id");
+ declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype");
+ declare(suffix, "delete-names-query", "", "delete from records where domain_id=:domain_id and name=:qname");
+
+ declare(suffix, "add-domain-key-query","", "insert into cryptokeys (id, domain_id, flags, active, content) select cryptokeys_id_sequence.nextval, id, :flags,:active, :content from domains where name=:domain");
+ declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain");
+ declare(suffix, "get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain");
+ declare(suffix, "get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain and domainmetadata.kind=:kind");
+ declare(suffix, "clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain) and domainmetadata.kind=:kind");
+ declare(suffix, "clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain)");
+ declare(suffix, "set-domain-metadata-query","", "insert into domainmetadata (id, domain_id, kind, content) select domainmetadata_id_sequence.nextval, id, :kind, :content from domains where name=:domain");
+ declare(suffix, "activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain)");
+ declare(suffix, "get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=:key_name");
+ declare(suffix, "set-tsig-key-query","", "merge into tsigkeys tk using dual on (name = :key_name and algorithm = :algorithm) when not matched then insert (id, name, algorithm, secret) values(tsigkeys_id_sequence.nextval, :key_name, :algorithm, :content) when matched then update set secret = :content");
+ declare(suffix, "delete-tsig-key-query","", "delete from tsigkeys where name=:key_name");
+ declare(suffix, "get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domain.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR records.disabled=:include_disabled");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,\"comment\" FROM comments WHERE domain_id=:domain_id");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (id, domain_id, name, type, modified_at, account, \"comment\") VALUES (comments_id_sequence.nextval, :domain_id, :qname, :qtype, :modified_at, :account, :content)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=:domain_id AND name=:qname AND type=:qtype");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=:domain_id");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE :value OR content LIKE :value2 LIMIT :limit");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE :value OR comment LIKE :value2 LIMIT :limit");
+
+ }
+
+ DNSBackend* make(const string &suffix="") {
+ return new gOracleBackend(d_mode,suffix);
+ }
+
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gOracleLoader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gOracleLoader() {
+ BackendMakers().report(new gOracleFactory("goracle"));
+ L << Logger::Info << "[goraclebackend] This is the goracle backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+//! Reports the backendloader to the UeberBackend.
+static gOracleLoader goracleloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GORACLEBACKEND_HH
+#define PDNS_GORACLEBACKEND_HH
+
+#include <string>
+#include <map>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+#include "pdns/namespaces.hh"
+
+/** The gOracleBackend is a DNSBackend that can answer DNS related questions. It looks up data
+ in PostgreSQL */
+class gOracleBackend : public GSQLBackend
+{
+public:
+ gOracleBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails.
+};
+
+#endif /* PDNS_GORACLEBACKEND_HH */
--- /dev/null
+CREATE TABLE domains (
+ id INTEGER NOT NULL,
+ name VARCHAR2(255) NOT NULL,
+ master VARCHAR2(128) DEFAULT NULL,
+ last_check INTEGER DEFAULT NULL,
+ type VARCHAR2(6) NOT NULL,
+ notified_serial NUMBER(10,0) DEFAULT NULL,
+ account VARCHAR2(40) DEFAULT NULL,
+ PRIMARY KEY (id)
+);
+
+CREATE SEQUENCE domains_id_sequence;
+CREATE INDEX domains$name ON domains (name);
+
+
+CREATE TABLE records (
+ id INTEGER NOT NULL,
+ domain_id INTEGER DEFAULT NULL REFERENCES domains (id) ON DELETE CASCADE,
+ name VARCHAR2(255) DEFAULT NULL,
+ type VARCHAR2(10) DEFAULT NULL,
+ content VARCHAR2(4000) DEFAULT NULL,
+ ttl INTEGER DEFAULT NULL,
+ prio INTEGER DEFAULT NULL,
+ change_date INTEGER DEFAULT NULL,
+ disabled NUMBER(1,0) DEFAULT 0 NOT NULL,
+ ordername VARCHAR2(255) DEFAULT NULL,
+ auth NUMBER(1,0) DEFAULT 1 NOT NULL,
+ PRIMARY KEY (id)
+) pctfree 40;
+
+CREATE SEQUENCE records_id_sequence;
+CREATE INDEX records$nametype ON records (name, type);
+CREATE INDEX records$domain_id ON records (domain_id);
+CREATE INDEX records$recordorder ON records (domain_id, ordername);
+
+
+CREATE TABLE supermasters (
+ ip VARCHAR2(64) NOT NULL,
+ nameserver VARCHAR2(255) NOT NULL,
+ account VARCHAR2(40) NOT NULL,
+ PRIMARY KEY (ip, nameserver)
+);
+
+
+CREATE TABLE comments (
+ id INTEGER NOT NULL,
+ domain_id INTEGER NOT NULL REFERENCES domains (id) ON DELETE CASCADE,
+ name VARCHAR2(255) NOT NULL,
+ type VARCHAR2(10) NOT NULL,
+ modified_at INTEGER NOT NULL,
+ account VARCHAR2(40) NOT NULL,
+ "comment" VARCHAR2(4000) NOT NULL
+);
+CREATE SEQUENCE comments_id_sequence;
+CREATE INDEX comments$nametype ON comments (name, type);
+CREATE INDEX comments$domain_id ON comments (domain_id);
+CREATE INDEX comments$order ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id INTEGER NOT NULL,
+ domain_id INTEGER NOT NULL,
+ kind VARCHAR2(32),
+ content VARCHAR2(4000),
+ PRIMARY KEY (id)
+);
+
+CREATE SEQUENCE domainmetadata_id_sequence;
+CREATE INDEX domainmetadata$domain_id ON domainmetadata (domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id INTEGER NOT NULL,
+ domain_id INTEGER NOT NULL,
+ flags INTEGER NOT NULL,
+ active INTEGER NOT NULL,
+ content VARCHAR2(4000),
+ PRIMARY KEY (id)
+);
+
+CREATE SEQUENCE cryptokeys_id_sequence;
+CREATE INDEX cryptokeys$domain_id ON cryptokeys (domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INTEGER NOT NULL,
+ name VARCHAR2(255),
+ algorithm VARCHAR2(50),
+ secret VARCHAR2(255),
+ PRIMARY KEY (id)
+);
+
+CREATE SEQUENCE tsigkeys_id_sequence;
+CREATE UNIQUE INDEX tsigkeys$namealgo ON tsigkeys (name, algorithm);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "soracle.hh"
+#include <string>
+#include <iostream>
+#include "pdns/misc.hh"
+#include "pdns/logger.hh"
+#include "pdns/dns.hh"
+#include "pdns/namespaces.hh"
+#include "pdns/md5.hh"
+
+static AtomicCounter s_txid;
+
+bool SOracle::s_dolog;
+
+class SOracleStatement: public SSqlStatement {
+public:
+ SOracleStatement(const string& query, bool dolog, int nparams, OCIEnv *ctx, OCISvcCtx *svc_ctx, bool release_stmt) {
+ d_query = query;
+ d_ctx = ctx;
+ d_svcctx = svc_ctx;
+ d_dolog = dolog;
+ d_res = NULL;
+ d_bind = NULL;
+ d_stmt = NULL;
+ d_err = NULL;
+ d_queryResult = OCI_NO_DATA;
+ d_paridx = d_parnum = d_resnum = d_residx = 0;
+ d_release_stmt = release_stmt;
+ d_non_null_ind = 0;
+ d_null_ind = -1;
+ d_init = false;
+ d_prepared = false;
+ d_parnum = nparams;
+ // create a key
+ string key = pdns_md5sum(d_query);
+ d_stmt_keysize = std::min(key.size()*2, sizeof(d_stmt_key));
+ for(string::size_type i = 0; i < key.size() && i*2 < d_stmt_keysize; i++)
+ snprintf((char*)&(d_stmt_key[i*2]), 3, "%02x", (unsigned char)key[i]);
+ d_stmt_key[d_stmt_keysize] = 0;
+ }
+
+ SSqlStatement* bind(const string& name, bool value)
+ {
+ return bind(name, (int)value);
+ }
+ SSqlStatement* bind(const string& name, int value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val4 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), &(d_bind[d_paridx].val4), sizeof(sb4), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, uint32_t value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val4 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(ub4), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, long value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val4 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(sb4), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, unsigned long value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val4 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (ub4*)&(d_bind[d_paridx].val4), sizeof(ub4), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, long long value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val8 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (orasb8*)&(d_bind[d_paridx].val8), sizeof(orasb8), SQLT_INT, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, unsigned long long value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].val8 = value;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (oraub8*)&(d_bind[d_paridx].val8), sizeof(oraub8), SQLT_UIN, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bind(const string& name, const std::string& value)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ d_bind[d_paridx].vals = new text[value.size()+1];
+ memset(d_bind[d_paridx].vals, 0, value.size()+1);
+ value.copy((char*)d_bind[d_paridx].vals, value.size());
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), (text*)d_bind[d_paridx].vals, value.size()+1, SQLT_STR, &d_non_null_ind,0,0,0,0,OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bindNull(const string& name)
+ {
+ if (d_paridx >= d_parnum)
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ prepareStatement();
+ string zName = string(":") + name;
+ if (OCIBindByName(d_stmt, &(d_bind[d_paridx].handle), d_err, (text*)zName.c_str(), zName.size(), NULL, 0, SQLT_STR, &d_null_ind, 0, 0, 0, 0, OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException(string("Cannot bind parameter ") + name + string(": ") + OCIErrStr());
+ }
+ d_bind[d_paridx].release = true; // remember to free this
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* execute()
+ {
+ if (d_query.size() == 0) return this; // do not execute empty queries
+ prepareStatement();
+
+ if (d_dolog)
+ L<<Logger::Warning<<"Query: "<<d_query<<endl;
+ ub2 fntype;
+ ub4 iters;
+
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&fntype, 0, OCI_ATTR_STMT_TYPE, d_err))
+ throw SSqlException("Cannot get statement type: " + d_query + string(": ") + OCIErrStr());
+
+ if (fntype == OCI_STMT_SELECT) iters = 0;
+ else iters = 1;
+
+ d_queryResult = OCIStmtExecute(d_svcctx, d_stmt, d_err, iters, 0, NULL, NULL, OCI_DEFAULT);
+ if (d_queryResult != OCI_NO_DATA && d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO) {
+ throw SSqlException("Cannot execute statement: " + d_query + string(": ") + OCIErrStr());
+ }
+
+ d_resnum = d_residx = 0;
+
+ if (fntype == OCI_STMT_SELECT) {
+ ub4 o_fnum;
+ ub4 o_resnum;
+
+ // figure out what the result looks like
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&o_resnum, 0, OCI_ATTR_ROW_COUNT, d_err))
+ throw SSqlException("Cannot get statement result row count: " + d_query + string(": ") + OCIErrStr()); // this returns 0
+ if (OCIAttrGet(d_stmt, OCI_HTYPE_STMT, (dvoid*)&o_fnum, 0, OCI_ATTR_PARAM_COUNT, d_err))
+ throw SSqlException("Cannot get statement result column count: " + d_query + string(": ") + OCIErrStr());
+
+ d_residx = 0;
+ d_resnum = o_resnum;
+ d_fnum = o_fnum;
+
+ if (d_res == NULL && d_fnum > 0) {
+ ub2 o_attrtype;
+ OCIParam *parms = NULL;
+ d_res = new struct oresult[d_fnum];
+ memset(d_res, 0, sizeof(struct oresult)*d_fnum);
+
+ for(int i=0; i < d_fnum; i++) {
+ if (OCIParamGet(d_stmt, OCI_HTYPE_STMT, d_err, (dvoid**)&parms, (ub4)i+1) != OCI_SUCCESS) {
+ throw SSqlException("Cannot get statement result column information: " + d_query + string(": ") + OCIErrStr());
+ }
+
+ if (OCIAttrGet(parms, OCI_DTYPE_PARAM, (dvoid*)&(d_res[i].colsize), 0, OCI_ATTR_DATA_SIZE, d_err) != OCI_SUCCESS) {
+ throw SSqlException("Cannot get statement result column information: " + d_query + string(": ") + OCIErrStr());
+ }
+
+ if (d_res[i].colsize == 0) {
+ if (OCIAttrGet(parms, OCI_DTYPE_PARAM, (dvoid*)&o_attrtype, 0, OCI_ATTR_DATA_TYPE, d_err) != OCI_SUCCESS) {
+ throw SSqlException("Cannot get statement result column information: " + d_query + string(": ") + OCIErrStr());
+ }
+
+ // oracle 11g returns 0 for integer fields - we know oracle should return 22.
+ if (o_attrtype == OCI_TYPECODE_INTEGER ||
+ o_attrtype == OCI_TYPECODE_SMALLINT ||
+ o_attrtype == OCI_TYPECODE_REAL ||
+ o_attrtype == OCI_TYPECODE_DOUBLE ||
+ o_attrtype == OCI_TYPECODE_FLOAT ||
+ o_attrtype == OCI_TYPECODE_NUMBER ||
+ o_attrtype == OCI_TYPECODE_DECIMAL) d_res[i].colsize = 22;
+ }
+ d_res[i].content = new char[d_res[i].colsize+1];
+ }
+ }
+
+ if (d_fnum > 0) {
+ for(int i=0;i<d_fnum;i++) {
+ if (OCIDefineByPos(d_stmt, &(d_res[i].handle), d_err, i+1, d_res[i].content, d_res[i].colsize+1, SQLT_STR, (dvoid*)&(d_res[i].ind), NULL, NULL, OCI_DEFAULT))
+ throw SSqlException("Cannot bind result column: " + d_query + string(": ") + OCIErrStr());
+ }
+ }
+
+ d_queryResult = OCIStmtFetch2(d_stmt, d_err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ return this;
+ }
+
+ string OCIErrStr()
+ {
+ string mReason = "ORA-UNKNOWN";
+ if (d_err != NULL) {
+ text msg[512];
+ sb4 errcode = 0;
+ memset(msg, 0, 512);
+ OCIErrorGet((dvoid*) d_err,1, NULL, &errcode, msg, sizeof(msg), OCI_HTYPE_ERROR);
+ if (errcode) {
+ char* p = (char*) msg;
+ while (*p++ != 0x00) {
+ if (*p == '\n' || *p == '\r') {
+ *p = ';';
+ }
+ }
+ mReason = (char*) msg;
+ }
+ }
+ return mReason;
+ }
+
+ bool hasNextRow() {
+ if (d_queryResult == OCI_NO_DATA) return false;
+ return true;
+ }
+
+ SSqlStatement* nextRow(row_t& row) {
+ row.clear();
+
+ if (d_stmt == NULL) return this;
+
+ if (d_queryResult == OCI_NO_DATA) return this;
+
+ if (d_queryResult != OCI_SUCCESS && d_queryResult != OCI_SUCCESS_WITH_INFO) {
+ throw SSqlException("Cannot get next row: " + d_query + string(": ") + OCIErrStr());
+ }
+
+ row.reserve(d_fnum);
+
+ for (int i=0; i < d_fnum ; i++) {
+
+ if (d_res[i].ind>=0) {
+ row.push_back(d_res[i].content);
+ } else {
+ row.push_back("");
+ }
+ }
+
+ d_queryResult = OCIStmtFetch2(d_stmt, d_err, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ d_residx++;
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ row_t row;
+
+ result.reserve(d_resnum);
+ while(hasNextRow()) {
+ nextRow(row);
+ result.push_back(row);
+ }
+
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ d_paridx = 0;
+ d_residx = d_resnum = 0;
+
+ if (d_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_bind[i].vals && d_bind[i].release) delete [] (text*)d_bind[i].vals;
+ }
+ }
+ d_bind = new struct obind[d_parnum];
+ memset(d_bind, 0, sizeof(struct obind)*d_parnum);
+
+ if (d_release_stmt) {
+ if (OCIStmtRelease(d_stmt, d_err, (text*)d_stmt_key, d_stmt_keysize, OCI_DEFAULT) != OCI_SUCCESS)
+ throw SSqlException("Could not release statement: " + d_query + string(": ") + OCIErrStr());
+ d_stmt = NULL;
+ }
+ return this;
+ }
+
+ const std::string& getQuery() {
+ return d_query;
+ }
+
+ ~SOracleStatement() {
+ releaseStatement();
+ }
+
+private:
+
+ void initStatement() {
+ if (d_query.size()==0) return;
+ if (d_prepared) return;
+
+ if (OCIHandleAlloc(d_ctx, (dvoid**)&d_err, OCI_HTYPE_ERROR, 0, NULL))
+ throw SSqlException("Cannot allocate statement error handle");
+
+ if (d_release_stmt) {
+ if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)d_query.c_str(), d_query.size(),
+ NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) {
+ // failed.
+ throw SSqlException("Cannot prepare statement: " + d_query + string(": ") + OCIErrStr());
+ }
+ d_init = true;
+ } else {
+ d_init = false;
+ }
+
+ d_bind = new struct obind[d_parnum];
+ memset(d_bind, 0, sizeof(struct obind)*d_parnum);
+ // and we are done.
+ }
+
+ void prepareStatement() {
+ initStatement();
+ if (d_stmt) return; // no-op
+ if (d_query.size()==0) return;
+ if (d_init == false) {
+ if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)d_query.c_str(), d_query.size(), NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException("Cannot prepare statement: " + d_query + string(": ") + OCIErrStr());
+ }
+ d_init = true;
+ } else {
+ if (OCIStmtPrepare2(d_svcctx, &d_stmt, d_err, (text*)d_query.c_str(), d_query.size(), d_stmt_key, d_stmt_keysize, OCI_NTV_SYNTAX, OCI_DEFAULT) != OCI_SUCCESS) {
+ throw SSqlException("Cannot prepare statement: " + d_query + string(": ") + OCIErrStr());
+ }
+ }
+
+ d_prepared = true;
+ }
+
+ void releaseStatement() {
+ try {
+ reset();
+ } catch(SSqlException) {
+ // ignore, can't be helped.
+ }
+ if (d_stmt)
+ OCIStmtRelease(d_stmt, d_err, d_stmt_key, d_stmt_keysize, OCI_STRLS_CACHE_DELETE);
+ if (d_err)
+ OCIHandleFree(d_err, OCI_HTYPE_ERROR);
+ if (d_res) {
+ for(int i=0;i<d_fnum;i++)
+ if (d_res[i].content) delete [] d_res[i].content;
+ delete [] d_res;
+ }
+ if (d_bind) {
+ for(int i=0;i<d_parnum;i++) {
+ if (d_bind[i].vals && d_bind[i].release) delete [] (text*)d_bind[i].vals;
+ }
+ }
+ d_init = false;
+ d_prepared = false;
+ }
+
+ string d_query;
+ OCIEnv *d_ctx;
+ OCISvcCtx *d_svcctx;
+ bool d_dolog;
+ bool d_release_stmt;
+ bool d_init;
+ bool d_prepared;
+ OCIStmt* d_stmt;
+ OCIError* d_err;
+ int d_parnum;
+ int d_paridx;
+ int d_resnum;
+ int d_residx;
+ int d_fnum;
+ dsword d_queryResult;
+ struct oresult {
+ OCIDefine *handle;
+ char* content;
+ sb4 ind;
+ ub4 colsize;
+ }* d_res;
+ struct obind {
+ OCIBind *handle;
+ ub4 val4;
+ oraub8 val8;
+ void* vals;
+ bool release;
+ }* d_bind;
+
+ sb4 d_non_null_ind;
+ sb4 d_null_ind;
+ text d_stmt_key[64];
+ size_t d_stmt_keysize;
+};
+
+
+SOracle::SOracle(const string &database,
+ const string &user,
+ const string &password,
+ bool releaseStatements,
+ OCIEnv* oraenv)
+{
+ d_environmentHandle = oraenv;
+ d_errorHandle = NULL;
+ d_serviceContextHandle = NULL;
+ d_release_stmt = releaseStatements;
+
+ // Allocate an error handle
+
+ int err = OCIHandleAlloc(d_environmentHandle, (dvoid**) &d_errorHandle, OCI_HTYPE_ERROR, 0, NULL);
+ if (err) {
+ throw sPerrorException("OCIHandleAlloc(errorHandle)" + string(": ") + getOracleError());
+ }
+
+ err = OCILogon2(d_environmentHandle, d_errorHandle, &d_serviceContextHandle, (OraText*)user.c_str(), user.size(),
+ (OraText*) password.c_str(), strlen(password.c_str()), (OraText*) database.c_str(), strlen(database.c_str()), OCI_LOGON2_STMTCACHE);
+ // increase statement cache to 100
+ if (err) {
+ throw sPerrorException(string("OCILogon2") + string(": ") + getOracleError());
+ }
+
+ ub4 cacheSize = 100;
+ err = OCIAttrSet(d_serviceContextHandle, OCI_HTYPE_SVCCTX, &cacheSize, sizeof(ub4), OCI_ATTR_STMTCACHESIZE, d_errorHandle);
+ if (err) {
+ throw sPerrorException("OCIAttrSet(stmtcachesize): " + string(": ") + getOracleError());
+ }
+
+}
+
+void SOracle::setLog(bool state)
+{
+ s_dolog=state;
+}
+
+SOracle::~SOracle()
+{
+ int err;
+ if (d_serviceContextHandle != NULL) {
+ err=OCILogoff(d_serviceContextHandle, d_errorHandle);
+ if (err) {
+ L<<Logger::Warning<<"Problems logging out: "+getOracleError()<<endl;
+ }
+ }
+
+ if (d_errorHandle != NULL) {
+ OCIHandleFree(d_errorHandle, OCI_HTYPE_ERROR);
+ d_errorHandle = NULL;
+ }
+}
+
+void SOracle::startTransaction() {
+ std::string cmd = "SET TRANSACTION NAME 'pdns_" + std::to_string(s_txid++) + "'";
+ execute(cmd);
+}
+
+void SOracle::commit() {
+ execute("COMMIT");
+}
+
+void SOracle::rollback() {
+ execute("ROLLBACK");
+}
+
+SSqlException SOracle::sPerrorException(const string &reason)
+{
+ return SSqlException(reason);
+}
+
+SSqlStatement* SOracle::prepare(const string& query, int nparams) {
+ return new SOracleStatement(query, s_dolog, nparams, d_environmentHandle, d_serviceContextHandle, d_release_stmt);
+}
+
+void SOracle::execute(const string& query) {
+ SOracleStatement(query, s_dolog, 0, d_environmentHandle, d_serviceContextHandle, true).execute();
+}
+
+string SOracle::getOracleError()
+{
+ string mReason = "ORA-UNKNOWN";
+ if (d_errorHandle != NULL) {
+ text msg[512];
+ sb4 errcode = 0;
+ memset(msg, 0, 512);
+ OCIErrorGet((dvoid*) d_errorHandle,1, NULL, &errcode, msg, sizeof(msg), OCI_HTYPE_ERROR);
+ if (errcode) {
+ char* p = (char*) msg;
+ while (*p++ != 0x00) {
+ if (*p == '\n' || *p == '\r') {
+ *p = ';';
+ }
+ }
+ mReason = (char*) msg;
+ }
+ }
+ return mReason;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SORACLE_HH
+#define SORACLE_HH
+
+#include "pdns/backends/gsql/ssql.hh"
+#include "pdns/utility.hh"
+#include <oci.h>
+#include <oratypes.h>
+#include "pdns/misc.hh"
+
+#ifndef dsword
+typedef sb4 dsword;
+#endif
+
+class SOracle : public SSql
+{
+public:
+ SOracle(const string &database,
+ const string &user="",
+ const string &password="",
+ bool releaseStatements=false,
+ OCIEnv* oraenv=NULL);
+
+ ~SOracle();
+
+ SSqlException sPerrorException(const string &reason);
+ void setLog(bool state);
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+
+ void startTransaction();
+ void commit();
+ void rollback();
+private:
+ OCIEnv* d_environmentHandle;
+ OCIError* d_errorHandle;
+ OCISvcCtx* d_serviceContextHandle;
+
+ string getOracleError();
+ static bool s_dolog;
+ bool d_release_stmt;
+};
+
+#endif /* SSORACLE_HH */
--- /dev/null
+AM_CPPFLAGS += $(PGSQL_inc)
+pkglib_LTLIBRARIES = libgpgsqlbackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.pgsql.sql
+ nodnssec-3.x_to_3.4.0_schema.pgsql.sql \
+ schema.pgsql.sql
+
+dist_doc_DATA = \
+ schema.pgsql.sql \
+ nodnssec-3.x_to_3.4.0_schema.pgsql.sql \
+ dnssec-3.x_to_3.4.0_schema.pgsql.sql
+
+libgpgsqlbackend_la_SOURCES = \
+ gpgsqlbackend.cc gpgsqlbackend.hh \
+ spgsql.cc spgsql.hh
+
+libgpgsqlbackend_la_LDFLAGS = -module -avoid-version
+libgpgsqlbackend_la_LIBADD = $(PGSQL_lib)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/gpgsqlbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libgpgsqlbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libgpgsqlbackend_la_OBJECTS = gpgsqlbackend.lo spgsql.lo
+libgpgsqlbackend_la_OBJECTS = $(am_libgpgsqlbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgpgsqlbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgpgsqlbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgpgsqlbackend_la_SOURCES)
+DIST_SOURCES = $(libgpgsqlbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(PGSQL_inc)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libgpgsqlbackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.pgsql.sql
+
+dist_doc_DATA = \
+ schema.pgsql.sql \
+ nodnssec-3.x_to_3.4.0_schema.pgsql.sql \
+ dnssec-3.x_to_3.4.0_schema.pgsql.sql
+
+libgpgsqlbackend_la_SOURCES = \
+ gpgsqlbackend.cc gpgsqlbackend.hh \
+ spgsql.cc spgsql.hh
+
+libgpgsqlbackend_la_LDFLAGS = -module -avoid-version
+libgpgsqlbackend_la_LIBADD = $(PGSQL_lib)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/gpgsqlbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/gpgsqlbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgpgsqlbackend.la: $(libgpgsqlbackend_la_OBJECTS) $(libgpgsqlbackend_la_DEPENDENCIES) $(EXTRA_libgpgsqlbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgpgsqlbackend_la_LINK) -rpath $(pkglibdir) $(libgpgsqlbackend_la_OBJECTS) $(libgpgsqlbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gpgsqlbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/spgsql.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+ nodnssec-3.x_to_3.4.0_schema.pgsql.sql \
+ schema.pgsql.sql
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+gpgsqlbackend.lo spgsql.lo
--- /dev/null
+-lssl -lcrypto $(PGSQL_lib)
--- /dev/null
+/* Uncomment next 2 lines for versions <= 3.3 */
+/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+/* ALTER TABLE tsigkeys ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+
+ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
+ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
+ALTER TABLE records ALTER COLUMN auth SET DEFAULT 't';
+ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
+ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
+ALTER TABLE supermasters ALTER COLUMN account SET DEFAULT NOT NULL;
+ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);
+ALTER TABLE domainmetadata ALTER COLUMN kind TYPE VARCHAR(32);
+ALTER TABLE tsigkeys ALTER COLUMN algorithm TYPE VARCHAR(50);
+
+CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
+DROP INDEX IF EXISTS orderindex;
+
+
+CREATE TABLE comments (
+ id SERIAL PRIMARY KEY,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL,
+ CONSTRAINT domain_exists
+ FOREIGN KEY(domain_id) REFERENCES domains(id)
+ ON DELETE CASCADE,
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <map>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "gpgsqlbackend.hh"
+#include "spgsql.hh"
+#include <sys/time.h>
+#include <sstream>
+
+gPgSQLBackend::gPgSQLBackend(const string &mode, const string &suffix) : GSQLBackend(mode,suffix)
+{
+ try {
+ setDB(new SPgSQL(getArg("dbname"),
+ getArg("host"),
+ getArg("port"),
+ getArg("user"),
+ getArg("password")));
+ }
+
+ catch(SSqlException &e) {
+ L<<Logger::Error<<mode<<" Connection failed: "<<e.txtReason()<<endl;
+ throw PDNSException("Unable to launch "+mode+" connection: "+e.txtReason());
+ }
+ L<<Logger::Info<<mode<<" Connection successful. Connected to database '"<<getArg("dbname")<<"' on '"<<getArg("host")<<"'."<<endl;
+}
+
+class gPgSQLFactory : public BackendFactory
+{
+public:
+ gPgSQLFactory(const string &mode) : BackendFactory(mode),d_mode(mode) {}
+
+ void declareArguments(const string &suffix="")
+ {
+ declare(suffix,"dbname","Pdns backend database name to connect to","");
+ declare(suffix,"user","Pdns backend user to connect as","");
+ declare(suffix,"host","Pdns backend host to connect to","");
+ declare(suffix,"port","Database backend port to connect to","");
+ declare(suffix,"password","Pdns backend password to connect with","");
+
+ declare(suffix,"dnssec","Enable DNSSEC processing","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled::int,name,auth::int FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=false and type=$1 and name=$2");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=false and type=$1 and name=$2 and domain_id=$3");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=false and name=$1");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=false and name=$1 and domain_id=$2");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=false OR $1) and domain_id=$2 order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=false and (name=$1 OR name like $2) and domain_id=$3");
+
+ declare(suffix,"remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=$1 and type is null");
+ declare(suffix,"delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=$1 and name=$2 and type is null");
+
+ declare(suffix,"master-zone-query","Data", "select master from domains where name=$1 and type='SLAVE'");
+
+ declare(suffix,"info-zone-query","","select id,name,master,last_check,notified_serial,type,account from domains where name=$1");
+
+ declare(suffix,"info-all-slaves-query","","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix,"supermaster-query","", "select account from supermasters where ip=$1 and nameserver=$2");
+ declare(suffix,"supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=$1 and account=$2");
+
+ declare(suffix,"insert-zone-query","", "insert into domains (type,name,master,account,last_check, notified_serial) values($1,$2,$3,$4,null,null)");
+
+ declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth,change_date) values ($1,$2,$3,$4,$5,$6,$7,$8,$9,null)");
+ declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth,ttl,prio,change_date,content) values (null,$1,false,$2,$3,$4,null,null,null,null)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, last", "select ordername from records where disabled=false and domain_id=$1 and ordername is not null order by 1 using ~<~ limit 1");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=false and ordername ~<=~ $1 and domain_id=$2 and ordername is not null order by 1 using ~>~ limit 1");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select ordername from records where disabled=false and ordername ~>~ $1 and domain_id=$2 and ordername is not null order by 1 using ~<~ limit 1");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=false and ordername != '' and domain_id=$1 and ordername is not null order by 1 using ~>~ limit 1");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=$1,auth=$2 where domain_id=$3 and name=$4 and disabled=false");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=$1,auth=$2 where domain_id=$3 and name=$4 and type=$5 and disabled=false");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=$1 where domain_id=$2 and name=$3 and disabled=false");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=$1 where domain_id=$2 and name=$3 and type=$4 and disabled=false");
+
+ declare(suffix,"update-master-query","", "update domains set master=$1 where name=$2");
+ declare(suffix,"update-kind-query","", "update domains set type=$1 where name=$2");
+ declare(suffix,"update-account-query","", "update domains set account=$1 where name=$2");
+ declare(suffix,"update-serial-query","", "update domains set notified_serial=$1 where id=$2");
+ declare(suffix,"update-lastcheck-query","", "update domains set last_check=$1 where id=$2");
+ declare(suffix,"zone-lastchange-query", "", "select max(change_date) from records where domain_id=$1");
+ declare(suffix,"info-all-master-query","", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix,"delete-domain-query","", "delete from domains where name=$1");
+ declare(suffix,"delete-zone-query","", "delete from records where domain_id=$1");
+ declare(suffix,"delete-rrset-query","","delete from records where domain_id=$1 and name=$2 and type=$3");
+ declare(suffix,"delete-names-query","","delete from records where domain_id=$1 and name=$2");
+
+ declare(suffix,"add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, $1, $2, $3 from domains where name=$4");
+ declare(suffix,"list-domain-keys-query","", "select cryptokeys.id, flags, case when active then 1 else 0 end as active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=$1");
+ declare(suffix,"get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1");
+ declare(suffix,"get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=$1 and domainmetadata.kind=$2");
+ declare(suffix,"clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=$1) and domainmetadata.kind=$2");
+ declare(suffix,"clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=$1)");
+ declare(suffix,"set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, $1, $2 from domains where name=$3");
+ declare(suffix,"activate-domain-key-query","", "update cryptokeys set active=true where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
+ declare(suffix,"deactivate-domain-key-query","", "update cryptokeys set active=false where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
+ declare(suffix,"remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1) and cryptokeys.id=$2");
+ declare(suffix,"clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=$1)");
+ declare(suffix,"get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=$1");
+ declare(suffix,"set-tsig-key-query","", "insert into tsigkeys (name,algorithm,secret) values($1,$2,$3)");
+ declare(suffix,"delete-tsig-key-query","", "delete from tsigkeys where name=$1");
+ declare(suffix,"get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=false OR $1");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=$1");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES ($1, $2, $3, $4, $5, $6)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=$1 AND name=$2 AND type=$3");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=$1");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE $1 OR content LIKE $2 LIMIT $3");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE $1 OR comment LIKE $2 LIMIT $3");
+
+ }
+
+ DNSBackend *make(const string &suffix="")
+ {
+ return new gPgSQLBackend(d_mode,suffix);
+ }
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gPgSQLLoader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gPgSQLLoader()
+ {
+ BackendMakers().report(new gPgSQLFactory("gpgsql"));
+ L << Logger::Info << "[gpgsqlbackend] This is the gpgsql backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+static gPgSQLLoader gpgsqlloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GPGSQLBACKEND_HH
+#define PDNS_GPGSQLBACKEND_HH
+
+#include <string>
+#include <map>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+#include "pdns/namespaces.hh"
+
+/** The gPgSQLBackend is a DNSBackend that can answer DNS related questions. It looks up data
+ in PostgreSQL */
+class gPgSQLBackend : public GSQLBackend
+{
+public:
+ gPgSQLBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails.
+};
+
+#endif /* PDNS_GPGSQLBACKEND_HH */
--- /dev/null
+/* Uncomment next line for versions <= 3.3 */
+/* ALTER TABLE domains ADD CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT))); */
+
+ALTER TABLE records ADD disabled BOOL DEFAULT 'f';
+ALTER TABLE records ALTER COLUMN content TYPE VARCHAR(65535);
+ALTER TABLE records ADD ordername VARCHAR(255);
+ALTER TABLE records ADD auth BOOL DEFAULT 't';
+ALTER TABLE records ALTER COLUMN type TYPE VARCHAR(10);
+ALTER TABLE supermasters ALTER COLUMN ip TYPE INET USING ip::INET;
+ALTER TABLE supermasters ALTER COLUMN account SET DEFAULT NOT NULL;
+ALTER TABLE supermasters ADD CONSTRAINT supermasters_pkey PRIMARY KEY (ip, nameserver);
+
+CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
+
+
+CREATE TABLE domainmetadata (
+ id SERIAL PRIMARY KEY,
+ domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
+ kind VARCHAR(32),
+ content TEXT
+);
+
+CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id SERIAL PRIMARY KEY,
+ domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ constraint c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+ id SERIAL PRIMARY KEY,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL,
+ CONSTRAINT domain_exists
+ FOREIGN KEY(domain_id) REFERENCES domains(id)
+ ON DELETE CASCADE,
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
--- /dev/null
+CREATE TABLE domains (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255) NOT NULL,
+ master VARCHAR(128) DEFAULT NULL,
+ last_check INT DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INT DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+
+CREATE TABLE records (
+ id SERIAL PRIMARY KEY,
+ domain_id INT DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(65535) DEFAULT NULL,
+ ttl INT DEFAULT NULL,
+ prio INT DEFAULT NULL,
+ change_date INT DEFAULT NULL,
+ disabled BOOL DEFAULT 'f',
+ ordername VARCHAR(255),
+ auth BOOL DEFAULT 't',
+ CONSTRAINT domain_exists
+ FOREIGN KEY(domain_id) REFERENCES domains(id)
+ ON DELETE CASCADE,
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX rec_name_index ON records(name);
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+CREATE INDEX recordorder ON records (domain_id, ordername text_pattern_ops);
+
+
+CREATE TABLE supermasters (
+ ip INET NOT NULL,
+ nameserver VARCHAR(255) NOT NULL,
+ account VARCHAR(40) NOT NULL,
+ PRIMARY KEY(ip, nameserver)
+);
+
+
+CREATE TABLE comments (
+ id SERIAL PRIMARY KEY,
+ domain_id INT NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL,
+ CONSTRAINT domain_exists
+ FOREIGN KEY(domain_id) REFERENCES domains(id)
+ ON DELETE CASCADE,
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE INDEX comments_domain_id_idx ON comments (domain_id);
+CREATE INDEX comments_name_type_idx ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id SERIAL PRIMARY KEY,
+ domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
+ kind VARCHAR(32),
+ content TEXT
+);
+
+CREATE INDEX domainidmetaindex ON domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id SERIAL PRIMARY KEY,
+ domain_id INT REFERENCES domains(id) ON DELETE CASCADE,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id SERIAL PRIMARY KEY,
+ name VARCHAR(255),
+ algorithm VARCHAR(50),
+ secret VARCHAR(255),
+ CONSTRAINT c_lowercase_name CHECK (((name)::TEXT = LOWER((name)::TEXT)))
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include "spgsql.hh"
+#include <sys/time.h>
+#include <iostream>
+#include "pdns/logger.hh"
+#include "pdns/dns.hh"
+#include "pdns/namespaces.hh"
+#include <algorithm>
+
+class SPgSQLStatement: public SSqlStatement
+{
+public:
+ SPgSQLStatement(const string& query, bool dolog, int nparams, SPgSQL* db) {
+ d_query = query;
+ d_dolog = dolog;
+ d_parent = db;
+ d_prepared = false;
+ d_nparams = nparams;
+ d_res = NULL;
+ d_res_set = NULL;
+ paramValues = NULL;
+ paramLengths = NULL;
+ d_do_commit = false;
+ d_paridx = 0;
+ d_residx = 0;
+ d_resnum = 0;
+ d_fnum = 0;
+ d_cur_set = 0;
+ }
+
+ SSqlStatement* bind(const string& name, bool value) { return bind(name, string(value ? "t" : "f")); }
+ SSqlStatement* bind(const string& name, int value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, uint32_t value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, long value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, unsigned long value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, long long value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, unsigned long long value) { return bind(name, std::to_string(value)); }
+ SSqlStatement* bind(const string& name, const std::string& value) {
+ prepareStatement();
+ allocate();
+ if (d_paridx>=d_nparams) {
+ releaseStatement();
+ throw SSqlException("Attempt to bind more parameters than query has: " + d_query);
+ }
+ paramValues[d_paridx] = new char[value.size()+1];
+ memset(paramValues[d_paridx], 0, sizeof(char)*(value.size()+1));
+ value.copy(paramValues[d_paridx], value.size());
+ paramLengths[d_paridx] = value.size();
+ d_paridx++;
+ return this;
+ }
+ SSqlStatement* bindNull(const string& name) { prepareStatement(); d_paridx++; return this; } // these are set null in allocate()
+ SSqlStatement* execute() {
+ prepareStatement();
+ if (d_dolog) {
+ L<<Logger::Warning<<"Query: "<<d_query<<endl;
+ }
+ if (!d_parent->in_trx()) {
+ auto res=PQexec(d_db(),"BEGIN");
+ PQclear(res);
+ d_do_commit = true;
+ } else d_do_commit = false;
+ d_res_set = PQexecPrepared(d_db(), d_stmt.c_str(), d_nparams, paramValues, paramLengths, NULL, 0);
+ ExecStatusType status = PQresultStatus(d_res_set);
+ string errmsg(PQresultErrorMessage(d_res_set));
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) {
+ string errmsg(PQresultErrorMessage(d_res_set));
+ releaseStatement();
+ throw SSqlException("Fatal error during query: " + d_query + string(": ") + errmsg);
+ }
+ d_cur_set = 0;
+ nextResult();
+ return this;
+ }
+
+ void nextResult() {
+ if (d_res_set == NULL) return; // no refcursor
+ if (d_cur_set >= PQntuples(d_res_set)) {
+ PQclear(d_res_set);
+ d_res_set = NULL;
+ return;
+ }
+ // this code handles refcursors if they are returned
+ // by stored procedures. you can return more than one
+ // if you return SETOF refcursor.
+ if (PQftype(d_res_set, 0) == 1790) { // REFCURSOR
+#if PG_VERSION_NUM > 90000
+ // PQescapeIdentifier was added to libpq in postggresql 9.0
+ char *val = PQgetvalue(d_res_set, d_cur_set++, 0);
+ char *portal = PQescapeIdentifier(d_db(), val, strlen(val));
+ string cmd = string("FETCH ALL FROM \"") + string(portal) + string("\"");
+ PQfreemem(portal);
+#else
+ string portal = string(PQgetvalue(d_res_set, d_cur_set++, 0));
+ string cmd = string("FETCH ALL FROM \"") + portal + string("\"");
+#endif
+ // execute FETCH
+ if (d_dolog)
+ L<<Logger::Warning<<"Query: "<<cmd<<endl;
+ d_res = PQexec(d_db(),cmd.c_str());
+ d_resnum = PQntuples(d_res);
+ d_fnum = PQnfields(d_res);
+ d_residx = 0;
+ } else {
+ d_res = d_res_set;
+ d_res_set = NULL;
+ d_resnum = PQntuples(d_res);
+ d_fnum = PQnfields(d_res);
+ }
+ }
+
+ bool hasNextRow()
+ {
+ return d_residx<d_resnum;
+ }
+
+ SSqlStatement* nextRow(row_t& row) {
+ int i;
+ row.clear();
+ if (d_residx>=d_resnum || !d_res) return this;
+ row.reserve(PQnfields(d_res));
+ for(i=0;i<PQnfields(d_res);i++) {
+ if (PQgetisnull(d_res, d_residx, i)) {
+ row.push_back("");
+ } else if (PQftype(d_res, i) == 16) { // BOOLEAN
+ char *val = PQgetvalue(d_res, d_residx, i);
+ row.push_back(val[0] == 't' ? "1" : "0");
+ } else {
+ row.push_back(string(PQgetvalue(d_res, d_residx, i)));
+ }
+ }
+ d_residx++;
+ if (d_residx >= d_resnum) {
+ PQclear(d_res);
+ d_res = NULL;
+ nextResult();
+ }
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ if (d_res == NULL) return this;
+ result.reserve(d_resnum);
+ row_t row;
+ while(hasNextRow()) { nextRow(row); result.push_back(row); }
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ int i;
+ if (!d_parent->in_trx() && d_do_commit) {
+ PGresult *res = PQexec(d_db(),"COMMIT");
+ PQclear(res);
+ }
+ d_do_commit = false;
+ if (d_res)
+ PQclear(d_res);
+ if (d_res_set)
+ PQclear(d_res_set);
+ d_res_set = NULL;
+ d_res = NULL;
+ d_paridx = d_residx = d_resnum = 0;
+ if (paramValues)
+ for(i=0;i<d_nparams;i++)
+ if (paramValues[i]) delete [] paramValues[i];
+ delete [] paramValues;
+ paramValues = NULL;
+ delete [] paramLengths;
+ paramLengths = NULL;
+ return this;
+ }
+
+ const std::string& getQuery() { return d_query; }
+
+ ~SPgSQLStatement() {
+ releaseStatement();
+ }
+private:
+ PGconn* d_db() {
+ return d_parent->db();
+ }
+
+ void releaseStatement() {
+ d_prepared = false;
+ reset();
+ if (!d_stmt.empty()) {
+ string cmd = string("DEALLOCATE " + d_stmt);
+ PGresult *res = PQexec(d_db(), cmd.c_str());
+ PQclear(res);
+ d_stmt.clear();
+ }
+ }
+
+ void prepareStatement() {
+ struct timeval tv;
+ if (d_prepared) return;
+ // prepare a statement
+ gettimeofday(&tv,NULL);
+ this->d_stmt = string("stmt") + std::to_string(tv.tv_sec) + std::to_string(tv.tv_usec);
+ PGresult* res = PQprepare(d_db(), d_stmt.c_str(), d_query.c_str(), d_nparams, NULL);
+ ExecStatusType status = PQresultStatus(res);
+ string errmsg(PQresultErrorMessage(res));
+ PQclear(res);
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) {
+ releaseStatement();
+ throw SSqlException("Fatal error during prepare: " + d_query + string(": ") + errmsg);
+ }
+ paramValues=NULL;
+ d_cur_set=d_paridx=d_residx=d_resnum=d_fnum=0;
+ paramLengths=NULL;
+ d_res=NULL;
+ d_res_set=NULL;
+ d_do_commit=false;
+ d_prepared = true;
+ }
+
+ void allocate() {
+ if (paramValues != NULL) return;
+ paramValues = new char*[d_nparams];
+ paramLengths = new int[d_nparams];
+ memset(paramValues, 0, sizeof(char*)*d_nparams);
+ memset(paramLengths, 0, sizeof(int)*d_nparams);
+ }
+
+ string d_query;
+ string d_stmt;
+ SPgSQL *d_parent;
+ PGresult *d_res_set;
+ PGresult *d_res;
+ bool d_dolog;
+ bool d_prepared;
+ int d_nparams;
+ int d_paridx;
+ char **paramValues;
+ int *paramLengths;
+ int d_residx;
+ int d_resnum;
+ int d_fnum;
+ int d_cur_set;
+ bool d_do_commit;
+};
+
+bool SPgSQL::s_dolog;
+
+SPgSQL::SPgSQL(const string &database, const string &host, const string& port, const string &user,
+ const string &password)
+{
+ d_db=0;
+ d_in_trx = false;
+ d_connectstr="";
+
+ if (!database.empty())
+ d_connectstr+="dbname="+database;
+
+ if (!user.empty())
+ d_connectstr+=" user="+user;
+
+ if(!host.empty())
+ d_connectstr+=" host="+host;
+
+ if(!port.empty())
+ d_connectstr+=" port="+port;
+
+ d_connectlogstr=d_connectstr;
+
+ if(!password.empty()) {
+ d_connectlogstr+=" password=<HIDDEN>";
+ d_connectstr+=" password="+password;
+ }
+
+ d_db=PQconnectdb(d_connectstr.c_str());
+
+ if (!d_db || PQstatus(d_db)==CONNECTION_BAD) {
+ try {
+ throw sPerrorException("Unable to connect to database, connect string: "+d_connectlogstr);
+ }
+ catch(...) {
+ if(d_db)
+ PQfinish(d_db);
+ d_db = 0;
+ throw;
+ }
+ }
+}
+
+void SPgSQL::setLog(bool state)
+{
+ s_dolog=state;
+}
+
+SPgSQL::~SPgSQL()
+{
+ PQfinish(d_db);
+}
+
+SSqlException SPgSQL::sPerrorException(const string &reason)
+{
+ return SSqlException(reason+string(": ")+(d_db ? PQerrorMessage(d_db) : "no connection"));
+}
+
+void SPgSQL::execute(const string& query)
+{
+ PGresult* res = PQexec(d_db, query.c_str());
+ ExecStatusType status = PQresultStatus(res);
+ string errmsg(PQresultErrorMessage(res));
+ PQclear(res);
+ if (status != PGRES_COMMAND_OK && status != PGRES_TUPLES_OK && status != PGRES_NONFATAL_ERROR) {
+ throw sPerrorException("Fatal error during query: " + errmsg);
+ }
+}
+
+SSqlStatement* SPgSQL::prepare(const string& query, int nparams)
+{
+ return new SPgSQLStatement(query, s_dolog, nparams, this);
+}
+
+void SPgSQL::startTransaction() {
+ execute("begin");
+ d_in_trx = true;
+}
+
+void SPgSQL::commit() {
+ execute("commit");
+ d_in_trx = false;
+}
+
+void SPgSQL::rollback() {
+ execute("rollback");
+ d_in_trx = false;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SPGSQL_HH
+#define SPGSQL_HH
+#include "pdns/namespaces.hh"
+#include "pdns/backends/gsql/ssql.hh"
+
+#include <libpq-fe.h>
+class SPgSQL : public SSql
+{
+public:
+ SPgSQL(const string &database, const string &host="", const string& port="",
+ const string &user="", const string &password="");
+
+ ~SPgSQL();
+
+ SSqlException sPerrorException(const string &reason);
+ void setLog(bool state);
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+
+ void startTransaction();
+ void rollback();
+ void commit();
+
+ PGconn* db() { return d_db; }
+ bool in_trx() { return d_in_trx; }
+
+private:
+ PGconn* d_db;
+ string d_connectstr;
+ string d_connectlogstr;
+ static bool s_dolog;
+ bool d_in_trx;
+};
+
+#endif /* SPGSQL_HH */
--- /dev/null
+pkglib_LTLIBRARIES = libgsqlite3backend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ nodnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ schema.sqlite3.sql
+
+dist_doc_DATA = \
+ dnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ nodnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ schema.sqlite3.sql
+
+libgsqlite3backend_la_SOURCES = gsqlite3backend.cc gsqlite3backend.hh
+
+libgsqlite3backend_la_LDFLAGS = -module -avoid-version
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/gsqlite3backend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+libgsqlite3backend_la_LIBADD =
+am_libgsqlite3backend_la_OBJECTS = gsqlite3backend.lo
+libgsqlite3backend_la_OBJECTS = $(am_libgsqlite3backend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libgsqlite3backend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libgsqlite3backend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libgsqlite3backend_la_SOURCES)
+DIST_SOURCES = $(libgsqlite3backend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libgsqlite3backend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ dnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ nodnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ schema.sqlite3.sql
+
+dist_doc_DATA = \
+ dnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ nodnssec-3.x_to_3.4.0_schema.sqlite3.sql \
+ schema.sqlite3.sql
+
+libgsqlite3backend_la_SOURCES = gsqlite3backend.cc gsqlite3backend.hh
+libgsqlite3backend_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/gsqlite3backend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/gsqlite3backend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libgsqlite3backend.la: $(libgsqlite3backend_la_OBJECTS) $(libgsqlite3backend_la_DEPENDENCIES) $(EXTRA_libgsqlite3backend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libgsqlite3backend_la_LINK) -rpath $(pkglibdir) $(libgsqlite3backend_la_OBJECTS) $(libgsqlite3backend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gsqlite3backend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+gsqlite3backend.lo
--- /dev/null
+$(SQLITE3_LIBS)
--- /dev/null
+CREATE TABLE comments (
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL
+);
+
+CREATE INDEX comments_domain_id_index ON comments (domain_id);
+CREATE INDEX comments_nametype_index ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+BEGIN TRANSACTION;
+ CREATE TEMPORARY TABLE records_backup(
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(65535) DEFAULT NULL,
+ ttl INTEGER DEFAULT NULL,
+ prio INTEGER DEFAULT NULL,
+ change_date INTEGER DEFAULT NULL,
+ ordername VARCHAR(255),
+ auth BOOL DEFAULT 1
+ );
+
+ INSERT INTO records_backup SELECT id,domain_id,name,type,content,ttl,prio,change_date,ordername,auth FROM records;
+ DROP TABLE records;
+
+ CREATE TABLE records (
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(65535) DEFAULT NULL,
+ ttl INTEGER DEFAULT NULL,
+ prio INTEGER DEFAULT NULL,
+ change_date INTEGER DEFAULT NULL,
+ disabled BOOLEAN DEFAULT 0,
+ ordername VARCHAR(255),
+ auth BOOL DEFAULT 1
+ );
+
+ CREATE INDEX rec_name_index ON records(name);
+ CREATE INDEX nametype_index ON records(name,type);
+ CREATE INDEX domain_id ON records(domain_id);
+ CREATE INDEX orderindex ON records(ordername);
+
+ INSERT INTO records SELECT id,domain_id,name,type,content,ttl,prio,change_date,0,ordername,auth FROM records_backup;
+ DROP TABLE records_backup;
+COMMIT;
+
+
+BEGIN TRANSACTION;
+ CREATE TEMPORARY TABLE supermasters_backup (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL COLLATE NOCASE,
+ account VARCHAR(40) DEFAULT NULL
+ );
+
+ INSERT INTO supermasters_backup SELECT ip,nameserver,account FROM supermasters;
+ UPDATE supermasters_backup SET account='' WHERE account IS NULL;
+ DROP TABLE supermasters;
+
+ CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL COLLATE NOCASE,
+ account VARCHAR(40) NOT NULL
+ );
+ CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);
+
+ INSERT INTO supermasters SELECT ip,nameserver,account FROM supermasters_backup;
+ DROP TABLE supermasters_backup;
+COMMIT;
+
+
+BEGIN TRANSACTION;
+ CREATE TABLE domainmetadata_backup (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32) COLLATE NOCASE,
+ content TEXT
+ );
+
+ INSERT INTO domainmetadata_backup SELECT id,domain_id,kind,content FROM domainmetadata;
+ DROP TABLE domainmetadata;
+
+ CREATE TABLE domainmetadata (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32) COLLATE NOCASE,
+ content TEXT
+ );
+ CREATE INDEX domainmetaidindex ON domainmetadata(domain_id);
+
+ INSERT INTO domainmetadata SELECT id,domain_id,kind,content FROM domainmetadata_backup;
+ DROP TABLE domainmetadata_backup;
+COMMIT;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/utility.hh"
+#include <map>
+#include <unistd.h>
+#include <sstream>
+#include <string>
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/ssqlite3.hh"
+#include "gsqlite3backend.hh"
+#include <boost/algorithm/string.hpp>
+
+// Connects to the database.
+gSQLite3Backend::gSQLite3Backend( const std::string & mode, const std::string & suffix ) : GSQLBackend( mode, suffix )
+{
+ try
+ {
+ SSQLite3 *ptr = new SSQLite3( getArg( "database" ));
+ setDB(ptr);
+ if(!getArg("pragma-synchronous").empty()) {
+ ptr->execute("PRAGMA synchronous="+getArg("pragma-synchronous"));
+ }
+ if (mustDo("pragma-foreign-keys")) {
+ ptr->execute("PRAGMA foreign_keys = 1");
+ }
+ }
+ catch( SSqlException & e )
+ {
+ L << Logger::Error << mode << ": connection failed: " << e.txtReason() << std::endl;
+ throw PDNSException( "Unable to launch " + mode + " connection: " + e.txtReason());
+ }
+
+ L << Logger::Info << mode << ": connection to '"<<getArg("database")<<"' successful" << std::endl;
+}
+
+
+//! Constructs a gSQLite3Backend
+class gSQLite3Factory : public BackendFactory
+{
+public:
+ //! Constructor.
+ gSQLite3Factory( const std::string & mode ) : BackendFactory( mode ), d_mode( mode )
+ {
+ }
+
+ //! Declares all needed arguments.
+ void declareArguments( const std::string & suffix = "" )
+ {
+ declare(suffix, "database", "Filename of the SQLite3 database", "powerdns.sqlite");
+ declare(suffix, "pragma-synchronous", "Set this to 0 for blazing speed", "");
+ declare(suffix, "pragma-foreign-keys", "Enable foreign key constraints", "no" );
+
+ declare(suffix, "dnssec", "Enable DNSSEC processing","no");
+
+ string record_query = "SELECT content,ttl,prio,type,domain_id,disabled,name,auth FROM records WHERE";
+
+ declare(suffix, "basic-query", "Basic query", record_query+" disabled=0 and type=:qtype and name=:qname");
+ declare(suffix, "id-query", "Basic with ID query", record_query+" disabled=0 and type=:qtype and name=:qname and domain_id=:domain_id");
+ declare(suffix, "any-query", "Any query", record_query+" disabled=0 and name=:qname");
+ declare(suffix, "any-id-query", "Any with ID query", record_query+" disabled=0 and name=:qname and domain_id=:domain_id");
+
+ declare(suffix, "list-query", "AXFR query", record_query+" (disabled=0 OR :include_disabled) and domain_id=:domain_id order by name, type");
+ declare(suffix, "list-subzone-query", "Subzone listing", record_query+" disabled=0 and (name=:zone OR name like :wildzone) and domain_id=:domain_id");
+
+ declare(suffix, "remove-empty-non-terminals-from-zone-query", "remove all empty non-terminals from zone", "delete from records where domain_id=:domain_id and type is null");
+ declare(suffix, "delete-empty-non-terminal-query", "delete empty non-terminal from zone", "delete from records where domain_id=:domain_id and name=:qname and type is null");
+
+ declare(suffix, "master-zone-query", "Data", "select master from domains where name=:domain and type='SLAVE'");
+
+ declare(suffix, "info-zone-query", "","select id,name,master,last_check,notified_serial,type,account from domains where name=:domain");
+
+ declare(suffix, "info-all-slaves-query", "","select id,name,master,last_check from domains where type='SLAVE'");
+ declare(suffix, "supermaster-query", "", "select account from supermasters where ip=:ip and nameserver=:nameserver");
+ declare(suffix, "supermaster-name-to-ips", "", "select ip,account from supermasters where nameserver=:nameserver and account=:account");
+
+ declare(suffix, "insert-zone-query", "", "insert into domains (type,name,master,account,last_check,notified_serial) values(:type, :domain, :masters, :account, null, null)");
+
+ declare(suffix, "insert-record-query", "", "insert into records (content,ttl,prio,type,domain_id,disabled,name,ordername,auth,change_date) values (:content,:ttl,:priority,:qtype,:domain_id,:disabled,:qname,:ordername,:auth,null)");
+ declare(suffix, "insert-empty-non-terminal-order-query", "insert empty non-terminal in zone", "insert into records (type,domain_id,disabled,name,ordername,auth,ttl,prio,change_date,content) values (null,:domain_id,0,:qname,:ordername,:auth,null,null,null,null)");
+
+ declare(suffix, "get-order-first-query", "DNSSEC Ordering Query, first", "select ordername from records where disabled=0 and domain_id=:domain_id and ordername is not null order by 1 asc limit 1");
+ declare(suffix, "get-order-before-query", "DNSSEC Ordering Query, before", "select ordername, name from records where disabled=0 and ordername <= :ordername and domain_id=:domain_id and ordername is not null order by 1 desc limit 1");
+ declare(suffix, "get-order-after-query", "DNSSEC Ordering Query, after", "select min(ordername) from records where disabled=0 and ordername > :ordername and domain_id=:domain_id and ordername is not null");
+ declare(suffix, "get-order-last-query", "DNSSEC Ordering Query, last", "select ordername, name from records where disabled=0 and ordername != '' and domain_id=:domain_id and ordername is not null order by 1 desc limit 1");
+
+ declare(suffix, "update-ordername-and-auth-query", "DNSSEC update ordername and auth for a qname query", "update records set ordername=:ordername,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0");
+ declare(suffix, "update-ordername-and-auth-type-query", "DNSSEC update ordername and auth for a rrset query", "update records set ordername=:ordername,auth=:auth where domain_id=:domain_id and name=:qname and type=:qtype and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-query", "DNSSEC nullify ordername and update auth for a qname query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and disabled=0");
+ declare(suffix, "nullify-ordername-and-update-auth-type-query", "DNSSEC nullify ordername and update auth for a rrset query", "update records set ordername=NULL,auth=:auth where domain_id=:domain_id and name=:qname and type=:qtype and disabled=0");
+
+ declare(suffix, "update-master-query", "", "update domains set master=:master where name=:domain");
+ declare(suffix, "update-kind-query", "", "update domains set type=:kind where name=:domain");
+ declare(suffix, "update-account-query","", "update domains set account=:account where name=:domain");
+ declare(suffix, "update-serial-query", "", "update domains set notified_serial=:serial where id=:domain_id");
+ declare(suffix, "update-lastcheck-query", "", "update domains set last_check=:last_check where id=:domain_id");
+ declare(suffix, "zone-lastchange-query", "", "select max(change_date) from records where domain_id=:domain_id");
+ declare(suffix, "info-all-master-query", "", "select id,name,master,last_check,notified_serial,type from domains where type='MASTER'");
+ declare(suffix, "delete-domain-query","", "delete from domains where name=:domain");
+ declare(suffix, "delete-zone-query", "", "delete from records where domain_id=:domain_id");
+ declare(suffix, "delete-rrset-query", "", "delete from records where domain_id=:domain_id and name=:qname and type=:qtype");
+ declare(suffix, "delete-names-query", "", "delete from records where domain_id=:domain_id and name=:qname");
+
+ declare(suffix, "add-domain-key-query","", "insert into cryptokeys (domain_id, flags, active, content) select id, :flags,:active, :content from domains where name=:domain");
+ declare(suffix, "list-domain-keys-query","", "select cryptokeys.id, flags, active, content from domains, cryptokeys where cryptokeys.domain_id=domains.id and name=:domain");
+ declare(suffix, "get-all-domain-metadata-query","", "select kind,content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain");
+ declare(suffix, "get-domain-metadata-query","", "select content from domains, domainmetadata where domainmetadata.domain_id=domains.id and name=:domain and domainmetadata.kind=:kind");
+ declare(suffix, "clear-domain-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain) and domainmetadata.kind=:kind");
+ declare(suffix, "clear-domain-all-metadata-query","", "delete from domainmetadata where domain_id=(select id from domains where name=:domain)");
+ declare(suffix, "set-domain-metadata-query","", "insert into domainmetadata (domain_id, kind, content) select id, :kind, :content from domains where name=:domain");
+ declare(suffix, "activate-domain-key-query","", "update cryptokeys set active=1 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "deactivate-domain-key-query","", "update cryptokeys set active=0 where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "remove-domain-key-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain) and cryptokeys.id=:key_id");
+ declare(suffix, "clear-domain-all-keys-query","", "delete from cryptokeys where domain_id=(select id from domains where name=:domain)");
+ declare(suffix, "get-tsig-key-query","", "select algorithm, secret from tsigkeys where name=:key_name");
+ declare(suffix, "set-tsig-key-query","", "replace into tsigkeys (name,algorithm,secret) values(:key_name,:algorithm,:content)");
+ declare(suffix, "delete-tsig-key-query","", "delete from tsigkeys where name=:key_name");
+ declare(suffix, "get-tsig-keys-query","", "select name,algorithm, secret from tsigkeys");
+
+ declare(suffix, "get-all-domains-query", "Retrieve all domains", "select domains.id, domains.name, records.content, domains.type, domains.master, domains.notified_serial, domains.last_check, domains.account from domains LEFT JOIN records ON records.domain_id=domains.id AND records.type='SOA' AND records.name=domains.name WHERE records.disabled=0 OR :include_disabled");
+
+ declare(suffix, "list-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE domain_id=:domain_id");
+ declare(suffix, "insert-comment-query", "", "INSERT INTO comments (domain_id, name, type, modified_at, account, comment) VALUES (:domain_id, :qname, :qtype, :modified_at, :account, :content)");
+ declare(suffix, "delete-comment-rrset-query", "", "DELETE FROM comments WHERE domain_id=:domain_id AND name=:qname AND type=:qtype");
+ declare(suffix, "delete-comments-query", "", "DELETE FROM comments WHERE domain_id=:domain_id");
+ declare(suffix, "search-records-query", "", record_query+" name LIKE :value OR content LIKE :value2 LIMIT :limit");
+ declare(suffix, "search-comments-query", "", "SELECT domain_id,name,type,modified_at,account,comment FROM comments WHERE name LIKE :value OR comment LIKE :value2 LIMIT :limit");
+ }
+
+ //! Constructs a new gSQLite3Backend object.
+ DNSBackend *make( const string & suffix = "" )
+ {
+ return new gSQLite3Backend( d_mode, suffix );
+ }
+
+private:
+ const string d_mode;
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class gSQLite3Loader
+{
+public:
+ //! This reports us to the main UeberBackend class
+ gSQLite3Loader()
+ {
+ BackendMakers().report( new gSQLite3Factory( "gsqlite3" ));
+ L << Logger::Info << "[gsqlite3] This is the gsqlite3 backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+//! Reports the backendloader to the UeberBackend.
+static gSQLite3Loader gsqlite3loader;
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef GSQLITEBACKEND_HH
+#define GSQLITEBACKEND_HH
+
+#include <string>
+#include "pdns/backends/gsql/gsqlbackend.hh"
+
+//! The gSQLiteBackend retrieves it's data from a SQLite database (http://www.sqlite.org/)
+class gSQLite3Backend : public GSQLBackend
+{
+public:
+ //! Constructs the backend, throws an exception if it failed..
+ gSQLite3Backend( const std::string & mode, const std::string & suffix );
+};
+
+#endif // GSQLITEBACKEND_HH
--- /dev/null
+ALTER TABLE records ADD disabled BOOL DEFAULT 0;
+ALTER TABLE records ADD ordername VARCHAR(255);
+ALTER TABLE records ADD auth BOOL DEFAULT 1;
+
+CREATE INDEX orderindex ON records(ordername);
+
+
+CREATE TABLE domainmetadata (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32) COLLATE NOCASE,
+ content TEXT
+);
+
+CREATE INDEX domainmetaidindex on domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(255) COLLATE NOCASE,
+ algorithm VARCHAR(50) COLLATE NOCASE,
+ secret VARCHAR(255)
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
+
+
+CREATE TABLE comments (
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL
+);
+
+CREATE INDEX comments_domain_id_index ON comments (domain_id);
+CREATE INDEX comments_nametype_index ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+BEGIN TRANSACTION;
+ CREATE TEMPORARY TABLE supermasters_backup (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL COLLATE NOCASE,
+ account VARCHAR(40) DEFAULT NULL
+ );
+
+ INSERT INTO supermasters_backup SELECT ip, nameserver, account FROM supermasters;
+ UPDATE supermasters_backup SET account='' WHERE account IS NULL;
+ DROP TABLE supermasters;
+
+ CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL COLLATE NOCASE,
+ account VARCHAR(40) NOT NULL
+ );
+ CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);
+
+ INSERT INTO supermasters SELECT ip, nameserver, account FROM supermasters_backup;
+ DROP TABLE supermasters_backup;
+COMMIT;
--- /dev/null
+PRAGMA foreign_keys = 1;
+
+CREATE TABLE domains (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(255) NOT NULL COLLATE NOCASE,
+ master VARCHAR(128) DEFAULT NULL,
+ last_check INTEGER DEFAULT NULL,
+ type VARCHAR(6) NOT NULL,
+ notified_serial INTEGER DEFAULT NULL,
+ account VARCHAR(40) DEFAULT NULL
+);
+
+CREATE UNIQUE INDEX name_index ON domains(name);
+
+
+CREATE TABLE records (
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER DEFAULT NULL,
+ name VARCHAR(255) DEFAULT NULL,
+ type VARCHAR(10) DEFAULT NULL,
+ content VARCHAR(65535) DEFAULT NULL,
+ ttl INTEGER DEFAULT NULL,
+ prio INTEGER DEFAULT NULL,
+ change_date INTEGER DEFAULT NULL,
+ disabled BOOLEAN DEFAULT 0,
+ ordername VARCHAR(255),
+ auth BOOL DEFAULT 1,
+ FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE INDEX rec_name_index ON records(name);
+CREATE INDEX nametype_index ON records(name,type);
+CREATE INDEX domain_id ON records(domain_id);
+CREATE INDEX orderindex ON records(ordername);
+
+
+CREATE TABLE supermasters (
+ ip VARCHAR(64) NOT NULL,
+ nameserver VARCHAR(255) NOT NULL COLLATE NOCASE,
+ account VARCHAR(40) NOT NULL
+);
+
+CREATE UNIQUE INDEX ip_nameserver_pk ON supermasters(ip, nameserver);
+
+
+CREATE TABLE comments (
+ id INTEGER PRIMARY KEY,
+ domain_id INTEGER NOT NULL,
+ name VARCHAR(255) NOT NULL,
+ type VARCHAR(10) NOT NULL,
+ modified_at INT NOT NULL,
+ account VARCHAR(40) DEFAULT NULL,
+ comment VARCHAR(65535) NOT NULL,
+ FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE INDEX comments_domain_id_index ON comments (domain_id);
+CREATE INDEX comments_nametype_index ON comments (name, type);
+CREATE INDEX comments_order_idx ON comments (domain_id, modified_at);
+
+
+CREATE TABLE domainmetadata (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ kind VARCHAR(32) COLLATE NOCASE,
+ content TEXT,
+ FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE INDEX domainmetaidindex ON domainmetadata(domain_id);
+
+
+CREATE TABLE cryptokeys (
+ id INTEGER PRIMARY KEY,
+ domain_id INT NOT NULL,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT,
+ FOREIGN KEY(domain_id) REFERENCES domains(id) ON DELETE CASCADE ON UPDATE CASCADE
+);
+
+CREATE INDEX domainidindex ON cryptokeys(domain_id);
+
+
+CREATE TABLE tsigkeys (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(255) COLLATE NOCASE,
+ algorithm VARCHAR(50) COLLATE NOCASE,
+ secret VARCHAR(255)
+);
+
+CREATE UNIQUE INDEX namealgoindex ON tsigkeys(name, algorithm);
--- /dev/null
+pkglib_LTLIBRARIES = libldapbackend.la
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+libldapbackend_la_SOURCES = \
+ ldapbackend.cc ldapbackend.hh \
+ powerldap.cc powerldap.hh \
+ utils.hh
+
+libldapbackend_la_LDFLAGS = -module -avoid-version
+libldapbackend_la_LIBADD = $(LDAP_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/ldapbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libldapbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libldapbackend_la_OBJECTS = ldapbackend.lo powerldap.lo
+libldapbackend_la_OBJECTS = $(am_libldapbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libldapbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libldapbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libldapbackend_la_SOURCES)
+DIST_SOURCES = $(libldapbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libldapbackend.la
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+libldapbackend_la_SOURCES = \
+ ldapbackend.cc ldapbackend.hh \
+ powerldap.cc powerldap.hh \
+ utils.hh
+
+libldapbackend_la_LDFLAGS = -module -avoid-version
+libldapbackend_la_LIBADD = $(LDAP_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/ldapbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/ldapbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libldapbackend.la: $(libldapbackend_la_OBJECTS) $(libldapbackend_la_DEPENDENCIES) $(EXTRA_libldapbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libldapbackend_la_LINK) -rpath $(pkglibdir) $(libldapbackend_la_OBJECTS) $(libldapbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ldapbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/powerldap.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+ldapbackend.lo powerldap.lo
--- /dev/null
+$(LDAP_LIBS)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ldapbackend.hh"
+
+unsigned int ldap_host_index = 0;
+
+LdapBackend::LdapBackend( const string &suffix )
+{
+ string hoststr;
+ unsigned int i, idx;
+ vector<string> hosts;
+
+
+ try
+ {
+ m_msgid = 0;
+ m_qname.clear();
+ m_pldap = NULL;
+ m_ttl = 0;
+ m_axfrqlen = 0;
+ m_last_modified = 0;
+ m_qlog = arg().mustDo( "query-logging" );
+ m_default_ttl = arg().asNum( "default-ttl" );
+ m_myname = "[LdapBackend]";
+
+ setArgPrefix( "ldap" + suffix );
+
+ m_getdn = false;
+ m_list_fcnt = &LdapBackend::list_simple;
+ m_lookup_fcnt = &LdapBackend::lookup_simple;
+ m_prepare_fcnt = &LdapBackend::prepare_simple;
+
+ if( getArg( "method" ) == "tree" )
+ {
+ m_lookup_fcnt = &LdapBackend::lookup_tree;
+ }
+
+ if( getArg( "method" ) == "strict" || mustDo( "disable-ptrrecord" ) )
+ {
+ m_list_fcnt = &LdapBackend::list_strict;
+ m_lookup_fcnt = &LdapBackend::lookup_strict;
+ m_prepare_fcnt = &LdapBackend::prepare_strict;
+ }
+
+ stringtok( hosts, getArg( "host" ), ", " );
+ idx = ldap_host_index++ % hosts.size();
+ hoststr = hosts[idx];
+
+ for( i = 1; i < hosts.size(); i++ )
+ {
+ hoststr += " " + hosts[ ( idx + i ) % hosts.size() ];
+ }
+
+ L << Logger::Info << m_myname << " LDAP servers = " << hoststr << endl;
+
+ m_pldap = new PowerLDAP( hoststr.c_str(), LDAP_PORT, mustDo( "starttls" ) );
+ m_pldap->setOption( LDAP_OPT_DEREF, LDAP_DEREF_ALWAYS );
+ m_pldap->bind( getArg( "binddn" ), getArg( "secret" ), LDAP_AUTH_SIMPLE, getArgAsNum( "timeout" ) );
+
+ L << Logger::Notice << m_myname << " Ldap connection succeeded" << endl;
+ return;
+ }
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Error << m_myname << " Ldap connection to server failed because of timeout" << endl;
+ }
+ catch( LDAPException &le )
+ {
+ L << Logger::Error << m_myname << " Ldap connection to server failed: " << le.what() << endl;
+ }
+ catch( std::exception &e )
+ {
+ L << Logger::Error << m_myname << " Caught STL exception: " << e.what() << endl;
+ }
+
+ if( m_pldap != NULL ) { delete( m_pldap ); }
+ throw( PDNSException( "Unable to connect to ldap server" ) );
+}
+
+
+
+LdapBackend::~LdapBackend()
+{
+ if( m_pldap != NULL ) { delete( m_pldap ); }
+ try {
+ L << Logger::Notice << m_myname << " Ldap connection closed" << endl;
+ }
+ catch (...) {
+ }
+}
+
+
+
+bool LdapBackend::list( const DNSName& target, int domain_id, bool include_disabled )
+{
+ try
+ {
+ m_qname = target;
+ m_axfrqlen = target.toStringRootDot().length();
+ m_adomain = m_adomains.end(); // skip loops in get() first time
+
+ return (this->*m_list_fcnt)( target, domain_id );
+ }
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Warning << m_myname << " Unable to get zone " << target << " from LDAP directory: " << lt.what() << endl;
+ throw( DBException( "LDAP server timeout" ) );
+ }
+ catch( LDAPException &le )
+ {
+ L << Logger::Error << m_myname << " Unable to get zone " << target << " from LDAP directory: " << le.what() << endl;
+ throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
+ }
+ catch( std::exception &e )
+ {
+ L << Logger::Error << m_myname << " Caught STL exception for target " << target << ": " << e.what() << endl;
+ throw( DBException( "STL exception" ) );
+ }
+
+ return false;
+}
+
+
+
+inline bool LdapBackend::list_simple( const DNSName& target, int domain_id )
+{
+ string dn;
+ string filter;
+ string qesc;
+
+
+ dn = getArg( "basedn" );
+ qesc = toLower( m_pldap->escape( target.toStringRootDot() ) );
+
+ // search for SOARecord of target
+ filter = strbind( ":target:", "&(associatedDomain=" + qesc + ")(sOARecord=*)", getArg( "filter-axfr" ) );
+ m_msgid = m_pldap->search( dn, LDAP_SCOPE_SUBTREE, filter, (const char**) ldap_attrany );
+ m_pldap->getSearchEntry( m_msgid, m_result, true );
+
+ if( m_result.count( "dn" ) && !m_result["dn"].empty() )
+ {
+ if( !mustDo( "basedn-axfr-override" ) )
+ {
+ dn = m_result["dn"][0];
+ }
+ m_result.erase( "dn" );
+ }
+
+ prepare();
+ filter = strbind( ":target:", "associatedDomain=*." + qesc, getArg( "filter-axfr" ) );
+ DLOG( L << Logger::Debug << m_myname << " Search = basedn: " << dn << ", filter: " << filter << endl );
+ m_msgid = m_pldap->search( dn, LDAP_SCOPE_SUBTREE, filter, (const char**) ldap_attrany );
+
+ return true;
+}
+
+
+
+inline bool LdapBackend::list_strict( const DNSName& target, int domain_id )
+{
+ if( target.isPartOf(DNSName("in-addr.arpa")) || target.isPartOf(DNSName("ip6.arpa")) )
+ {
+ L << Logger::Warning << m_myname << " Request for reverse zone AXFR, but this is not supported in strict mode" << endl;
+ return false; // AXFR isn't supported in strict mode. Use simple mode and additional PTR records
+ }
+
+ return list_simple( target, domain_id );
+}
+
+
+
+void LdapBackend::lookup( const QType &qtype, const DNSName &qname, DNSPacket *dnspkt, int zoneid )
+{
+ try
+ {
+ m_axfrqlen = 0;
+ m_qname = qname;
+ m_adomain = m_adomains.end(); // skip loops in get() first time
+
+ if( m_qlog ) { L.log( "Query: '" + qname.toStringRootDot() + "|" + qtype.getName() + "'", Logger::Error ); }
+ (this->*m_lookup_fcnt)( qtype, qname, dnspkt, zoneid );
+ }
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Warning << m_myname << " Unable to search LDAP directory: " << lt.what() << endl;
+ throw( DBException( "LDAP server timeout" ) );
+ }
+ catch( LDAPException &le )
+ {
+ L << Logger::Error << m_myname << " Unable to search LDAP directory: " << le.what() << endl;
+ throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
+ }
+ catch( std::exception &e )
+ {
+ L << Logger::Error << m_myname << " Caught STL exception for qname " << qname << ": " << e.what() << endl;
+ throw( DBException( "STL exception" ) );
+ }
+}
+
+
+
+void LdapBackend::lookup_simple( const QType &qtype, const DNSName &qname, DNSPacket *dnspkt, int zoneid )
+{
+ string filter, attr, qesc;
+ const char** attributes = ldap_attrany + 1; // skip associatedDomain
+ const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
+
+
+ qesc = toLower( m_pldap->escape( qname.toStringRootDot() ) );
+ filter = "associatedDomain=" + qesc;
+
+ if( qtype.getCode() != QType::ANY )
+ {
+ attr = qtype.getName() + "Record";
+ filter = "&(" + filter + ")(" + attr + "=*)";
+ attronly[0] = attr.c_str();
+ attributes = attronly;
+ }
+
+ filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
+
+ DLOG( L << Logger::Debug << m_myname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl );
+ m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attributes );
+}
+
+
+
+void LdapBackend::lookup_strict( const QType &qtype, const DNSName &qname, DNSPacket *dnspkt, int zoneid )
+{
+ int len;
+ vector<string> parts;
+ string filter, attr, qesc;
+ const char** attributes = ldap_attrany + 1; // skip associatedDomain
+ const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
+
+
+ qesc = toLower( m_pldap->escape( qname.toStringRootDot() ) );
+ stringtok( parts, qesc, "." );
+ len = qesc.length();
+
+ if( parts.size() == 6 && len > 13 && qesc.substr( len - 13, 13 ) == ".in-addr.arpa" ) // IPv4 reverse lookups
+ {
+ filter = "aRecord=" + ptr2ip4( parts );
+ attronly[0] = "associatedDomain";
+ attributes = attronly;
+ }
+ else if( parts.size() == 34 && len > 9 && ( qesc.substr( len - 9, 9 ) == ".ip6.arpa" ) ) // IPv6 reverse lookups
+ {
+ filter = "aAAARecord=" + ptr2ip6( parts );
+ attronly[0] = "associatedDomain";
+ attributes = attronly;
+ }
+ else // IPv4 and IPv6 lookups
+ {
+ filter = "associatedDomain=" + qesc;
+ if( qtype.getCode() != QType::ANY )
+ {
+ attr = qtype.getName() + "Record";
+ filter = "&(" + filter + ")(" + attr + "=*)";
+ attronly[0] = attr.c_str();
+ attributes = attronly;
+ }
+ }
+
+ filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
+
+ DLOG( L << Logger::Debug << m_myname << " Search = basedn: " << getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl );
+ m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attributes );
+}
+
+
+
+void LdapBackend::lookup_tree( const QType &qtype, const DNSName &qname, DNSPacket *dnspkt, int zoneid )
+{
+ string filter, attr, qesc, dn;
+ const char** attributes = ldap_attrany + 1; // skip associatedDomain
+ const char* attronly[] = { NULL, "dNSTTL", "modifyTimestamp", NULL };
+ vector<string> parts;
+
+
+ qesc = toLower( m_pldap->escape( qname.toStringRootDot() ) );
+ filter = "associatedDomain=" + qesc;
+
+ if( qtype.getCode() != QType::ANY )
+ {
+ attr = qtype.getName() + "Record";
+ filter = "&(" + filter + ")(" + attr + "=*)";
+ attronly[0] = attr.c_str();
+ attributes = attronly;
+ }
+
+ filter = strbind( ":target:", filter, getArg( "filter-lookup" ) );
+
+ stringtok( parts, toLower( qname.toString() ), "." );
+ for(auto i = parts.crbegin(); i != parts.crend(); i++ )
+ {
+ dn = "dc=" + *i + "," + dn;
+ }
+
+ DLOG( L << Logger::Debug << m_myname << " Search = basedn: " << dn + getArg( "basedn" ) << ", filter: " << filter << ", qtype: " << qtype.getName() << endl );
+ m_msgid = m_pldap->search( dn + getArg( "basedn" ), LDAP_SCOPE_BASE, filter, attributes );
+}
+
+
+inline bool LdapBackend::prepare()
+{
+ m_adomains.clear();
+ m_ttl = m_default_ttl;
+ m_last_modified = 0;
+
+ if( m_result.count( "dNSTTL" ) && !m_result["dNSTTL"].empty() )
+ {
+ char* endptr;
+
+ m_ttl = (uint32_t) strtol( m_result["dNSTTL"][0].c_str(), &endptr, 10 );
+ if( *endptr != '\0' )
+ {
+ L << Logger::Warning << m_myname << " Invalid time to live for " << m_qname << ": " << m_result["dNSTTL"][0] << endl;
+ m_ttl = m_default_ttl;
+ }
+ m_result.erase( "dNSTTL" );
+ }
+
+ if( m_result.count( "modifyTimestamp" ) && !m_result["modifyTimestamp"].empty() )
+ {
+ if( ( m_last_modified = str2tstamp( m_result["modifyTimestamp"][0] ) ) == 0 )
+ {
+ L << Logger::Warning << m_myname << " Invalid modifyTimestamp for " << m_qname << ": " << m_result["modifyTimestamp"][0] << endl;
+ }
+ m_result.erase( "modifyTimestamp" );
+ }
+
+ if( !(this->*m_prepare_fcnt)() )
+ {
+ return false;
+ }
+
+ m_adomain = m_adomains.begin();
+ m_attribute = m_result.begin();
+ m_value = m_attribute->second.begin();
+
+ return true;
+}
+
+
+
+inline bool LdapBackend::prepare_simple()
+{
+ if( !m_axfrqlen ) // request was a normal lookup()
+ {
+ m_adomains.push_back( m_qname );
+ }
+ else // request was a list() for AXFR
+ {
+ if( m_result.count( "associatedDomain" ) )
+ {
+ for(auto i = m_result["associatedDomain"].begin(); i != m_result["associatedDomain"].end(); i++ ) {
+ if( i->size() >= m_axfrqlen && i->substr( i->size() - m_axfrqlen, m_axfrqlen ) == m_qname.toStringRootDot() /* ugh */ ) {
+ m_adomains.push_back( DNSName(*i) );
+ }
+ }
+ m_result.erase( "associatedDomain" );
+ }
+ }
+
+ return true;
+}
+
+
+
+inline bool LdapBackend::prepare_strict()
+{
+ if( !m_axfrqlen ) // request was a normal lookup()
+ {
+ m_adomains.push_back( m_qname );
+ if( m_result.count( "associatedDomain" ) )
+ {
+ m_result["PTRRecord"] = m_result["associatedDomain"];
+ m_result.erase( "associatedDomain" );
+ }
+ }
+ else // request was a list() for AXFR
+ {
+ if( m_result.count( "associatedDomain" ) )
+ {
+ for(auto i = m_result["associatedDomain"].begin(); i != m_result["associatedDomain"].end(); i++ ) {
+ if( i->size() >= m_axfrqlen && i->substr( i->size() - m_axfrqlen, m_axfrqlen ) == m_qname.toStringRootDot() /* ugh */ ) {
+ m_adomains.push_back( DNSName(*i) );
+ }
+ }
+ m_result.erase( "associatedDomain" );
+ }
+ }
+
+ return true;
+}
+
+
+
+bool LdapBackend::get( DNSResourceRecord &rr )
+{
+ QType qt;
+ vector<string> parts;
+ string attrname, qstr;
+
+
+ try
+ {
+ do
+ {
+ while( m_adomain != m_adomains.end() )
+ {
+ while( m_attribute != m_result.end() )
+ {
+ attrname = m_attribute->first;
+ qstr = attrname.substr( 0, attrname.length() - 6 ); // extract qtype string from ldap attribute name
+ qt = const_cast<char*>(toUpper( qstr ).c_str());
+
+ while( m_value != m_attribute->second.end() )
+ {
+
+ rr.qtype = qt;
+ rr.qname = *m_adomain;
+ rr.ttl = m_ttl;
+ rr.last_modified = m_last_modified;
+ rr.content = *m_value;
+ m_value++;
+
+ DLOG( L << Logger::Debug << m_myname << " Record = qname: " << rr.qname << ", qtype: " << (rr.qtype).getName() << ", ttl: " << rr.ttl << ", content: " << rr.content << endl );
+ return true;
+ }
+
+ m_attribute++;
+ m_value = m_attribute->second.begin();
+ }
+ m_adomain++;
+ m_attribute = m_result.begin();
+ m_value = m_attribute->second.begin();
+ }
+ }
+ while( m_pldap->getSearchEntry( m_msgid, m_result, m_getdn ) && prepare() );
+
+ }
+ catch( LDAPTimeout < )
+ {
+ L << Logger::Warning << m_myname << " Search failed: " << lt.what() << endl;
+ throw( DBException( "LDAP server timeout" ) );
+ }
+ catch( LDAPException &le )
+ {
+ L << Logger::Error << m_myname << " Search failed: " << le.what() << endl;
+ throw( PDNSException( "LDAP server unreachable" ) ); // try to reconnect to another server
+ }
+ catch( std::exception &e )
+ {
+ L << Logger::Error << m_myname << " Caught STL exception for " << m_qname << ": " << e.what() << endl;
+ throw( DBException( "STL exception" ) );
+ }
+
+ return false;
+}
+
+
+
+ bool LdapBackend::getDomainInfo( const string& domain, DomainInfo& di )
+{
+ string filter;
+ SOAData sd;
+ const char* attronly[] = { "sOARecord", NULL };
+
+
+ // search for SOARecord of domain
+ filter = "(&(associatedDomain=" + toLower( m_pldap->escape( domain ) ) + ")(SOARecord=*))";
+ m_msgid = m_pldap->search( getArg( "basedn" ), LDAP_SCOPE_SUBTREE, filter, attronly );
+ m_pldap->getSearchEntry( m_msgid, m_result );
+
+ if( m_result.count( "sOARecord" ) && !m_result["sOARecord"].empty() )
+ {
+ sd.serial = 0;
+ fillSOAData( m_result["sOARecord"][0], sd );
+
+ di.id = 0;
+ di.serial = sd.serial;
+ di.zone = DNSName(domain);
+ di.last_check = 0;
+ di.backend = this;
+ di.kind = DomainInfo::Master;
+
+ return true;
+ }
+
+ return false;
+}
+
+
+
+
+
+class LdapFactory : public BackendFactory
+{
+
+public:
+
+ LdapFactory() : BackendFactory( "ldap" ) {}
+
+
+ void declareArguments( const string &suffix="" )
+ {
+ declare( suffix, "host", "One or more LDAP server with ports or LDAP URIs (separated by spaces)","ldap://127.0.0.1:389/" );
+ declare( suffix, "starttls", "Use TLS to encrypt connection (unused for LDAP URIs)", "no" );
+ declare( suffix, "basedn", "Search root in ldap tree (must be set)","" );
+ declare( suffix, "basedn-axfr-override", "Override base dn for AXFR subtree search", "no" );
+ declare( suffix, "binddn", "User dn for non anonymous binds","" );
+ declare( suffix, "secret", "User password for non anonymous binds", "" );
+ declare( suffix, "timeout", "Seconds before connecting to server fails", "5" );
+ declare( suffix, "method", "How to search entries (simple, strict or tree)", "simple" );
+ declare( suffix, "filter-axfr", "LDAP filter for limiting AXFR results", "(:target:)" );
+ declare( suffix, "filter-lookup", "LDAP filter for limiting IP or name lookups", "(:target:)" );
+ declare( suffix, "disable-ptrrecord", "Deprecated, use ldap-method=strict instead", "no" );
+ }
+
+
+ DNSBackend* make( const string &suffix="" )
+ {
+ return new LdapBackend( suffix );
+ }
+};
+
+
+
+
+
+class LdapLoader
+{
+ LdapFactory factory;
+
+public:
+
+ LdapLoader()
+ {
+ BackendMakers().report( &factory );
+ L << Logger::Info << "[ldapbackend] This is the ldap backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+
+static LdapLoader ldaploader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <algorithm>
+#include <sstream>
+#include <utility>
+#include <string>
+#include <cstdlib>
+#include <cctype>
+#include <inttypes.h>
+#include "pdns/dns.hh"
+#include "pdns/utility.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/arguments.hh"
+#include "pdns/logger.hh"
+#include "powerldap.hh"
+#include "utils.hh"
+
+
+
+#ifndef LDAPBACKEND_HH
+#define LDAPBACKEND_HH
+
+using std::string;
+using std::vector;
+
+
+
+/*
+ * Known DNS RR types
+ * Types which aren't active are currently not supported by PDNS
+ */
+
+static const char* ldap_attrany[] = {
+ "associatedDomain",
+ "dNSTTL",
+ "aRecord",
+ "nSRecord",
+ "cNAMERecord",
+ "sOARecord",
+ "pTRRecord",
+ "hInfoRecord",
+ "mXRecord",
+ "tXTRecord",
+ "rPRecord",
+ "aFSDBRecord",
+// "SigRecord",
+ "KeyRecord",
+// "gPosRecord",
+ "aAAARecord",
+ "lOCRecord",
+ "sRVRecord",
+ "nAPTRRecord",
+ "kXRecord",
+ "certRecord",
+// "a6Record",
+// "dNameRecord",
+// "aPLRecord",
+ "dSRecord",
+ "sSHFPRecord",
+ "iPSecKeyRecord",
+ "rRSIGRecord",
+ "nSECRecord",
+ "dNSKeyRecord",
+ "dHCIDRecord",
+ "sPFRecord",
+ "TYPE65534Record",
+ "EUI48Record",
+ "EUI64Record",
+ "TYPE65226Record",
+ "modifyTimestamp",
+ NULL
+};
+
+
+
+class LdapBackend : public DNSBackend
+{
+ bool m_getdn;
+ bool m_qlog;
+ int m_msgid;
+ uint32_t m_ttl;
+ uint32_t m_default_ttl;
+ unsigned int m_axfrqlen;
+ time_t m_last_modified;
+ string m_myname;
+ DNSName m_qname;
+ PowerLDAP* m_pldap;
+ PowerLDAP::sentry_t m_result;
+ PowerLDAP::sentry_t::iterator m_attribute;
+ vector<string>::iterator m_value;
+ vector<DNSName>::iterator m_adomain;
+ vector<DNSName> m_adomains;
+
+ bool (LdapBackend::*m_list_fcnt)( const DNSName&, int );
+ void (LdapBackend::*m_lookup_fcnt)( const QType&, const DNSName&, DNSPacket*, int );
+ bool (LdapBackend::*m_prepare_fcnt)();
+
+ bool list_simple( const DNSName& target, int domain_id );
+ bool list_strict( const DNSName& target, int domain_id );
+
+ void lookup_simple( const QType& qtype, const DNSName& qdomain, DNSPacket* p, int zoneid );
+ void lookup_strict( const QType& qtype, const DNSName& qdomain, DNSPacket* p, int zoneid );
+ void lookup_tree( const QType& qtype, const DNSName& qdomain, DNSPacket* p, int zoneid );
+
+ bool prepare();
+ bool prepare_simple();
+ bool prepare_strict();
+
+ bool getDomainInfo( const string& domain, DomainInfo& di );
+
+public:
+
+ LdapBackend( const string &suffix="" );
+ ~LdapBackend();
+
+ bool list( const DNSName& target, int domain_id, bool include_disabled=false );
+ void lookup( const QType& qtype, const DNSName& qdomain, DNSPacket* p = 0, int zoneid = -1 );
+ bool get( DNSResourceRecord& rr );
+};
+
+#endif /* LDAPBACKEND_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "powerldap.hh"
+#include "pdns/misc.hh"
+#include <sys/time.h>
+
+
+
+PowerLDAP::PowerLDAP( const string& hosts, uint16_t port, bool tls )
+{
+ d_ld = 0;
+ d_hosts = hosts;
+ d_port = port;
+ d_tls = tls;
+ ensureConnect();
+}
+
+void PowerLDAP::ensureConnect()
+{
+ int err;
+
+ if(d_ld) {
+ ldap_unbind_ext( d_ld, NULL, NULL );
+ }
+
+#ifdef HAVE_LDAP_INITIALIZE
+ if( ( err = ldap_initialize( &d_ld, d_hosts.c_str() ) ) != LDAP_SUCCESS )
+ {
+ string ldapuris;
+ vector<string> uris;
+ stringtok( uris, d_hosts );
+
+ for( size_t i = 0; i < uris.size(); i++ )
+ {
+ ldapuris += " ldap://" + uris[i];
+ }
+
+ if( ( err = ldap_initialize( &d_ld, ldapuris.c_str() ) ) != LDAP_SUCCESS )
+ {
+ throw LDAPException( "Error initializing LDAP connection to '" + ldapuris + ": " + getError( err ) );
+ }
+ }
+#else
+ if( ( d_ld = ldap_init( d_hosts.c_str(), d_port ) ) == NULL )
+ {
+ throw LDAPException( "Error initializing LDAP connection to '" + d_hosts + "': " + string( strerror( errno ) ) );
+ }
+#endif
+
+ int protocol = LDAP_VERSION3;
+ if( ldap_set_option( d_ld, LDAP_OPT_PROTOCOL_VERSION, &protocol ) != LDAP_OPT_SUCCESS )
+ {
+ protocol = LDAP_VERSION2;
+ if( ldap_set_option( d_ld, LDAP_OPT_PROTOCOL_VERSION, &protocol ) != LDAP_OPT_SUCCESS )
+ {
+ ldap_unbind_ext( d_ld, NULL, NULL );
+ throw LDAPException( "Couldn't set protocol version to LDAPv3 or LDAPv2" );
+ }
+ }
+
+ if( d_tls && ( err = ldap_start_tls_s( d_ld, NULL, NULL ) ) != LDAP_SUCCESS )
+ {
+ ldap_unbind_ext( d_ld, NULL, NULL );
+ throw LDAPException( "Couldn't perform STARTTLS: " + getError( err ) );
+ }
+}
+
+
+PowerLDAP::~PowerLDAP()
+{
+ ldap_unbind_ext( d_ld, NULL, NULL );
+}
+
+
+void PowerLDAP::setOption( int option, int value )
+{
+ if( ldap_set_option( d_ld, option, (void*) &value ) != LDAP_OPT_SUCCESS )
+ {
+ throw( LDAPException( "Unable to set option" ) );
+ }
+}
+
+
+void PowerLDAP::getOption( int option, int *value )
+{
+ if( ldap_get_option( d_ld, option, (void*) value ) != LDAP_OPT_SUCCESS )
+ {
+ throw( LDAPException( "Unable to get option" ) );
+ }
+}
+
+
+void PowerLDAP::bind( const string& ldapbinddn, const string& ldapsecret, int method, int timeout )
+{
+ int msgid;
+
+#ifdef HAVE_LDAP_SASL_BIND
+ int rc;
+ struct berval passwd;
+
+ passwd.bv_val = (char *)ldapsecret.c_str();
+ passwd.bv_len = strlen( passwd.bv_val );
+
+ if( ( rc = ldap_sasl_bind( d_ld, ldapbinddn.c_str(), LDAP_SASL_SIMPLE, &passwd, NULL, NULL, &msgid ) ) != LDAP_SUCCESS )
+ {
+ throw LDAPException( "Failed to bind to LDAP server: " + getError( rc ) );
+ }
+#else
+ if( ( msgid = ldap_bind( d_ld, ldapbinddn.c_str(), ldapsecret.c_str(), method ) ) == -1 )
+ {
+ throw LDAPException( "Failed to bind to LDAP server: " + getError( msgid ) );
+ }
+#endif
+
+ waitResult( msgid, timeout, NULL );
+}
+
+
+/**
+ * Deprecated, use PowerLDAP::bind() instead
+ */
+
+void PowerLDAP::simpleBind( const string& ldapbinddn, const string& ldapsecret )
+{
+ this->bind( ldapbinddn, ldapsecret, LDAP_AUTH_SIMPLE, 30 );
+}
+
+
+int PowerLDAP::search( const string& base, int scope, const string& filter, const char** attr )
+{
+ int msgid, rc;
+
+ if( ( rc = ldap_search_ext( d_ld, base.c_str(), scope, filter.c_str(), const_cast<char**> (attr), 0, NULL, NULL, NULL, LDAP_NO_LIMIT, &msgid ) ) != LDAP_SUCCESS )
+ {
+ throw LDAPException( "Starting LDAP search: " + getError( rc ) );
+ }
+
+ return msgid;
+}
+
+
+/**
+ * Function waits for a result, returns its type and optionally stores the result.
+ * If the result is returned, the caller is responsible for freeing it with
+ * ldap_msgfree!
+ */
+
+int PowerLDAP::waitResult( int msgid, int timeout, LDAPMessage** result )
+{
+ struct timeval tv;
+ LDAPMessage* res;
+
+ tv.tv_sec = timeout;
+ tv.tv_usec = 0;
+ int rc;
+
+ rc = ldap_result( d_ld, msgid, LDAP_MSG_ONE, &tv, &res );
+
+ switch( rc )
+ {
+ case -1:
+ ensureConnect();
+ throw LDAPException( "Error waiting for LDAP result: " + getError() );
+ case 0:
+ throw LDAPTimeout();
+ }
+
+ if( result == NULL )
+ {
+ ldap_msgfree( res );
+ return rc;
+ }
+
+ *result = res;
+ return rc;
+}
+
+
+bool PowerLDAP::getSearchEntry( int msgid, sentry_t& entry, bool dn, int timeout )
+{
+ int i;
+ char* attr;
+ BerElement* ber;
+ struct berval** berval;
+ vector<string> values;
+ LDAPMessage* result;
+ LDAPMessage* object;
+
+
+ if( ( i = waitResult( msgid, timeout, &result ) ) == LDAP_RES_SEARCH_RESULT )
+ {
+ ldap_msgfree( result );
+ return false;
+ }
+
+ if( i != LDAP_RES_SEARCH_ENTRY )
+ {
+ ldap_msgfree( result );
+ throw LDAPException( "Search returned an unexpected result" );
+ }
+
+ if( ( object = ldap_first_entry( d_ld, result ) ) == NULL )
+ {
+ ldap_msgfree( result );
+ throw LDAPException( "Couldn't get first result entry: " + getError() );
+ }
+
+ entry.clear();
+
+ if( dn )
+ {
+ attr = ldap_get_dn( d_ld, object );
+ values.push_back( string( attr ) );
+ ldap_memfree( attr );
+ entry["dn"] = values;
+ }
+
+ if( ( attr = ldap_first_attribute( d_ld, object, &ber ) ) != NULL )
+ {
+ do
+ {
+ if( ( berval = ldap_get_values_len( d_ld, object, attr ) ) != NULL )
+ {
+ values.clear();
+ for( i = 0; i < ldap_count_values_len( berval ); i++ )
+ {
+ values.push_back( berval[i]->bv_val ); // use berval[i]->bv_len for non string values?
+ }
+
+ entry[attr] = values;
+ ldap_value_free_len( berval );
+ }
+ ldap_memfree( attr );
+ }
+ while( ( attr = ldap_next_attribute( d_ld, object, ber ) ) != NULL );
+
+ ber_free( ber, 0 );
+ }
+
+ ldap_msgfree( result );
+ return true;
+}
+
+
+void PowerLDAP::getSearchResults( int msgid, sresult_t& result, bool dn, int timeout )
+{
+ sentry_t entry;
+
+ result.clear();
+ while( getSearchEntry( msgid, entry, dn, timeout ) )
+ {
+ result.push_back( entry );
+ }
+}
+
+
+const string PowerLDAP::getError( int rc )
+{
+ if( rc == -1 ) { getOption( LDAP_OPT_ERROR_NUMBER, &rc ); }
+
+ return string( ldap_err2string( rc ) );;
+}
+
+
+const string PowerLDAP::escape( const string& str )
+{
+ string a;
+ string::const_iterator i;
+ char tmp[4];
+
+ for( i = str.begin(); i != str.end(); i++ )
+ {
+ // RFC4515 3
+ if( *i == '*' ||
+ *i == '(' ||
+ *i == ')' ||
+ *i == '\\' ||
+ *i == '\0' ||
+ *i > 127)
+ {
+ sprintf(tmp,"\\%02x", (unsigned char)*i);
+
+ a += tmp;
+ }
+ else
+ a += *i;
+ }
+
+ return a;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <map>
+#include <string>
+#include <vector>
+#include <exception>
+#include <stdexcept>
+#include <inttypes.h>
+#include <errno.h>
+#include <lber.h>
+#include <ldap.h>
+
+
+
+
+#ifndef POWERLDAP_HH
+#define POWERLDAP_HH
+
+using std::map;
+using std::string;
+using std::vector;
+
+class LDAPException : public std::runtime_error
+{
+public:
+ explicit LDAPException( const string &str ) : std::runtime_error( str ) {}
+};
+
+class LDAPTimeout : public LDAPException
+{
+public:
+ explicit LDAPTimeout() : LDAPException( "Timeout" ) {}
+};
+
+class PowerLDAP
+{
+ LDAP* d_ld;
+ string d_hosts;
+ int d_port;
+ bool d_tls;
+
+ const string getError( int rc = -1 );
+ int waitResult( int msgid = LDAP_RES_ANY, int timeout = 0, LDAPMessage** result = NULL );
+ void ensureConnect();
+
+public:
+ typedef map<string, vector<string> > sentry_t;
+ typedef vector<sentry_t> sresult_t;
+
+ PowerLDAP( const string& hosts = "ldap://127.0.0.1/", uint16_t port = LDAP_PORT, bool tls = false );
+ ~PowerLDAP();
+
+ void getOption( int option, int* value );
+ void setOption( int option, int value );
+
+ void bind( const string& ldapbinddn = "", const string& ldapsecret = "", int method = LDAP_AUTH_SIMPLE, int timeout = 5 );
+ void simpleBind( const string& ldapbinddn = "", const string& ldapsecret = "" );
+ int search( const string& base, int scope, const string& filter, const char** attr = 0 );
+
+ bool getSearchEntry( int msgid, sentry_t& entry, bool dn = false, int timeout = 5 );
+ void getSearchResults( int msgid, sresult_t& result, bool dn = false, int timeout = 5 );
+
+ static const string escape( const string& tobe );
+};
+
+
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <string>
+#include <vector>
+#include <time.h>
+#include <stdlib.h>
+#include "pdns/misc.hh"
+#include "pdns/utility.hh"
+
+
+#ifndef LDAPBACKEND_UTILS_HH
+#define LDAPBACKEND_UTILS_HH
+
+using std::string;
+using std::vector;
+
+
+inline string ptr2ip4( vector<string>& parts )
+{
+ string ip;
+ parts.pop_back();
+ parts.pop_back();
+
+
+ ip = parts.back();
+ parts.pop_back();
+
+ while( !parts.empty() )
+ {
+ ip += "." + parts.back();
+ parts.pop_back();
+ }
+
+ return ip;
+}
+
+
+inline string ptr2ip6( vector<string>& parts )
+{
+ int i = 0;
+ string ip;
+
+
+ parts.pop_back();
+ parts.pop_back();
+
+ while( i < 3 && parts.size() > 1 && parts.back() == "0" )
+ {
+ parts.pop_back();
+ i++;
+ }
+
+ while( i++ < 4 && !parts.empty() )
+ {
+ ip += parts.back();
+ parts.pop_back();
+ }
+
+ while( !parts.empty() )
+ {
+ i = 0;
+ ip += ":";
+
+ while( i < 3 && parts.size() > 1 && parts.back() == "0" )
+ {
+ parts.pop_back();
+ i++;
+ }
+
+ while( i++ < 4 && !parts.empty() )
+ {
+ ip += parts.back();
+ parts.pop_back();
+ }
+ }
+
+ return ip;
+}
+
+
+inline string ip2ptr4( const string& ip )
+{
+ string ptr;
+ vector<string> parts;
+
+ stringtok( parts, ip, "." );
+ while( !parts.empty() )
+ {
+ ptr += parts.back() + ".";
+ parts.pop_back();
+ }
+
+ return ptr + "in-addr.arpa";
+}
+
+
+inline string ip2ptr6( const string& ip )
+{
+ string ptr, part, defstr;
+ vector<string> parts;
+
+ stringtok( parts, ip, ":" );
+ while( !parts.empty() )
+ {
+ defstr = "0.0.0.0.";
+ part = parts.back();
+
+ while( part.length() < 4 )
+ {
+ part = "0" + part;
+ }
+
+ defstr[0] = part[3];
+ defstr[2] = part[2];
+ defstr[4] = part[1];
+ defstr[6] = part[0];
+ ptr += defstr;
+ parts.pop_back();
+ }
+
+ return ptr + "ip6.arpa";
+}
+
+
+inline string strbind( const string& search, const string& replace, string subject )
+{
+ size_t pos = 0;
+
+
+ while( ( pos = subject.find( search, pos ) ) != string::npos )
+ {
+ subject.replace( pos, search.size(), replace );
+ pos += replace.size();
+ }
+
+ return subject;
+}
+
+/*
+ * Convert a LDAP time string to a time_t. Return 0 if unable to convert
+ */
+
+inline time_t str2tstamp( const string& str )
+{
+ char* tmp;
+ struct tm tm;
+
+ tmp = strptime( str.c_str(), "%Y%m%d%H%M%SZ", &tm );
+
+ if( tmp != NULL && *tmp == 0 )
+ {
+ return Utility::timegm( &tm );
+ }
+
+ return 0;
+}
+
+#endif
--- /dev/null
+AM_CPPFLAGS += $(LUA_CFLAGS)
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+pkglib_LTLIBRARIES = libluabackend.la
+
+libluabackend_la_SOURCES = \
+ dnssec.cc \
+ lua_functions.cc lua_functions.hh \
+ luabackend.cc luabackend.hh \
+ master.cc \
+ minimal.cc \
+ private.cc \
+ reload.cc \
+ slave.cc \
+ supermaster.cc
+
+libluabackend_la_LDFLAGS = -module -avoid-version
+libluabackend_la_LIBADD = $(LUA_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/luabackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libluabackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libluabackend_la_OBJECTS = dnssec.lo lua_functions.lo luabackend.lo \
+ master.lo minimal.lo private.lo reload.lo slave.lo \
+ supermaster.lo
+libluabackend_la_OBJECTS = $(am_libluabackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libluabackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libluabackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libluabackend_la_SOURCES)
+DIST_SOURCES = $(libluabackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(LUA_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+pkglib_LTLIBRARIES = libluabackend.la
+libluabackend_la_SOURCES = \
+ dnssec.cc \
+ lua_functions.cc lua_functions.hh \
+ luabackend.cc luabackend.hh \
+ master.cc \
+ minimal.cc \
+ private.cc \
+ reload.cc \
+ slave.cc \
+ supermaster.cc
+
+libluabackend_la_LDFLAGS = -module -avoid-version
+libluabackend_la_LIBADD = $(LUA_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/luabackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/luabackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libluabackend.la: $(libluabackend_la_OBJECTS) $(libluabackend_la_DEPENDENCIES) $(EXTRA_libluabackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libluabackend_la_LINK) -rpath $(pkglibdir) $(libluabackend_la_OBJECTS) $(libluabackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnssec.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lua_functions.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/luabackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/master.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/minimal.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/private.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/reload.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slave.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/supermaster.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+luabackend.lo minimal.lo reload.lo lua_functions.lo master.lo private.lo slave.lo supermaster.lo dnssec.lo
\ No newline at end of file
--- /dev/null
+$(LUA_LIBS)
--- /dev/null
+====================================
+This is the luabackend for PowerDNS!
+====================================
+
+Note: shortly before the 3.2 release of PowerDNS, Fredrik Danerklinkt
+(author of this Luabackend) opened https://github.com/fredan/luabackend
+and is doing development there.
+
+
+http://www.lua.org for more information about what Lua really is.
+
+
+This backend is just a "glue" between PowerDNS and your own Lua application.
+
+What this means is that you can not have a working setup that can serve you
+dns-questions directly from start. What you need to do is to program your own
+backend completely in Lua! Which database server to use etc is now up to you!
+
+What you have here is the possibility to make your own "dns-server" without the
+knowledge of programming in c/c++.
+
+There is one thing that needs to be said. Remember that each thread
+PowerDNS launches of this backend is completely different so they cannot
+share information between each other!
+
+You will need some kind of a database that can be shared for this.
+
+All the functionnames that PowerDNS accept for a backend should be the same
+in your Lua script, in lowercase. Also, the parameters should be in the same
+order. Where there is a structure in c/c++ there is a table in the Lua backend.
+This is also true for return values. A few functions expect that you return a
+table in a table.
+
+
+=============
+NEW FUNCTIONS
+=============
+
+There is a couple of new functions for you to use in Lua:
+
+----------------------------------------
+logger(log_facility, "your", "messages")
+----------------------------------------
+
+All these log_facilities is available:
+log_all, log_ntlog, log_alert, log_critical, log_error, log_warning, log_notice,
+log_info, log_debug, log_none
+
+
+-----------
+dnspacket()
+-----------
+
+This will give you back three parameters with
+remote_ip, remote_port and local_ip in that order.
+
+Can only be used in the functions list() and getsoa().
+
+
+------------------------
+getarg("your_parameter")
+------------------------
+
+This one tries to get the value of the name "lua-your_parameter" from the
+pdns.conf file.
+
+
+------------------------
+mustdo("your_parameter")
+------------------------
+
+This is the same as getarg() but return a boolean instead of a string.
+
+
+You also have all the different QTypes in a table called 'QTypes'.
+
+
+====================
+WHAT HAS BEEN TESTED
+====================
+
+The only functionality of the minimal functions except zone-transfer has
+been tested.
+
+In the included powerdns-luabackend.lua file there is a example of how
+this can be done. Note that this is more or less a static example since
+there is no possibility for each thread to know when something has changed.
+
+However, you can run 'pdns_control reload' and it should reload the hole thing
+from scratch (does not work for the moment, PowerDNS only calls two thread with
+the reload command - not all of them).
+
+
+===========================================
+WHAT YOU WILL FIND UNDER THE TEST DIRECTORY
+===========================================
+
+The script 'pdns' is used to test the server on the ip address '127.0.0.1' with
+the port 5300. You should be able to run the following test with the included
+'powerdns-luabackend.lua' file:
+
+$dig any www.test.com @127.0.0.1 -p5300 +multiline
+; <<>> DiG 9.7.3 <<>> any www.test.com @127.0.0.1 -p5300 +multiline
+;; global options: +cmd
+;; Got answer:
+;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 1001
+;; flags: qr aa rd; QUERY: 1, ANSWER: 3, AUTHORITY: 0, ADDITIONAL: 0
+;; WARNING: recursion requested but not available
+
+;; QUESTION SECTION:
+;www.test.com. IN ANY
+
+;; ANSWER SECTION:
+www.test.com. 120 IN CNAME host.test.com.
+host.test.com. 120 IN A 10.11.12.13
+host.test.com. 120 IN AAAA 1:2:3:4:5:6:7:8
+
+;; Query time: 1 msec
+;; SERVER: 127.0.0.1#5300(127.0.0.1)
+;; WHEN: Thu Jun 2 22:19:56 2011
+;; MSG SIZE rcvd: 93
+
+
+=============================
+OPTIONS IN THE CONFIGURE FILE
+=============================
+
+The default values is:
+
+lua-filename = powerdns-luabackend.lua
+lua-logging-query = no
+
+You can also override all the default functionsnames for the luafunctions if you
+want. The prefix is lua-f_<functionname>=mynewfunction. For example:
+
+lua-f_lookup = mynewfunction
+
+will call the function 'mynewfunction' for the lookup-routine.
+
+If you want your own configuration parameters you can have that too.
+Just call the function getarg("my_parameter") and it will return the value
+of 'lua-my_parameter'. For boolean you use the function mustdo("my_parameter").
+
+
+==============================
+YOUR OWN ERROR FUNCTION IN LUA
+==============================
+
+You can have an error function in Lua when Lua gives back a error.
+
+First make your error function then you put this in pdns.conf:
+
+lua-f_exec_error = <your_name_of_the_error_function_in_lua>
+
+
+======
+DNSSEC
+======
+
+You can have full dnssec support in our Lua application. You should note the
+following regarding this:
+
+You don't have to implement the function 'updateDNSSECOrderAndAuth' since the
+default code will work correctly for you via the backend itself.
+
+The functions activateDomainKey and deactivateDomainKey can be implemented via a
+new function called updateDomainKey, which has three parameters (the other two
+has only two parameters) where the third is a boolean which is true or false
+depending on which function that was called from the beginning.
+
+
+=======================
+INFORMATION FOR LOGGING
+=======================
+
+If you have the parameter 'query-logging' or 'lua-logging-query' set to
+true/yes/on, then you will see what is happening in each function when PowerDNS
+calls them.
+
+This can, hopefully, help you with some debugging if you run into some kind of
+trouble with your Lua application.
+
+
+===============
+ASKING QUESTION
+===============
+
+You can send question about this backend to >dev/null first and if you don't get any
+answer from that you can try to send them to me at fredan-pdns@fredan.org
+
+Fredrik Danerklint.
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+
+bool LUABackend::updateDNSSECOrderAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, bool auth) {
+
+ if(f_lua_updatednssecorderandauth == 0) {
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) domain_id: '" << domain_id << "' zonename: '" << zonename << "' qname: '" << qname << "' auth: '" << auth << "'" << endl;
+
+ string ins=toLower(labelReverse(qname.makeRelative(zonename).toString()));
+ return this->updateDNSSECOrderAndAuthAbsolute(domain_id, qname, ins, auth);
+ }
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) BEGIN domain_id: '" << domain_id << "' zonename: '" << zonename << "' qname: '" << qname << "' auth: '" << auth << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauth);
+
+ lua_pushinteger(lua, domain_id);
+ lua_pushstring(lua, zonename.toString().c_str());
+ lua_pushstring(lua, qname.toString().c_str());
+ lua_pushboolean(lua, auth);
+
+ if(lua_pcall(lua, 4, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuth) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::updateDNSSECOrderNameAndAuth(unsigned int, DNSName const&, DNSName const&, DNSName const&, bool, unsigned short)
+{
+ return false;
+}
+
+bool LUABackend::updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const DNSName& qname, const std::string& ordername, bool auth) {
+
+ if(f_lua_updatednssecorderandauthabsolute == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuthAbsolute) BEGIN domain_id: '" << domain_id << "' qname: '" << qname << "' ordername: '" << ordername << "' auth: '" << auth << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauthabsolute);
+
+ lua_pushinteger(lua, domain_id);
+ lua_pushstring(lua, qname.toString().c_str());
+ lua_pushstring(lua, ordername.c_str());
+ lua_pushboolean(lua, auth);
+
+ if(lua_pcall(lua, 4, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDNSSECOrderAndAuthAbsolute) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, DNSName& unhashed, std::string& before, std::string& after) {
+
+ if(f_lua_getbeforeandafternamesabsolute == 0)
+ return false;
+
+ unhashed.clear();
+ before.clear();
+ after.clear();
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) BEGIN id: '" << id << "' qname: '" << qname << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatednssecorderandauthabsolute);
+
+ lua_pushinteger(lua, id);
+ lua_pushstring(lua, qname.c_str());
+
+ if(lua_pcall(lua, 2, 3, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = returnedwhat == LUA_TSTRING;
+
+ if (!ok) {
+ if(logging)
+ L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) ERROR!" << endl;
+
+ return false;
+ }
+
+ //will this be correct since we are poping one at the time?
+ unhashed = DNSName(lua_tostring(lua, -1));
+ lua_pop(lua, 1);
+
+ returnedwhat = lua_type(lua, -1);
+ ok = (returnedwhat == LUA_TSTRING) && ok;
+
+ before = lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ returnedwhat = lua_type(lua, -1);
+ ok = (returnedwhat == LUA_TSTRING) && ok;
+
+ after = lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getBeforeAndAfterNamesAbsolute) END unhashed: '" << unhashed << "' before: '" << before << "' after: '" << after << "' " << endl;
+
+ return ok;
+}
+
+bool LUABackend::updateDomainKey(const DNSName& name, unsigned int &id, bool toowhat ) {
+
+ if(f_lua_updatedomainkey == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDomainKey) BEGIN name: '" << name << "' id: '" << id << "' toowhat: '" << toowhat << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_updatedomainkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushinteger(lua, id);
+ lua_pushboolean(lua, toowhat);
+
+ if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(updateDomainKey) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::activateDomainKey(const DNSName& name, unsigned int id) {
+
+ if(f_lua_activatedomainkey == 0)
+ return updateDomainKey(name, id, true);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(activateDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_activatedomainkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushinteger(lua, id);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(activateDomainKey) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::deactivateDomainKey(const DNSName& name, unsigned int id) {
+
+ if(f_lua_deactivatedomainkey == 0)
+ return updateDomainKey(name, id, false);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(deactivateDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_deactivatedomainkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushinteger(lua, id);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(deactivateDomainKey) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::removeDomainKey(const DNSName& name, unsigned int id) {
+
+ if(f_lua_removedomainkey == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(removeDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_removedomainkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushinteger(lua, id);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(removeDomainKey) END" << endl;
+
+ return ok;
+}
+
+int LUABackend::addDomainKey(const DNSName& name, const KeyData& key) {
+// there is no logging function in pdnsutil when running this routine?
+
+//key = id, flags, active, content
+
+ if(f_lua_adddomainkey == 0)
+ return -1;
+
+ if(logging)
+ //L << Logger::Info << backend_name << "(addDomainKey) BEGIN name: '" << name << "' id: '" << id << endl;
+ cerr << backend_name << "(addDomainKey) BEGIN name: '" << name << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_adddomainkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+
+ lua_newtable(lua);
+
+ lua_pushliteral(lua, "flags");
+ lua_pushinteger(lua, key.flags);
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "active");
+ lua_pushboolean(lua, key.active);
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "content");
+ lua_pushstring(lua, key.content.c_str());
+ lua_settable(lua, -3);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return -1;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ int ok = -1;
+
+ if (returnedwhat == LUA_TNUMBER)
+ ok = lua_tonumber(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ cerr << backend_name << "(addDomainKey) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys) {
+ //what is kind used for?
+
+ if(f_lua_getdomainkeys == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getDomainKeys) BEGIN name: '" << name << "' kind: '" << kind << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomainkeys);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushinteger(lua, kind);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1);
+ if(logging)
+ L << Logger::Info << backend_name << "(getDomainKeys) ERROR!" << endl;
+
+ return false;
+ }
+
+ lua_pushnil(lua);
+
+ int j = 0;
+
+ while (lua_next(lua, -2)) {
+ returnedwhat = lua_type(lua, -1);
+ if (returnedwhat == LUA_TTABLE) {
+ KeyData kd;
+ bool i,f,a,c = false;
+
+ i = getValueFromTable(lua, "id", kd.id);
+ f = getValueFromTable(lua, "flags", kd.flags);
+ a = getValueFromTable(lua, "active", kd.active);
+ c = getValueFromTable(lua, "content", kd.content);
+
+ if (i && f && a && c) {
+ j++;
+ keys.push_back(kd);
+ }
+ }
+
+ lua_pop(lua,1);
+ }
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getDomainKeys) END" << endl;
+
+ return j > 0;
+}
+
+bool LUABackend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) {
+
+ if(f_lua_gettsigkey == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getTSIGKey) BEGIN name: '" << name << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_gettsigkey);
+
+ lua_pushstring(lua, name.toString().c_str());
+
+ if(lua_pcall(lua, 1, 2, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ if ( (lua_type(lua, -1) != LUA_TSTRING) && (lua_type(lua, -2) != LUA_TSTRING) ) {
+ lua_pop(lua, 2);
+ if(logging)
+ L << Logger::Info << backend_name << "(getTSIGKey) ERROR" << endl;
+ return false;
+ }
+
+ string a,c = "";
+
+ a = lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ c = lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ *algorithm = DNSName(a);
+ *content = c;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getTSIGKey) END" << endl;
+
+ return true;
+}
+
+bool LUABackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) {
+
+ if(f_lua_setdomainmetadata == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(setDomainMetadata) BEGIN name: '" << name << "' kind: '" << kind << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setdomainmetadata);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushstring(lua, kind.c_str());
+
+ lua_newtable(lua);
+
+ std::vector<std::string>::const_iterator i;
+
+ int c = 0;
+
+ for(i = meta.begin(); i<meta.end(); i++ ) {
+ c++;
+ lua_pushinteger(lua, c);
+ lua_pushstring(lua, i->c_str());
+ lua_settable(lua, -3);
+ }
+
+ if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if(logging)
+ L << Logger::Info << backend_name << "(setDomainMetadata) END" << endl;
+
+ return ok;
+
+}
+
+bool LUABackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) {
+ if(f_lua_getdomainmetadata == 0)
+ return false;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getDomainMetadata) BEGIN name: '" << name << "' kind: '" << kind << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomainmetadata);
+
+ lua_pushstring(lua, name.toString().c_str());
+ lua_pushstring(lua, kind.c_str());
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ if (lua_type(lua, -1) != LUA_TTABLE)
+ return false;
+
+ lua_pushnil(lua);
+
+ int j = 0;
+ size_t returnedwhat;
+
+ while (lua_next(lua, -2)) {
+ returnedwhat = lua_type(lua, -1);
+ if (returnedwhat == LUA_TSTRING) {
+ j++;
+ meta.push_back(lua_tostring(lua, -1));
+ }
+
+ lua_pop(lua,1);
+ }
+
+ if(logging)
+ L << Logger::Info << backend_name << "(getDomainMetadata) END" << endl;
+
+ return j > 0;
+
+}
+
+void LUABackend::alsoNotifies(const DNSName& domain, set<string> *ips) {
+
+ if(f_lua_alsonotifies == 0)
+ return;
+
+ if(logging)
+ L << Logger::Info << backend_name << "(alsonotifies) BEGIN domain: '" << domain << "'" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_alsonotifies);
+
+ lua_pushstring(lua, domain.toString().c_str());
+
+ if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return;
+ }
+
+ if (lua_type(lua, -1) != LUA_TTABLE)
+ return;
+
+ lua_pushnil(lua);
+
+ size_t returnedwhat;
+
+ while (lua_next(lua, -2)) {
+ returnedwhat = lua_type(lua, -1);
+ if (returnedwhat == LUA_TSTRING) {
+ ips->insert(lua_tostring(lua, -1));
+ }
+
+ lua_pop(lua,1);
+ }
+
+ if(logging)
+ L << Logger::Info << backend_name << "(alsoNotifies) END" << endl;
+
+ return;
+
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define LUABACKEND_EXTERN_F_HH
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnspacket.hh"
+
+#include <iostream>
+#include <sstream>
+using namespace std;
+
+// It seems we don't want the coroutine standard library so we can't use
+// luaL_openlibs(). FIXME: is the coroutine library really that bad?
+const luaL_Reg lualibs[] = {
+#if LUA_VERSION_NUM < 502
+ {"", luaopen_base},
+#else
+ {"_G", luaopen_base},
+#endif
+ {LUA_LOADLIBNAME, luaopen_package},
+ {LUA_TABLIBNAME, luaopen_table},
+ {LUA_IOLIBNAME, luaopen_io},
+ {LUA_OSLIBNAME, luaopen_os},
+ {LUA_STRLIBNAME, luaopen_string},
+ {LUA_MATHLIBNAME, luaopen_math},
+ {LUA_DBLIBNAME, luaopen_debug},
+#if LUA_VERSION_NUM == 502 || defined(LUA_COMPAT_BITLIB)
+ {LUA_BITLIBNAME, luaopen_bit32},
+#endif
+#if LUA_VERSION_NUM == 503
+ {LUA_UTF8LIBNAME, luaopen_utf8},
+#endif
+// {LUA_COLIBNAME, luaopen_coroutine},
+#ifdef USE_LUAJIT
+ {"bit", luaopen_bit},
+ {"jit", luaopen_jit},
+#endif
+ {NULL, NULL}
+};
+
+int my_lua_panic (lua_State *lua) {
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+ LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+ assert(lua == lb->lua);
+
+ stringstream e;
+
+ e << lb->backend_name << "LUA PANIC! '" << lua_tostring(lua,-1) << "'" << endl;
+
+ throw LUAException (e.str());
+
+ return 0;
+}
+
+int l_arg_get (lua_State *lua) {
+ int i = lua_gettop(lua);
+ if (i < 1)
+ return 0;
+
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+ LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+ string a = lua_tostring(lua, 1);
+
+ if (::arg().isEmpty(a))
+ lua_pushnil(lua);
+ else
+ lua_pushstring(lua, lb->my_getArg(a).c_str());
+
+ return 1;
+}
+
+int l_arg_mustdo (lua_State *lua) {
+ int i = lua_gettop(lua);
+ if (i < 1)
+ return 0;
+
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+ LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+ string a = lua_tostring(lua, 1);
+
+ if (::arg().isEmpty(a))
+ lua_pushnil(lua);
+ else
+ lua_pushboolean(lua, lb->my_mustDo(a));
+
+ return 1;
+}
+
+int l_dnspacket (lua_State *lua) {
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+ LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+ if (lb->dnspacket == NULL) {
+ lua_pushnil(lua);
+
+ return 1;
+ }
+
+ lua_pushstring(lua, lb->dnspacket->getRemote().toString().c_str());
+ lua_pushinteger(lua, lb->dnspacket->getRemotePort());
+ lua_pushstring(lua, lb->dnspacket->getLocal().toString().c_str());
+ lua_pushstring(lua, lb->dnspacket->getRealRemote().toString().c_str());
+
+ return 4;
+}
+
+int l_logger (lua_State *lua) {
+// assert(lua == lb->lua);
+
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+ LUABackend* lb = (LUABackend*)lua_touserdata(lua, -1);
+
+ int i = lua_gettop(lua);
+ if (i < 1)
+ return 0;
+
+ int log_level = 0;
+ stringstream s;
+ int j;
+ const char *ss;
+
+ log_level = lua_tointeger(lua, 1);
+
+ string space = "";
+
+ for(j=2; j<=i; j++) {
+ ss = lua_tostring(lua, j);
+ s << space << ss;
+ space = " ";
+ }
+
+ L.log(lb->backend_name + s.str(), (Logger::Urgency) log_level);
+
+ return 0;
+}
+
+void register_lua_functions(lua_State *lua) {
+ lua_gc(lua, LUA_GCSTOP, 0); // stop collector during initialization
+
+ const luaL_Reg *lib = lualibs;
+ for (; lib->func; lib++) {
+#if LUA_VERSION_NUM < 502
+ lua_pushcfunction(lua, lib->func);
+ lua_pushstring(lua, lib->name);
+ lua_call(lua, 1, 0);
+#else
+ luaL_requiref(lua, lib->name, lib->func, 1);
+ lua_pop(lua, 1); /* remove lib */
+#endif
+ }
+
+ lua_gc(lua, LUA_GCRESTART, 0);
+
+ lua_pushinteger(lua, Logger::All);
+ lua_setglobal(lua, "log_all");
+
+ lua_pushinteger(lua, Logger::Alert);
+ lua_setglobal(lua, "log_alert");
+
+ lua_pushinteger(lua, Logger::Critical);
+ lua_setglobal(lua, "log_critical");
+
+ lua_pushinteger(lua, Logger::Error);
+ lua_setglobal(lua, "log_error");
+
+ lua_pushinteger(lua, Logger::Warning);
+ lua_setglobal(lua, "log_warning");
+
+ lua_pushinteger(lua, Logger::Notice);
+ lua_setglobal(lua, "log_notice");
+
+ lua_pushinteger(lua, Logger::Info);
+ lua_setglobal(lua, "log_info");
+
+ lua_pushinteger(lua, Logger::Debug);
+ lua_setglobal(lua, "log_debug");
+
+ lua_pushinteger(lua, Logger::None);
+ lua_setglobal(lua, "log_none");
+
+ lua_pushcfunction(lua, l_dnspacket);
+ lua_setglobal(lua, "dnspacket");
+
+ lua_pushcfunction(lua, l_logger);
+ lua_setglobal(lua, "logger");
+
+ lua_pushcfunction(lua, l_arg_get);
+ lua_setglobal(lua, "getarg");
+
+ lua_pushcfunction(lua, l_arg_mustdo);
+ lua_setglobal(lua, "mustdo");
+
+ lua_newtable(lua);
+ for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
+ lua_pushinteger(lua, iter->second);
+ lua_setfield(lua, -2, iter->first.c_str());
+ }
+ lua_pushinteger(lua, 3);
+ lua_setfield(lua, -2, "NXDOMAIN");
+ lua_setglobal(lua, "QTypes");
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, string& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = lua_tostring(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, DNSName& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = DNSName(lua_tostring(lua, -1));
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, uint32_t key, string& value) {
+ lua_pushinteger(lua, key);
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = lua_tostring(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+#if !(defined(__i386__) && defined(__FreeBSD__))
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, time_t& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (time_t)lua_tonumber(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+#endif
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, uint32_t& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (uint32_t)lua_tointeger(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, uint16_t& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (uint16_t)lua_tointeger(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, uint8_t& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (uint8_t)lua_tointeger(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, int& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (int)lua_tointeger(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
+
+bool LUABackend::getValueFromTable(lua_State *lua, const std::string& key, bool& value) {
+ lua_pushstring(lua, key.c_str());
+ lua_gettable(lua, -2);
+
+ bool ret = false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = lua_toboolean(lua, -1);
+ ret = true;
+ }
+
+ lua_pop(lua, 1);
+
+ return ret;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef LUABACKEND_EXTERN_F_HH
+#define LUABACKEND_EXTERN_F_HH
+
+//extern LUABackend* lb;
+extern int my_lua_panic(lua_State* lua);
+extern void register_lua_functions(lua_State* lua);
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+#include "pdns/logger.hh"
+
+/* SECOND PART */
+
+class LUAFactory : public BackendFactory
+{
+public:
+ LUAFactory() : BackendFactory("lua") {}
+
+ void declareArguments(const string &suffix="")
+ {
+
+ declare(suffix,"filename","Filename of the script for lua backend","powerdns-luabackend.lua");
+ declare(suffix,"logging-query","Logging of the LUA Backend","no");
+
+ }
+
+ DNSBackend *make(const string &suffix="")
+ {
+ return new LUABackend(suffix);
+ }
+
+};
+
+/* THIRD PART */
+
+class LUALoader
+{
+public:
+ LUALoader()
+ {
+ BackendMakers().report(new LUAFactory);
+
+ L << Logger::Info << "[luabackend] This is the lua backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static LUALoader luaLoader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef LUABACKEND_HH
+#define LUABACKEND_HH
+
+#include "lua.hpp"
+
+//extern "C" {
+//#include "lua.h"
+//#include "lualib.h"
+//#include "lauxlib.h"
+//}
+
+#include "pdns/dnsbackend.hh"
+
+#include <string>
+using std::string;
+
+//#undef L
+
+
+
+class LUAException {
+public:
+ LUAException(const string &ex) : what(ex){}
+ string what;
+};
+
+class LUABackend : public DNSBackend {
+
+public:
+
+// MINIMAL BACKEND
+
+ LUABackend(const string &suffix="");
+ ~LUABackend();
+ bool list(const DNSName &target, int domain_id, bool include_disabled=false);
+ void lookup(const QType &qtype, const DNSName &qname, DNSPacket *p, int domain_id);
+ bool get(DNSResourceRecord &rr);
+ //! fills the soadata struct with the SOA details. Returns false if there is no SOA.
+ bool getSOA(const DNSName &name, SOAData &soadata, DNSPacket *p=0);
+
+
+// MASTER BACKEND
+
+ void getUpdatedMasters(vector<DomainInfo>* domains);
+ void setNotifed(int id, uint32_t serial);
+
+
+// SLAVE BACKEND
+
+ bool getDomainInfo(const DNSName& domain, DomainInfo &di) override;
+ bool isMaster(const DNSName& name, const string &ip) override;
+ void getUnfreshSlaveInfos(vector<DomainInfo>* domains) override;
+ void setFresh(uint32_t id) override;
+
+ bool startTransaction(const DNSName &qname, int id) override;
+ bool commitTransaction() override;
+ bool abortTransaction() override;
+ bool feedRecord(const DNSResourceRecord &rr, string *ordername=0) override;
+
+
+// SUPERMASTER BACKEND
+
+ bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) override;
+ bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account) override;
+
+
+// DNSSEC BACKEND
+
+ //! get a list of IP addresses that should also be notified for a domain
+ void alsoNotifies(const DNSName &domain, set<string> *ips) override;
+ bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) override;
+ bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) override;
+
+ bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys) override ;
+ bool removeDomainKey(const DNSName& name, unsigned int id) override ;
+ bool activateDomainKey(const DNSName& name, unsigned int id) override ;
+ bool deactivateDomainKey(const DNSName& name, unsigned int id) override ;
+ bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) override ;
+ int addDomainKey(const DNSName& name, const KeyData& key) override ;
+ bool updateDNSSECOrderAndAuthAbsolute(uint32_t domain_id, const DNSName& qname, const std::string& ordername, bool auth);
+ bool getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, string& before, string& after) override;
+ bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype=QType::ANY) override;
+ bool updateDNSSECOrderAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, bool auth);
+// OTHER
+ void reload() override ;
+ void rediscover(string* status=0) override ;
+
+
+ string backend_name;
+ lua_State *lua;
+ DNSPacket *dnspacket;
+
+ //private.cc
+ string my_getArg(string a);
+ bool my_mustDo(string a);
+
+private:
+
+ pthread_t backend_pid;
+ unsigned int backend_count{0};
+
+ int f_lua_exec_error;
+
+ //minimal functions....
+ int f_lua_list;
+ int f_lua_lookup;
+ int f_lua_get;
+ int f_lua_getsoa;
+
+ //master functions....
+ int f_lua_getupdatedmasters;
+ int f_lua_setnotifed;
+
+ //slave functions....
+ int f_lua_getdomaininfo;
+ int f_lua_ismaster;
+ int f_lua_getunfreshslaveinfos;
+ int f_lua_setfresh;
+
+ int f_lua_starttransaction;
+ int f_lua_committransaction;
+ int f_lua_aborttransaction;
+ int f_lua_feedrecord;
+
+ //supermaster functions....
+ int f_lua_supermasterbackend;
+ int f_lua_createslavedomain;
+
+ //rediscover
+ int f_lua_rediscover;
+
+ //dnssec
+ int f_lua_alsonotifies;
+ int f_lua_getdomainmetadata;
+ int f_lua_setdomainmetadata;
+
+ int f_lua_getdomainkeys;
+ int f_lua_removedomainkey;
+ int f_lua_activatedomainkey;
+ int f_lua_deactivatedomainkey;
+ int f_lua_updatedomainkey;
+ int f_lua_gettsigkey;
+ int f_lua_adddomainkey;
+
+ int f_lua_getbeforeandafternamesabsolute;
+ int f_lua_updatednssecorderandauthabsolute;
+ int f_lua_updatednssecorderandauth;
+
+
+// int my_lua_panic (lua_State *lua);
+
+// FUNCTIONS TO THIS BACKEND
+ bool getValueFromTable(lua_State *lua, const std::string& key, string& value);
+ bool getValueFromTable(lua_State *lua, const std::string& key, DNSName& value);
+ bool getValueFromTable(lua_State *lua, uint32_t key, string& value);
+#if !(defined(__i386__) && defined(__FreeBSD__))
+ bool getValueFromTable(lua_State *lua, const std::string& key, time_t& value);
+#endif
+ bool getValueFromTable(lua_State *lua, const std::string& key, uint32_t& value);
+ bool getValueFromTable(lua_State *lua, const std::string& key, uint16_t& value);
+ bool getValueFromTable(lua_State *lua, const std::string& key, uint8_t& value);
+ bool getValueFromTable(lua_State *lua, const std::string& key, int& value);
+ bool getValueFromTable(lua_State *lua, const std::string& key, bool& value);
+
+ //private.cc
+ bool domaininfo_from_table(DomainInfo *di);
+ void domains_from_table(vector<DomainInfo>* domains, const char *f_name);
+ void dnsrr_to_table(lua_State *lua, const DNSResourceRecord *rr);
+
+ //reload.cc
+ void get_lua_function(lua_State *lua, const char *name, int *function);
+
+ bool dnssec;
+
+ bool logging;
+
+ //dnssec.cc
+ bool updateDomainKey(const DNSName& name, unsigned int &id, bool toowhat);
+
+
+/*
+ //minimal.cc
+ bool content(DNSResourceRecord* rr);
+
+ void getTheFreshOnes(vector<DomainInfo>* domains, string *type, string *f_name);
+ bool checkDomainInfo(const string *domain, mongo::BSONObj *mongo_r, string *f_name, string *mongo_q, DomainInfo *di, SOAData *soadata = NULL);
+
+
+ //crc32.cc
+ int generateCRC32(const string& my_string);
+
+ string mongo_db;
+ string collection_domains;
+ string collection_records;
+
+ string collection_domainmetadata;
+ string collection_cryptokeys;
+ string collection_tsigkeys;
+
+ mongo::DBClientConnection m_db;
+
+ auto_ptr<mongo::DBClientCursor> cursor;
+
+ string q_name;
+
+// long long unsigned int count;
+ mongo::Query mongo_query;
+ mongo::BSONObj mongo_record;
+ bool elements;
+ DNSResourceRecord rr_record;
+ string type;
+ mongo::BSONObjIterator* contents;
+
+
+
+ unsigned int default_ttl;
+
+ bool logging_cerr;
+ bool logging_content;
+
+ bool checkindex;
+
+ bool use_default_ttl;
+
+ bool axfr_soa;
+ SOAData last_soadata;
+*/
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/*
+ virtual void getUpdatedMasters(vector<DomainInfo>* domains);
+ virtual void setNotifed(int id, uint32_t serial);
+*/
+
+void LUABackend::getUpdatedMasters(vector<DomainInfo>* domains) {
+
+ if (f_lua_getupdatedmasters == 0)
+ return;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getUpdatedMasters) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getupdatedmasters);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1 );
+ return;
+ }
+
+ domains_from_table(domains, "getUpdatedMasters");
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getUpdatedMasters) END" << endl;
+}
+
+void LUABackend::setNotifed(int id, uint32_t serial) {
+
+ if (f_lua_setnotifed == 0)
+ return;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(setNotifed) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setnotifed);
+
+ lua_pushinteger(lua, id);
+ lua_pushinteger(lua, serial);
+
+ if(lua_pcall(lua, 2, 0, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return;
+ }
+
+ if (logging)
+ L << Logger::Info << backend_name << "(setNotifed) END" << endl;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+//#include "lua_functions.hh"
+
+/* FIRST PART */
+
+LUABackend::LUABackend(const string &suffix) {
+
+ setArgPrefix("lua"+suffix);
+
+ try {
+
+ if (pthread_equal(backend_pid, pthread_self())) {
+ backend_count++;
+ } else {
+ backend_count = 1;
+ backend_pid = pthread_self();
+ }
+
+// lb = NULL;
+ lua = NULL;
+ dnspacket = NULL;
+ dnssec = false;
+
+ reload();
+ }
+
+ catch(LUAException &e) {
+ L<<Logger::Error<<backend_name<<"Error: "<<e.what<<endl;
+ throw PDNSException(e.what);
+ }
+
+}
+
+LUABackend::~LUABackend() {
+ try {
+ L<<Logger::Info<<backend_name<<"Closing..." << endl;
+ }
+ catch (...) {
+ }
+
+ lua_close(lua);
+}
+
+bool LUABackend::list(const DNSName &target, int domain_id, bool include_disabled) {
+ if (logging)
+ L << Logger::Info << backend_name << "(list) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_list);
+
+ lua_pushstring(lua, target.toString().c_str());
+ lua_pushinteger(lua, domain_id);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(list) END" << endl;
+
+ return ok;
+}
+
+void LUABackend::lookup(const QType &qtype, const DNSName &qname, DNSPacket *p, int domain_id) {
+ if (logging)
+ L << Logger::Info << backend_name << "(lookup) BEGIN" << endl;
+
+ dnspacket = p;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_lookup);
+
+// lua_pushnumber(lua, qtype.getCode());
+ lua_pushstring(lua, qtype.getName().c_str());
+ lua_pushstring(lua, qname.toString(). c_str());
+ lua_pushinteger(lua, domain_id);
+
+ if(lua_pcall(lua, 3, 0, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ dnspacket = NULL;
+
+ throw runtime_error(e);
+ return;
+ }
+
+ dnspacket = NULL;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(lookup) END" << endl;
+}
+
+bool LUABackend::get(DNSResourceRecord &rr) {
+ if (logging)
+ L << Logger::Info << backend_name << "(get) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_get);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1 );
+ return false;
+ }
+
+ rr.content.clear();
+
+// uint16_t qt;
+ string qt;
+
+ if (getValueFromTable(lua, "type", qt) )
+ rr.qtype = qt;
+ getValueFromTable(lua, "name", rr.qname);
+ getValueFromTable(lua, "domain_id", rr.domain_id);
+ getValueFromTable(lua, "auth", rr.auth);
+ getValueFromTable(lua, "last_modified", rr.last_modified);
+
+ getValueFromTable(lua, "ttl", rr.ttl);
+ if (rr.ttl == 0)
+ rr.ttl = ::arg().asNum( "default-ttl" );
+
+ getValueFromTable(lua, "content", rr.content);
+ getValueFromTable(lua, "scopeMask", rr.scopeMask);
+
+ lua_pop(lua, 1 );
+
+ if (logging)
+ L << Logger::Info << backend_name << "(get) END" << endl;
+
+ return !rr.content.empty();
+}
+
+bool LUABackend::getSOA(const DNSName &name, SOAData &soadata, DNSPacket *p) {
+ if (logging)
+ L << Logger::Info << backend_name << "(getsoa) BEGIN" << endl;
+
+ dnspacket = p;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getsoa);
+
+ lua_pushstring(lua, name.toString().c_str());
+
+ if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ dnspacket = NULL;
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ dnspacket = NULL;
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1 );
+ return false;
+ }
+
+ soadata.db = this;
+ soadata.serial = 0;
+ getValueFromTable(lua, "serial", soadata.serial);
+ if (soadata.serial == 0) {
+ lua_pop(lua, 1 );
+ return false;
+ }
+
+ getValueFromTable(lua, "refresh", soadata.refresh);
+ getValueFromTable(lua, "retry", soadata.retry);
+ getValueFromTable(lua, "expire", soadata.expire);
+ getValueFromTable(lua, "default_ttl", soadata.default_ttl);
+ getValueFromTable(lua, "domain_id", soadata.domain_id);
+
+ getValueFromTable(lua, "ttl", soadata.ttl);
+ if (soadata.ttl == 0 && soadata.default_ttl > 0)
+ soadata.ttl = soadata.default_ttl;
+
+ if (soadata.ttl == 0) {
+ lua_pop(lua, 1 );
+ return false;
+ }
+
+ if (!getValueFromTable(lua, "nameserver", soadata.nameserver)) {
+ soadata.nameserver = DNSName(arg()["default-soa-name"]);
+ if (soadata.nameserver.empty()) {
+ L<<Logger::Error << backend_name << "(getSOA)" << " Error: SOA Record is missing nameserver for the domain '" << name << "'" << endl;
+ lua_pop(lua, 1 );
+ return false;
+ }
+ }
+
+ if (!getValueFromTable(lua, "hostmaster", soadata.hostmaster))
+ soadata.hostmaster = DNSName("hostmaster")+DNSName(name);
+
+ lua_pop(lua, 1 );
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getsoa) END" << endl;
+
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+string LUABackend::my_getArg(string a) {
+ return getArg(a);
+}
+
+bool LUABackend::my_mustDo(string a) {
+ return mustDo(a);
+}
+
+bool LUABackend::domaininfo_from_table(DomainInfo *di) {
+
+ di->backend = NULL;
+
+ if (!getValueFromTable(lua, "id", di->id))
+ return false;
+
+ if (!getValueFromTable(lua, "zone", di->zone))
+ return false;
+
+ if (!getValueFromTable(lua, "serial", di->serial))
+ return false;
+
+ getValueFromTable(lua, "notified_serial", di->notified_serial);
+ getValueFromTable(lua, "last_check", di->last_check);
+
+ di->kind = DomainInfo::Native;
+
+ string kind;
+ if (getValueFromTable(lua, "kind", kind)) {
+
+ if (kind == "MASTER")
+ di->kind = DomainInfo::Master;
+ else if (kind == "SLAVE")
+ di->kind = DomainInfo::Slave;
+ }
+
+ lua_pushstring(lua, "masters");
+ lua_gettable(lua, -2);
+
+ if(!lua_isnil(lua, -1)) {
+ lua_pushnil(lua);
+ const char *value;
+ while (lua_next(lua, -2)) {
+ value = lua_tostring(lua, -1);
+ lua_pop(lua,1);
+ di->masters.push_back(value);
+ }
+ }
+
+ lua_pop(lua, 1);
+
+ di->backend = this;
+
+ return true;
+}
+
+void LUABackend::domains_from_table(vector<DomainInfo>* domains, const char *f_name) {
+ lua_pushnil(lua);
+
+ size_t returnedwhat;
+
+ while (lua_next(lua, -2)) {
+ returnedwhat = lua_type(lua, -1);
+ if (returnedwhat == LUA_TTABLE) {
+ DomainInfo di;
+
+ if (domaininfo_from_table(&di))
+ domains->push_back(di);
+ }
+
+ lua_pop(lua,1);
+ }
+}
+
+
+void LUABackend::dnsrr_to_table(lua_State *lua, const DNSResourceRecord *rr) {
+
+ lua_newtable(lua);
+
+ lua_pushliteral(lua, "qtype");
+ lua_pushstring(lua, rr->qtype.getName().c_str());
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "qclass");
+ lua_pushinteger(lua, rr->qclass);
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "ttl");
+ lua_pushinteger(lua, rr->ttl);
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "auth");
+ lua_pushboolean(lua, rr->auth);
+ lua_settable(lua, -3);
+
+ lua_pushliteral(lua, "content");
+ lua_pushstring(lua, rr->content.c_str());
+ lua_settable(lua, -3);
+
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+#include <iostream>
+#include <sstream>
+using namespace std;
+
+#include "lua_functions.hh"
+
+/*
+ virtual void reload();
+ virtual void rediscover(string* status=0);
+*/
+
+void LUABackend::get_lua_function(lua_State *lua, const char *name, int *function) {
+ *function = 0;
+
+ string f = "f_";
+ f.append(name);
+
+ string arg = "";
+ if (!::arg().isEmpty(f))
+ arg = getArg(f);
+
+ lua_getglobal(lua, arg == "" ? name : arg.c_str());
+ if (!lua_isnil(lua, -1)) {
+ lua_pushvalue(lua, -1);
+ *function = luaL_ref(lua, LUA_REGISTRYINDEX);
+ }
+}
+
+
+void LUABackend::reload() {
+
+ backend_name.clear();
+
+// backend_name = "[LUABackend: " + uitoa(backend_pid) + " (" + uitoa(backend_count) +")] ";
+ backend_name = "[LUABackend: (" + uitoa(backend_count) +")] ";
+
+ if (lua)
+ lua_close(lua);
+
+ logging = ::arg().mustDo("query-logging") || mustDo("logging-query");
+
+#if LUA_VERSION_NUM >= 502
+ lua = luaL_newstate();
+#else
+ lua = lua_open();
+#endif
+
+ if (lua != NULL) {
+ lua_atpanic(lua, my_lua_panic);
+
+ string filename = getArg("filename"); //"powerdns-luabackend.lua";
+
+ if (luaL_loadfile (lua, filename.c_str()) != 0) {
+ stringstream e;
+ e << backend_name << "Error loading the file '" << filename << "' : " << lua_tostring(lua,-1) << endl;
+
+ lua_pop(lua, 1);
+ throw LUAException (e.str());
+ } else {
+
+ lua_pushlightuserdata(lua, (void*)this);
+ lua_setfield(lua, LUA_REGISTRYINDEX, "__LUABACKEND");
+
+ register_lua_functions(lua);
+
+ if(lua_pcall(lua, 0, 0, 0)) {
+ stringstream e;
+ e << backend_name << "Error running the file '" << filename << "' : " << lua_tostring(lua,-1) << endl;
+
+ lua_pop(lua, 1);
+ throw LUAException (e.str());
+
+ } else {
+ get_lua_function(lua, "exec_error", &f_lua_exec_error);
+
+ //minimal functions....
+ get_lua_function(lua, "list", &f_lua_list);
+ get_lua_function(lua, "lookup", &f_lua_lookup);
+ get_lua_function(lua, "get", &f_lua_get);
+ get_lua_function(lua, "getsoa", &f_lua_getsoa);
+
+ if (f_lua_list == 0 || f_lua_lookup == 0 || f_lua_get == 0 || f_lua_getsoa == 0) {
+ throw LUAException (backend_name + "MINIMAL BACKEND: Missing required function(s)!");
+ }
+
+ //master functions....
+ get_lua_function(lua, "getupdatedmasters", &f_lua_getupdatedmasters);
+ get_lua_function(lua, "setnotifed", &f_lua_setnotifed);
+
+ //slave functions....
+ get_lua_function(lua, "getdomaininfo", &f_lua_getdomaininfo);
+ get_lua_function(lua, "ismaster", &f_lua_ismaster);
+ get_lua_function(lua, "getunfreshslaveinfos", &f_lua_getunfreshslaveinfos);
+ get_lua_function(lua, "setfresh", &f_lua_setfresh);
+ get_lua_function(lua, "starttransaction", &f_lua_starttransaction);
+ get_lua_function(lua, "committransaction", &f_lua_committransaction);
+ get_lua_function(lua, "aborttransaction", &f_lua_aborttransaction);
+ get_lua_function(lua, "feedrecord", &f_lua_feedrecord);
+
+ //supermaster functions....
+ get_lua_function(lua, "supermasterbackend", &f_lua_supermasterbackend);
+ get_lua_function(lua, "createslavedomain", &f_lua_createslavedomain);
+
+ //rediscover
+ get_lua_function(lua, "rediscover", &f_lua_rediscover);
+
+ //dnssec
+ get_lua_function(lua, "alsonotifies", &f_lua_alsonotifies);
+ get_lua_function(lua, "getdomainmetadata", &f_lua_getdomainmetadata);
+ get_lua_function(lua, "setdomainmetadata", &f_lua_setdomainmetadata);
+
+ get_lua_function(lua, "getdomainkeys", &f_lua_getdomainkeys);
+ get_lua_function(lua, "removedomainkey", &f_lua_removedomainkey);
+ get_lua_function(lua, "activatedomainkey", &f_lua_activatedomainkey);
+ get_lua_function(lua, "deactivatedomainkey", &f_lua_deactivatedomainkey);
+ get_lua_function(lua, "updatedomainkey", &f_lua_updatedomainkey);
+ get_lua_function(lua, "adddomainkey", &f_lua_adddomainkey);
+
+ get_lua_function(lua, "gettsigkey", &f_lua_gettsigkey);
+
+ get_lua_function(lua, "getbeforeandafternamesabsolute", &f_lua_getbeforeandafternamesabsolute);
+ get_lua_function(lua, "updatednssecorderandauthabsolute", &f_lua_updatednssecorderandauthabsolute);
+ get_lua_function(lua, "updatednssecorderandauth", &f_lua_updatednssecorderandauth); // not needed...
+
+ }
+ }
+ } else {
+ //a big kaboom here!
+ throw LUAException (backend_name + "LUA OPEN FAILED!");
+ }
+}
+
+void LUABackend::rediscover(string* status) {
+
+ if (f_lua_rediscover == 0)
+ return;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(rediscover) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_rediscover);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TSTRING) {
+ lua_pop(lua, 1 );
+ return;
+ }
+
+ string s = lua_tostring(lua, -1);
+ lua_pop(lua, 1 );
+ *status = s;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(rediscover) END" << endl;
+
+ return;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/*
+
+ virtual bool startTransaction(const string &qname, int id);
+ virtual bool commitTransaction();
+ virtual bool abortTransaction();
+ virtual bool feedRecord(const DNSResourceRecord &rr, string* ordername=0);
+
+ virtual bool getDomainInfo(const string &domain, DomainInfo &di);
+ virtual bool isMaster(const string &name, const string &ip);
+ virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+ virtual void setFresh(uint32_t id);
+*/
+
+bool LUABackend::startTransaction(const DNSName& qname, int id) {
+
+ if (f_lua_starttransaction == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(startTransaction) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_starttransaction);
+
+ lua_pushstring(lua, qname.toString().c_str());
+ lua_pushinteger(lua, id);
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(startTransaction) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::commitTransaction() {
+
+ if (f_lua_committransaction == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(commitTransaction) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_committransaction);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(commitTransaction) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::abortTransaction() {
+
+ if (f_lua_aborttransaction == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(abortTransaction) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_aborttransaction);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(abortTransaction) END" << endl;
+ return ok;
+}
+
+bool LUABackend::feedRecord(const DNSResourceRecord &rr, string *ordername) {
+
+ if (f_lua_feedrecord == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(feedRecord) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_feedrecord);
+ dnsrr_to_table(lua, &rr);
+
+ if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(feedRecord) END" << endl;
+
+ return ok;
+}
+
+void LUABackend::setFresh(uint32_t id) {
+
+ if (f_lua_setfresh == 0)
+ return;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(setFresh) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_setfresh);
+
+ lua_pushinteger(lua, id);
+
+ if(lua_pcall(lua, 1, 0, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return;
+ }
+
+ if (logging)
+ L << Logger::Info << backend_name << "(setFresh) END" << endl;
+
+}
+
+void LUABackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains) {
+
+ if (f_lua_getunfreshslaveinfos == 0)
+ return;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getUnfreshSlaveInfos) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getunfreshslaveinfos);
+
+ if(lua_pcall(lua, 0, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1 );
+ return;
+ }
+
+ domains_from_table(domains, "getUnfreshSlaveInfos");
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getUnfreshSlaveInfos) END" << endl;
+
+}
+
+bool LUABackend::isMaster(const DNSName& domain, const string &ip) {
+
+ if (f_lua_ismaster == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Error << backend_name << "(isMaster) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_ismaster);
+
+ lua_pushstring(lua, domain.toString().c_str());
+ lua_pushstring(lua, ip.c_str());
+
+ if(lua_pcall(lua, 2, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(isMaster) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::getDomainInfo(const DNSName&domain, DomainInfo &di) {
+ if (f_lua_getdomaininfo == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getDomainInfo) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_getdomaininfo);
+
+ lua_pushstring(lua, domain.toString().c_str());
+
+ if(lua_pcall(lua, 1, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ if (returnedwhat != LUA_TTABLE) {
+ lua_pop(lua, 1 );
+ return false;
+ }
+
+ if (logging)
+ L << Logger::Info << backend_name << "(getDomainInfo) END" << endl;
+
+ return domaininfo_from_table(&di);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Fredrik Danerklint
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "luabackend.hh"
+
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+/*
+ //! determine if ip is a supermaster for a domain
+ virtual bool superMasterBackend(const string &ip, const string &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
+
+ //! called by PowerDNS to create a slave record for a superMaster
+ virtual bool createSlaveDomain(const string &ip, const string &domain, const string &nameserver, const string &account)
+
+*/
+
+bool LUABackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db) {
+
+ if (f_lua_supermasterbackend == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(superMasterBackend) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_supermasterbackend);
+
+ lua_pushstring(lua, ip.c_str());
+ lua_pushstring(lua, domain.toString().c_str());
+
+
+ lua_newtable(lua);
+ int c = 0;
+ for(vector<DNSResourceRecord>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
+ c++;
+ lua_pushinteger(lua, c);
+
+ DNSResourceRecord rr;
+
+ rr.qtype = i->qtype;
+ rr.qclass = i->qclass;
+ rr.ttl = i->ttl;
+ rr.auth = i->auth;
+ rr.content = i->content;
+
+ dnsrr_to_table(lua, &rr);
+ lua_settable(lua, -3);
+ }
+
+ if(lua_pcall(lua, 3, 2, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ string a = "";
+ returnedwhat = lua_type(lua, -1);
+ if (returnedwhat == LUA_TSTRING)
+ a = lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ if (ok) {
+ *account = a;
+ *db = this;
+ }
+
+ if (logging)
+ L << Logger::Info << backend_name << "(superMasterBackend) END" << endl;
+
+ return ok;
+}
+
+bool LUABackend::createSlaveDomain(const string &ip, const DNSName& domain, const string &nameserver, const string &account) {
+
+ if (f_lua_createslavedomain == 0)
+ return false;
+
+ if (logging)
+ L << Logger::Info << backend_name << "(createSlaveDomain) BEGIN" << endl;
+
+ lua_rawgeti(lua, LUA_REGISTRYINDEX, f_lua_createslavedomain);
+
+ lua_pushstring(lua, ip.c_str());
+ lua_pushstring(lua, domain.toString().c_str());
+ lua_pushstring(lua, account.c_str());
+
+ if(lua_pcall(lua, 3, 1, f_lua_exec_error) != 0) {
+ string e = backend_name + lua_tostring(lua, -1);
+ lua_pop(lua, 1);
+
+ throw runtime_error(e);
+ return false;
+ }
+
+ size_t returnedwhat = lua_type(lua, -1);
+ bool ok = false;
+
+ if (returnedwhat == LUA_TBOOLEAN)
+ ok = lua_toboolean(lua, -1);
+
+ lua_pop(lua, 1);
+
+ if (logging)
+ L << Logger::Info << backend_name << "(createSlaveDomain) END" << endl;
+
+ return ok;
+}
--- /dev/null
+AM_CPPFLAGS += $(MYSQL_CFLAGS)
+pkglib_LTLIBRARIES = libmydnsbackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ schema.mydns.sql
+
+dist_doc_DATA = schema.mydns.sql
+
+libmydnsbackend_la_SOURCES = \
+ mydnsbackend.cc mydnsbackend.hh
+
+libmydnsbackend_la_LDFLAGS = -module -avoid-version
+libmydnsbackend_la_LIBADD = \
+ ../gmysqlbackend/smysql.lo \
+ $(MYSQL_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/mydnsbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA)
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libmydnsbackend_la_DEPENDENCIES = ../gmysqlbackend/smysql.lo \
+ $(am__DEPENDENCIES_1)
+am_libmydnsbackend_la_OBJECTS = mydnsbackend.lo
+libmydnsbackend_la_OBJECTS = $(am_libmydnsbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libmydnsbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libmydnsbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libmydnsbackend_la_SOURCES)
+DIST_SOURCES = $(libmydnsbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(MYSQL_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libmydnsbackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ schema.mydns.sql
+
+dist_doc_DATA = schema.mydns.sql
+libmydnsbackend_la_SOURCES = \
+ mydnsbackend.cc mydnsbackend.hh
+
+libmydnsbackend_la_LDFLAGS = -module -avoid-version
+libmydnsbackend_la_LIBADD = \
+ ../gmysqlbackend/smysql.lo \
+ $(MYSQL_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/mydnsbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/mydnsbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libmydnsbackend.la: $(libmydnsbackend_la_OBJECTS) $(libmydnsbackend_la_DEPENDENCIES) $(EXTRA_libmydnsbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libmydnsbackend_la_LINK) -rpath $(pkglibdir) $(libmydnsbackend_la_OBJECTS) $(libmydnsbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mydnsbackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+mydnsbackend.lo
--- /dev/null
+$(MYSQL_LIBS)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Jonathan Oddy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/*
+ * The schema used by MyDNS isn't suitable for retrieving results with a single
+ * query. This means that existing PowerDNS backends are unable to make use of
+ * the schema without lame hackery (or awful performance.) This module does
+ * the nasty lookup logic required to make use of the schema, and should be as
+ * tolerant as MyDNS when it comes to things being fully qualified or not.
+ *
+ * A known "bug" is that AXFRs will fail if your rr table contains invalid
+ * junk. I'm not sure this is really a bug, if you've decided to put free-form
+ * text in your data for an A record you have bigger issues.
+ *
+ * I'd advise avoiding the MyDNS schema if at all possible as the query count
+ * for even simple lookups is daft. It's quite trivial to craft a request
+ * that'll require 128 database queries to answer with a servfail!
+ *
+ * If you do not know what mydns is: http://mydns.bboy.net/
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <map>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sstream>
+
+#include "pdns/namespaces.hh"
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "mydnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+
+#include <modules/gmysqlbackend/smysql.hh>
+
+static string backendName="[MyDNSbackend]";
+
+MyDNSBackend::MyDNSBackend(const string &suffix) {
+ setArgPrefix("mydns"+suffix);
+
+ d_domainIdQuery_stmt = NULL;
+ d_domainNoIdQuery_stmt = NULL;
+ d_listQuery_stmt = NULL;
+ d_soaQuery_stmt = NULL;
+ d_basicQuery_stmt = NULL;
+ d_anyQuery_stmt = NULL;
+ d_query_stmt = NULL;
+
+ try {
+ d_db = new SMySQL(getArg("dbname"),
+ getArg("host"),
+ getArgAsNum("port"),
+ getArg("socket"),
+ getArg("user"),
+ getArg("password"));
+ d_db->setLog(::arg().mustDo("query-logging"));
+ }
+ catch(SSqlException &e) {
+ L<<Logger::Error<<backendName<<" Connection failed: "<<e.txtReason()<<endl;
+ throw PDNSException(backendName+"Unable to launch connection: "+e.txtReason());
+ }
+
+ string rrtable=getArg("rr-table");
+ string soatable=getArg("soa-table");
+ string rrwhere=(mustDo("rr-active")?"(active = '1' or active = 'Y') and ":"")+getArg("rr-where");
+ string soawhere=(mustDo("soa-active")?"(active = '1' or active = 'Y') and ":"")+getArg("soa-where");
+
+ if (soatable.empty()) { throw PDNSException("SOA Table must not be empty"); }
+ if (rrtable.empty()) { throw PDNSException("Records table must not be empty"); }
+
+ d_useminimalttl=mustDo("use-minimal-ttl");
+ d_minimum=0;
+
+ L<<Logger::Warning<<backendName<<" Connection successful"<<endl;
+
+ try {
+
+ string domainIdQuery = "SELECT origin, minimum FROM `"+soatable+"` WHERE id = ?";
+ string domainNoIdQuery = "SELECT id, origin, minimum FROM `"+soatable+"` WHERE origin = ?";
+ string soaQuery = "SELECT id, mbox, serial, ns, refresh, retry, expire, minimum, ttl FROM `"+soatable+"` WHERE origin = ?";
+
+ if (!soawhere.empty()) {
+ domainIdQuery += " AND " + soawhere;
+ domainNoIdQuery += " AND " + soawhere;
+ soaQuery += " AND "+soawhere;
+ }
+
+ d_domainIdQuery_stmt = d_db->prepare(domainIdQuery, 1);
+ d_domainNoIdQuery_stmt = d_db->prepare(domainNoIdQuery, 1);
+ d_soaQuery_stmt = d_db->prepare(soaQuery, 1);
+
+ string listQuery = "SELECT type, data, aux, ttl, zone, name FROM `"+rrtable+"` WHERE zone = ?";
+ string basicQuery = "SELECT type, data, aux, ttl, zone FROM `"+rrtable+"` WHERE zone = ? AND (name = ? OR name = ?) AND type = ?";
+ string anyQuery = "(SELECT type, data, aux, ttl, zone FROM `"+rrtable+"` WHERE zone = ? AND (name = ? OR name = ?)";
+
+ if (!rrwhere.empty()) {
+ listQuery += " AND "+rrwhere;
+ basicQuery += " AND " + rrwhere;
+ anyQuery += " AND " + rrwhere;
+ }
+
+ d_listQuery_stmt = d_db->prepare(listQuery, 1);
+
+ anyQuery += ") UNION (SELECT 'SOA' AS type, origin AS data, '0' AS aux, ttl, id AS zone FROM `"+soatable+"` WHERE id = ? AND origin = ?";
+
+ if (!soawhere.empty()) {
+ anyQuery += " AND "+soawhere;
+ }
+
+ basicQuery += " ORDER BY type,aux,data";
+ anyQuery += ") ORDER BY type,aux,data";
+
+ d_basicQuery_stmt = d_db->prepare(basicQuery, 4);
+ d_anyQuery_stmt = d_db->prepare(anyQuery, 5);
+ } catch (SSqlException &e) {
+ L<<Logger::Error<<"Cannot prepare statements: " << e.txtReason() <<endl;
+ throw PDNSException("Cannot prepare statements: " + e.txtReason());
+ }
+}
+
+MyDNSBackend::~MyDNSBackend() {
+ delete d_domainIdQuery_stmt;
+ d_domainIdQuery_stmt = NULL;
+ delete d_domainNoIdQuery_stmt;
+ d_domainNoIdQuery_stmt = NULL;
+ delete d_listQuery_stmt;
+ d_listQuery_stmt = NULL;
+ delete d_soaQuery_stmt;
+ d_soaQuery_stmt = NULL;
+ delete d_basicQuery_stmt;
+ d_basicQuery_stmt = NULL;
+ delete d_anyQuery_stmt;
+ d_anyQuery_stmt = NULL;
+ delete(d_db);
+}
+
+
+bool MyDNSBackend::list(const DNSName &target, int zoneId, bool include_disabled) {
+ string query;
+ string sname;
+ SSqlStatement::row_t rrow;
+
+ try {
+ d_domainIdQuery_stmt->
+ bind("domain_id", zoneId)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to list domain_id "+itoa(zoneId)+": "+e.txtReason());
+ }
+
+ if (d_result.empty())
+ return false; // No such zone
+
+ d_origin = d_result[0][0];
+ if (d_origin[d_origin.length()-1] == '.')
+ d_origin.erase(d_origin.length()-1);
+ d_minimum = pdns_stou(d_result[0][1]);
+
+ if (d_result.size()>1) {
+ L<<Logger::Warning<<backendName<<" Found more than one matching origin for zone ID: "<<zoneId<<endl;
+ };
+
+ try {
+ d_query_stmt = d_listQuery_stmt;
+ d_query_stmt->
+ bind("domain_id", zoneId)->
+ execute();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to list domain_id "+itoa(zoneId)+": "+e.txtReason());
+ }
+
+ d_qname = "";
+ return true;
+}
+
+bool MyDNSBackend::getSOA(const DNSName& name, SOAData& soadata, DNSPacket*) {
+ string query;
+ SSqlStatement::row_t rrow;
+
+ if (name.empty())
+ return false;
+
+ try {
+ d_soaQuery_stmt->
+ bind("origin", name.toString())->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to get soa for domain "+name.toString()+": "+e.txtReason());
+ }
+
+ if (d_result.empty()) {
+ return false;
+ }
+
+ rrow = d_result[0];
+
+ soadata.qname = name;
+ soadata.domain_id = pdns_stou(rrow[0]);
+ soadata.hostmaster = DNSName(rrow[1]);
+ soadata.serial = pdns_stou(rrow[2]);
+ soadata.nameserver = DNSName(rrow[3]);
+ soadata.refresh = pdns_stou(rrow[4]);
+ soadata.retry = pdns_stou(rrow[5]);
+ soadata.expire = pdns_stou(rrow[6]);
+ soadata.default_ttl = pdns_stou(rrow[7]);
+ soadata.ttl = pdns_stou(rrow[8]);
+ if (d_useminimalttl) {
+ soadata.ttl = std::min(soadata.ttl, soadata.default_ttl);
+ }
+ soadata.db = this;
+
+ if (d_result.size()>1) {
+ L<<Logger::Warning<<backendName<<" Found more than one matching zone for: "<<name<<endl;
+ };
+
+ return true;
+}
+
+void MyDNSBackend::lookup(const QType &qtype, const DNSName &qname, DNSPacket *p, int zoneId) {
+ SSqlStatement::row_t rrow;
+ bool found = false;
+
+ DNSName sdom(qname);
+ d_origin = "";
+
+ if (qname.empty()) {
+ return;
+ }
+
+ DLOG(L<<Logger::Debug<<"MyDNSBackend::lookup(" << qtype.getName() << "," << qname << ",p," << zoneId << ")" << endl);
+
+ if (zoneId < 0) {
+ // First off we need to work out what zone we're working with
+ // MyDNS records aren't always fully qualified, so we need to work out the zone ID.
+
+
+ do {
+ try {
+ d_domainNoIdQuery_stmt->
+ bind("domain", sdom.toString())->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+qname.toString()+": "+e.txtReason());
+ }
+
+ if (d_result.empty() == false) {
+ rrow = d_result[0];
+ zoneId = pdns_stou(rrow[0]);
+ d_origin = stripDot(rrow[1]);
+ d_minimum = pdns_stou(rrow[2]);
+ found = true;
+ break;
+ }
+
+ } while(sdom.chopOff());
+
+ } else {
+ try {
+ d_domainIdQuery_stmt->
+ bind("domain_id", zoneId)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+qname.toString()+": "+e.txtReason());
+ }
+
+ if(d_result.empty()) {
+ return; // just return if zone was not found instead of throwing an error
+ }
+
+ rrow = d_result[0];
+
+ found = true;
+ d_origin = stripDot(rrow[0]);
+ d_minimum = pdns_stou(rrow[1]);
+ }
+
+ if (found) {
+
+ while (d_result.size()>1) {
+ L<<Logger::Warning<<backendName<<" Found more than one matching zone for: "+d_origin<<endl;
+ };
+ // We found the zoneId, so we can work out how to find our rr
+ string host;
+
+ // The host part of the query is the name less the origin
+ DNSName origin(d_origin);
+ host = qname.makeRelative(origin).toStringNoDot();
+
+ try {
+
+ if (qtype.getCode()==QType::ANY) {
+ DLOG(L<<Logger::Debug<<"Running d_anyQuery_stmt with " << zoneId << ", " << host << ", " << sdom << ", " << zoneId <<" , "<< qname << ", " << qtype.getName() << endl);
+ d_query_stmt = d_anyQuery_stmt;
+ d_query_stmt->
+ bind("domain_id", zoneId)->
+ bind("host", host)->
+ bind("qname", qname.toString())->
+ bind("domain_id", zoneId)-> // this is because positional arguments
+ bind("qname2", sdom.toString())->
+ execute();
+ } else {
+ DLOG(L<<Logger::Debug<<"Running d_basicQuery_stmt with " << zoneId << ", " << host << ", " << qname << ", " << qtype.getName() << endl);
+ d_query_stmt = d_basicQuery_stmt;
+ d_query_stmt->
+ bind("domain_id", zoneId)->
+ bind("host", host)->
+ bind("qname", qname.toString())->
+ bind("qtype", qtype.getName())->
+ execute();
+ }
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+qname.toString()+": "+e.txtReason());
+ }
+
+ d_qname = qname.toString();
+ }
+
+}
+
+bool MyDNSBackend::get(DNSResourceRecord &rr) {
+ if (d_origin.empty()) {
+ if (d_query_stmt) {
+ try {
+ d_query_stmt->reset();
+ } catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason());
+ }
+ d_query_stmt = NULL;
+ }
+ // This happens if lookup() couldn't find the zone
+ return false;
+ }
+
+ SSqlStatement::row_t rrow;
+
+ if (d_query_stmt->hasNextRow()) {
+ try {
+ d_query_stmt->nextRow(rrow);
+ } catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason());
+ }
+ rr.qtype=rrow[0];
+ rr.content = rrow[1];
+
+ if(!d_qname.empty()) {
+ // use this to distinguish between select with 'name' field (list()) and one without
+ rr.qname=DNSName(d_qname);
+ } else {
+ string tmpQname = rrow[5];
+
+ //TODO: Refactor
+ if (!tmpQname.empty() && tmpQname[tmpQname.length()-1] == '.') {
+ tmpQname.erase(tmpQname.length()-1); // Fully qualified, nuke the last .
+ } else {
+ if (!tmpQname.empty()) {
+ tmpQname += ".";
+ }
+ tmpQname += d_origin; // Not fully qualified
+ }
+ rr.qname = DNSName(tmpQname);
+ }
+
+ if (rr.qtype.getCode() == QType::NS || rr.qtype.getCode()==QType::MX ||
+ rr.qtype.getCode() == QType::CNAME || rr.qtype.getCode() == QType::PTR) {
+ if (!rr.content.empty() && rr.content[rr.content.length()-1] == '.') {
+ if (rr.content.length() > 1)
+ rr.content.erase(rr.content.length()-1); // Fully qualified, nuke the last .
+ } else {
+ if (rr.content != ".")
+ rr.content += ".";
+ rr.content += d_origin;
+ }
+ }
+
+ if (rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::SRV)
+ rr.content=rrow[2]+" "+rr.content;
+
+ rr.ttl = pdns_stou(rrow[3]);
+ if (d_useminimalttl)
+ rr.ttl = std::min(rr.ttl, d_minimum);
+ rr.domain_id=pdns_stou(rrow[4]);
+
+ rr.last_modified=0;
+
+ return true;
+ }
+
+ try {
+ d_query_stmt->reset();
+ } catch (SSqlException &e) {
+ throw PDNSException("MyDNSBackend unable to lookup "+d_qname+": "+e.txtReason());
+ }
+
+ d_query_stmt = NULL;
+
+ return false;
+}
+
+class MyDNSFactory : public BackendFactory {
+
+public:
+ MyDNSFactory() : BackendFactory("mydns") {}
+
+ void declareArguments(const string &suffix = "") {
+ declare(suffix,"dbname","Pdns backend database name to connect to","mydns");
+ declare(suffix,"user","Pdns backend user to connect as","powerdns");
+ declare(suffix,"host","Pdns backend host to connect to","");
+ declare(suffix,"port","Pdns backend host to connect to","");
+ declare(suffix,"password","Pdns backend password to connect with","");
+ declare(suffix,"socket","Pdns backend socket to connect to","");
+ declare(suffix,"rr-table","Name of RR table to use","rr");
+ declare(suffix,"soa-table","Name of SOA table to use","soa");
+ declare(suffix,"soa-where","Additional WHERE clause for SOA","1 = 1");
+ declare(suffix,"rr-where","Additional WHERE clause for RR","1 = 1");
+ declare(suffix,"soa-active","Use the active column in the SOA table","yes");
+ declare(suffix,"rr-active","Use the active column in the RR table","yes");
+ declare(suffix,"use-minimal-ttl","Setting this to 'yes' will make the backend behave like MyDNS on the TTL values. Setting it to 'no' will make it ignore the minimal-ttl of the zone.","yes");
+ }
+
+ DNSBackend *make(const string &suffix="") {
+ return new MyDNSBackend(suffix);
+ }
+
+};
+
+class MyDNSLoader {
+
+public:
+ MyDNSLoader() {
+ BackendMakers().report(new MyDNSFactory());
+ L << Logger::Info << "[mydnsbackend] This is the mydns backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static MyDNSLoader mydnsloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Jonathan Oddy
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef MYDNSBACKEND_HH
+#define MYDNSBACKEND_HH
+
+#include <string>
+#include <map>
+
+#include "pdns/namespaces.hh"
+
+#include <modules/gmysqlbackend/smysql.hh>
+
+class MyDNSBackend : public DNSBackend
+{
+public:
+ MyDNSBackend(const string &suffix);
+ ~MyDNSBackend();
+
+ void lookup(const QType &, const DNSName &qdomain, DNSPacket *p=0, int zoneId=-1);
+ bool list(const DNSName &target, int domain_id, bool include_disabled=false);
+ bool get(DNSResourceRecord &r);
+ bool getSOA(const DNSName& name, SOAData& soadata, DNSPacket*);
+
+private:
+ SMySQL *d_db;
+
+ string d_qname;
+ string d_origin;
+ bool d_useminimalttl;
+ unsigned int d_minimum;
+
+ SSqlStatement::result_t d_result;
+
+ SSqlStatement* d_query_stmt;
+ SSqlStatement* d_domainIdQuery_stmt;
+ SSqlStatement* d_domainNoIdQuery_stmt;
+ SSqlStatement* d_listQuery_stmt;
+ SSqlStatement* d_soaQuery_stmt;
+ SSqlStatement* d_basicQuery_stmt;
+ SSqlStatement* d_anyQuery_stmt;
+};
+
+#endif /* MYDNSBACKEND_HH */
--- /dev/null
+--
+-- Table layouts for mydns 1.2.8.31 (Dec 2014)
+-- Copyright (C) 2002-2005 Don Moore 2007-2008 Howard Wilkinson
+--
+-- You might create these tables with a command like:
+--
+-- $ mydns --create-tables | mysql -hHOST -p -uUSER DATABASE
+--
+-- Originally licensed under the GNU GPLv2 or higer
+
+--
+-- Table structure for table 'soa' (zones of authority)
+--
+CREATE TABLE IF NOT EXISTS soa (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ origin CHAR(255) NOT NULL,
+ ns CHAR(255) NOT NULL,
+ mbox CHAR(255) NOT NULL,
+ serial INT UNSIGNED NOT NULL default '1',
+ refresh INT UNSIGNED NOT NULL default '28800',
+ retry INT UNSIGNED NOT NULL default '7200',
+ expire INT UNSIGNED NOT NULL default '604800',
+ minimum INT UNSIGNED NOT NULL default '86400',
+ ttl INT UNSIGNED NOT NULL default '86400',
+ active ENUM('Y', 'N') NOT NULL DEFAULT 'Y',
+ UNIQUE KEY (origin)
+) Engine=MyISAM;
+
+--
+-- Table structure for table 'rr' (resource records)
+--
+CREATE TABLE IF NOT EXISTS rr (
+ id INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY,
+ zone INT UNSIGNED NOT NULL,
+ name CHAR(200) NOT NULL,
+ data VARBINARY(128) NOT NULL,
+ aux INT UNSIGNED NOT NULL,
+ ttl INT UNSIGNED NOT NULL default '86400',
+ type ENUM('A','AAAA','CNAME','HINFO','MX','NAPTR','NS','PTR','RP','SRV','TXT'),
+ active ENUM('Y', 'N') NOT NULL DEFAULT 'Y',
+ UNIQUE KEY rr (zone,name,type,data,aux,active)
+) Engine=MyISAM;
--- /dev/null
+pkglib_LTLIBRARIES = libopendbxbackend.la
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+libopendbxbackend_la_SOURCES = \
+ odbxbackend.cc odbxbackend.hh \
+ odbxprivate.cc
+
+libopendbxbackend_la_LDFLAGS = -module -avoid-version
+libopendbxbackend_la_LIBADD = $(OPENDBX_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/opendbxbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp README
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libopendbxbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libopendbxbackend_la_OBJECTS = odbxbackend.lo odbxprivate.lo
+libopendbxbackend_la_OBJECTS = $(am_libopendbxbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libopendbxbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libopendbxbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libopendbxbackend_la_SOURCES)
+DIST_SOURCES = $(libopendbxbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libopendbxbackend.la
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+libopendbxbackend_la_SOURCES = \
+ odbxbackend.cc odbxbackend.hh \
+ odbxprivate.cc
+
+libopendbxbackend_la_LDFLAGS = -module -avoid-version
+libopendbxbackend_la_LIBADD = $(OPENDBX_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/opendbxbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/opendbxbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libopendbxbackend.la: $(libopendbxbackend_la_OBJECTS) $(libopendbxbackend_la_DEPENDENCIES) $(EXTRA_libopendbxbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libopendbxbackend_la_LINK) -rpath $(pkglibdir) $(libopendbxbackend_la_OBJECTS) $(libopendbxbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odbxbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/odbxprivate.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+odbxbackend.lo odbxprivate.lo
--- /dev/null
+$(OPENDBX_LIBS)
--- /dev/null
+For more information, see
+http://wiki.linuxnetworks.de/doc/index.php/PowerDNS_OpenDBX_Backend
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "odbxbackend.hh"
+
+
+
+inline string& strbind( const string& search, const string& replace, string& subject )
+{
+ size_t pos = 0;
+
+ while( ( pos = subject.find( search, pos ) ) != string::npos )
+ {
+ subject.replace( pos, search.size(), replace );
+ pos += replace.size();
+ }
+
+ return subject;
+}
+
+
+
+OdbxBackend::OdbxBackend( const string& suffix )
+{
+ vector<string> hosts;
+
+
+ try
+ {
+ m_result = NULL;
+ m_handle[READ] = NULL;
+ m_handle[WRITE] = NULL;
+ m_myname = "[OpendbxBackend]";
+ m_default_ttl = arg().asNum( "default-ttl" );
+ m_qlog = arg().mustDo( "query-logging" );
+
+ setArgPrefix( "opendbx" + suffix );
+
+ if( getArg( "host" ).size() > 0 )
+ {
+ L.log( m_myname + " WARNING: Using deprecated opendbx-host parameter", Logger::Warning );
+ stringtok( m_hosts[READ], getArg( "host" ), ", " );
+ m_hosts[WRITE] = m_hosts[READ];
+ }
+ else
+ {
+ stringtok( m_hosts[READ], getArg( "host-read" ), ", " );
+ stringtok( m_hosts[WRITE], getArg( "host-write" ), ", " );
+ }
+
+ if( !connectTo( m_hosts[READ], READ ) ) { throw( PDNSException( "Fatal: Connecting to server for reading failed" ) ); }
+ if( !connectTo( m_hosts[WRITE], WRITE ) ) { throw( PDNSException( "Fatal: Connecting to server for writing failed" ) ); }
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " OdbxBackend(): Caught STL exception - " + e.what(), Logger::Error );
+ throw( PDNSException( "Fatal: STL exception" ) );
+ }
+}
+
+
+
+OdbxBackend::~OdbxBackend()
+{
+ odbx_unbind( m_handle[WRITE] );
+ odbx_unbind( m_handle[READ] );
+
+ odbx_finish( m_handle[WRITE] );
+ odbx_finish( m_handle[READ] );
+}
+
+
+
+bool OdbxBackend::getDomainInfo( const DNSName& domain, DomainInfo& di )
+{
+ const char* tmp;
+
+
+ try
+ {
+ DLOG( L.log( m_myname + " getDomainInfo()", Logger::Debug ) );
+
+ string stmt = getArg( "sql-zoneinfo" );
+ string& stmtref = strbind( ":name", escape( domain.makeLowerCase().toStringRootDot(), READ ), stmt );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
+ if( !getRecord( READ ) ) { return false; }
+
+ do
+ {
+ di.id = 0;
+ di.zone.clear();
+ di.masters.clear();
+ di.last_check = 0;
+ di.notified_serial = 0;
+ di.kind = DomainInfo::Native;
+ di.backend = this;
+ di.serial = 0;
+
+ if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
+ {
+ SOAData sd;
+
+ sd.serial = 0;
+ fillSOAData( string( tmp, odbx_field_length( m_result, 6 ) ), sd );
+
+ if( sd.serial == 0 && ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+ {
+ sd.serial = strtol( tmp, NULL, 10 );
+ }
+
+ di.serial = sd.serial;
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
+ {
+ di.last_check = strtol( tmp, NULL, 10 );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+ {
+ stringtok(di.masters, string( tmp, odbx_field_length( m_result, 3 ) ), ", \t");
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+ {
+ if( !strncmp( tmp, "SLAVE", 5 ) )
+ {
+ di.kind = DomainInfo::Slave;
+ }
+ else if( !strncmp( tmp, "MASTER", 6 ) )
+ {
+ di.kind = DomainInfo::Master;
+ }
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+ {
+ di.zone = DNSName(string( tmp, odbx_field_length( m_result, 1 ) ));
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+ {
+ di.id = strtol( tmp, NULL, 10 );
+ }
+ }
+ while( getRecord( READ ) );
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " getDomainInfo: Caught STL std::exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::getSOA( const DNSName& domain, SOAData& sd, DNSPacket* p )
+{
+ const char* tmp;
+
+
+ try
+ {
+ DLOG( L.log( m_myname + " getSOA()", Logger::Debug ) );
+
+ string stmt = getArg( "sql-lookupsoa" );
+ string& stmtref = strbind( ":name", escape( domain.makeLowerCase().toStringRootDot(), READ ), stmt );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
+ if( !getRecord( READ ) ) { return false; }
+
+ do
+ {
+ sd.qname = domain;
+ sd.serial = 0;
+ sd.ttl = m_default_ttl;
+
+ if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+ {
+ fillSOAData( string( tmp, odbx_field_length( m_result, 3 ) ), sd );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+ {
+ sd.ttl = strtoul( tmp, NULL, 10 );
+ }
+
+ if( sd.serial == 0 && ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+ {
+ sd.serial = strtol( tmp, NULL, 10 );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+ {
+ sd.domain_id = strtol( tmp, NULL, 10 );
+ }
+
+ if( sd.nameserver.empty() )
+ {
+ sd.nameserver = DNSName(arg()["default-soa-name"]);
+ }
+
+ if( sd.hostmaster.empty() )
+ {
+ sd.hostmaster = DNSName("hostmaster") + DNSName(domain);
+ }
+
+ sd.db = this;
+ }
+ while( getRecord( READ ) );
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " getSOA: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::list( const DNSName& target, int zoneid, bool include_disabled )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " list()", Logger::Debug ) );
+
+ m_qname.clear();
+ m_result = NULL;
+
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " list: Unable to convert zone id to string - format error", Logger::Error );
+ return false;
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " list: Unable to convert zone id to string - insufficient buffer space", Logger::Error );
+ return false;
+ }
+
+ string stmt = getArg( "sql-list" );
+ string& stmtref = strbind( ":id", string( m_buffer, len ), stmt );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " list: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+void OdbxBackend::lookup( const QType& qtype, const DNSName& qname, DNSPacket* dnspkt, int zoneid )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " lookup()", Logger::Debug ) );
+
+ string stmt;
+ string& stmtref = stmt;
+
+ m_result = NULL;
+ m_qname = qname;
+
+ if( zoneid < 0 )
+ {
+ if( qtype.getCode() == QType::ANY )
+ {
+ stmt = getArg( "sql-lookup" );
+ } else {
+ stmt = getArg( "sql-lookuptype" );
+ stmtref = strbind( ":type", qtype.getName(), stmt );
+ }
+ }
+ else
+ {
+ if( qtype.getCode() == QType::ANY )
+ {
+ stmt = getArg( "sql-lookupid" );
+ } else {
+ stmt = getArg( "sql-lookuptypeid" );
+ stmtref = strbind( ":type", qtype.getName(), stmt );
+ }
+
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " lookup: Unable to convert zone id to string - format error", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " lookup: Unable to convert zone id to string - insufficient buffer space", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ stmtref = strbind( ":id", string( m_buffer, len ), stmtref );
+ }
+
+ stmtref = strbind( ":name", escape( qname.makeLowerCase().toStringRootDot(), READ ), stmtref );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) )
+ {
+ throw( DBException( "Error: DB statement failed" ) );
+ }
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " lookup: Caught STL exception - " + e.what(), Logger::Error );
+ throw( DBException( "Error: STL exception" ) );
+ }
+}
+
+
+
+bool OdbxBackend::get( DNSResourceRecord& rr )
+{
+ const char* tmp;
+ string priority;
+
+ try
+ {
+ DLOG( L.log( m_myname + " get()", Logger::Debug ) );
+
+ if( getRecord( READ ) )
+ {
+
+ rr.content = "";
+ rr.domain_id = 0;
+ rr.last_modified = 0;
+ rr.ttl = m_default_ttl;
+ rr.qname = m_qname;
+
+ if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+ {
+ rr.domain_id = strtol( tmp, NULL, 10 );
+ }
+
+ if( m_qname.empty() && ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+ {
+ rr.qname = DNSName( string(tmp, odbx_field_length( m_result, 1 ) ));
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+ {
+ rr.qtype = tmp;
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+ {
+ rr.ttl = strtoul( tmp, NULL, 10 );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
+ {
+ priority = string( tmp, odbx_field_length( m_result, 4 ) );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+ {
+ rr.content = string( tmp, odbx_field_length( m_result, 5 ) );
+ }
+
+ if (rr.qtype==QType::MX || rr.qtype==QType::SRV)
+ rr.content = priority + " " + rr.content;
+
+ return true;
+ }
+ }
+ catch( std::exception& e )
+ {
+ L.log( m_myname + " get: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return false;
+}
+
+
+void OdbxBackend::setFresh( uint32_t domain_id )
+{
+ int len;
+
+
+ try
+ {
+ DLOG( L.log( m_myname + " setFresh()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " setFresh: Master server is unreachable", Logger::Error );
+ throw( DBException( "Error: Server unreachable" ) );
+ }
+
+ len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-lastcheck" ).c_str(), time( 0 ), domain_id );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - format error", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " setFresh: Unable to insert values into statement '" + getArg( "sql-update-lastcheck" ) + "' - insufficient buffer space", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ if( !execStmt( m_buffer, len, WRITE ) )
+ {
+ throw( DBException( "Error: DB statement failed" ) );
+ }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " setFresh: Caught STL exception - " + e.what(), Logger::Error );
+ throw( DBException( "Error: STL exception" ) );
+ }
+}
+
+
+
+void OdbxBackend::setNotified( uint32_t domain_id, uint32_t serial )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " setNotified()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " setFresh: Master server is unreachable", Logger::Error );
+ throw( DBException( "Error: Server unreachable" ) );
+ }
+
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-update-serial" ).c_str(), serial, domain_id );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - format error", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " setNotified: Unable to insert values into statement '" + getArg( "sql-update-serial" ) + "' - insufficient buffer space", Logger::Error );
+ throw( DBException( "Error: Libc error" ) );
+ }
+
+ if( !execStmt( m_buffer, len, WRITE ) )
+ {
+ throw( DBException( "Error: DB statement failed" ) );
+ }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " setNotified: Caught STL exception - " + e.what(), Logger::Error );
+ throw( DBException( "Error: STL exception" ) );
+ }
+}
+
+
+
+bool OdbxBackend::isMaster( const DNSName& domain, const string& ip )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " isMaster()", Logger::Debug ) );
+
+ string stmt = getArg( "sql-master" );
+ string& stmtref = strbind( ":name", escape( domain.makeLowerCase().toStringRootDot(), READ ), stmt );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
+ if( !getRecord( READ ) ) { return false; }
+
+ do
+ {
+ if( odbx_field_value( m_result, 0 ) != NULL )
+ {
+ if( !strcmp( odbx_field_value( m_result, 0 ), ip.c_str() ) )
+ {
+ while( getRecord( READ ) );
+ return true;
+ }
+ }
+ }
+ while( getRecord( READ ) );
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " isMaster: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return false;
+}
+
+
+
+void OdbxBackend::getUnfreshSlaveInfos( vector<DomainInfo>* unfresh )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " getUnfreshSlaveInfos()", Logger::Debug ) );
+
+ if( unfresh == NULL )
+ {
+ L.log( m_myname + " getUnfreshSlaveInfos: invalid parameter - NULL pointer", Logger::Error );
+ return;
+ }
+
+ getDomainList( getArg( "sql-infoslaves" ), unfresh, &checkSlave );
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " getUnfreshSlaveInfo: Caught STL exception - " + e.what(), Logger::Error );
+ }
+}
+
+
+
+void OdbxBackend::getUpdatedMasters( vector<DomainInfo>* updated )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " getUpdatedMasters()", Logger::Debug ) );
+
+ if( updated == NULL )
+ {
+ L.log( m_myname + " getUpdatedMasters: invalid parameter - NULL pointer", Logger::Error );
+ return;
+ }
+
+ getDomainList( getArg( "sql-infomasters" ), updated, &checkMaster );
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " getUpdatedMasters: Caught STL exception - " + e.what(), Logger::Error );
+ }
+}
+
+
+
+bool OdbxBackend::superMasterBackend( const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& set, string *nameserver, string* account, DNSBackend** ddb )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " superMasterBackend()", Logger::Debug ) );
+
+ if( account != NULL && ddb != NULL )
+ {
+ vector<DNSResourceRecord>::const_iterator i;
+
+ for( i = set.begin(); i != set.end(); i++ )
+ {
+ string stmt = getArg( "sql-supermaster" );
+ string& stmtref = strbind( ":ip", escape( ip, READ ), stmt );
+ stmtref = strbind( ":ns", escape( i->content, READ ), stmtref );
+
+ if( !execStmt( stmtref.c_str(), stmtref.size(), READ ) ) { return false; }
+
+ if( getRecord( READ ) )
+ {
+ if( odbx_field_value( m_result, 0 ) != NULL )
+ {
+ *account = string( odbx_field_value( m_result, 0 ), odbx_field_length( m_result, 0 ) );
+ }
+
+ while( getRecord( READ ) );
+
+ *ddb=this;
+ return true;
+ }
+ }
+ }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " superMasterBackend: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return false;
+}
+
+
+
+bool OdbxBackend::createSlaveDomain( const string& ip, const DNSName& domain, const string &nameserver, const string& account )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " createSlaveDomain()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " createSlaveDomain: Master server is unreachable", Logger::Error );
+ return false;
+ }
+
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-slave" ).c_str(), escape( domain.makeLowerCase().toStringRootDot(), WRITE ).c_str(),
+ escape( ip, WRITE ).c_str(), escape( account, WRITE ).c_str() );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - format error", Logger::Error );
+ return false;
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " createSlaveDomain: Unable to insert values in statement '" + getArg( "sql-insert-slave" ) + "' - insufficient buffer space", Logger::Error );
+ return false;
+ }
+
+ if( !execStmt( m_buffer, len, WRITE ) ) { return false; }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " createSlaveDomain: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::feedRecord( const DNSResourceRecord& rr, string *ordername )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " feedRecord()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " feedRecord: Master server is unreachable", Logger::Error );
+ return false;
+ }
+
+ unsigned int priority=0;
+ string content(rr.content);
+
+ if(rr.qtype == QType::MX || rr.qtype == QType::SRV) {
+ priority=pdns_stou(content);
+ string::size_type pos = content.find_first_not_of("0123456789");
+ if(pos != string::npos)
+ boost::erase_head(content, pos);
+ trim_left(content);
+ }
+
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, getArg( "sql-insert-record" ).c_str(), rr.domain_id,
+ escape( rr.qname.makeLowerCase().toStringRootDot(), WRITE ).c_str(), rr.qtype.getName().c_str(), rr.ttl, priority,
+ escape( content, WRITE ).c_str() );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - format error", Logger::Error );
+ return false;
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " feedRecord: Unable to insert values in statement '" + getArg( "sql-insert-record" ) + "' - insufficient buffer space", Logger::Error );
+ return false;
+ }
+
+ if( !execStmt( m_buffer, len, WRITE ) ) { return false; }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " feedRecord: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::startTransaction( const DNSName& domain, int zoneid )
+{
+ try
+ {
+ DLOG( L.log( m_myname + " startTransaction()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " startTransaction: Master server is unreachable", Logger::Error );
+ return false;
+ }
+
+ string stmtref = getArg( "sql-transactbegin" );
+ if( !execStmt( stmtref.c_str(), stmtref.size(), WRITE ) ) { return false; }
+ int len = snprintf( m_buffer, sizeof( m_buffer ) - 1, "%d", zoneid );
+
+ if( len < 0 )
+ {
+ L.log( m_myname + " startTransaction: Unable to convert zone id to string - format error", Logger::Error );
+ return false;
+ }
+
+ if( len > static_cast<int>(sizeof( m_buffer )) - 1 )
+ {
+ L.log( m_myname + " startTransaction: Unable to convert zone id to string - insufficient buffer space", Logger::Error );
+ return false;
+ }
+
+ if(zoneid >= 0) {
+ string stmt = getArg( "sql-zonedelete" );
+ stmtref = strbind( ":id", string( m_buffer, len ), stmt );
+ if( !execStmt( stmtref.c_str(), stmtref.size(), WRITE ) ) { return false; }
+ }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " startTransaction: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::commitTransaction()
+{
+ try
+ {
+ DLOG( L.log( m_myname + " commitTransaction()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " commitTransaction: Master server is unreachable", Logger::Error );
+ return false;
+ }
+
+ const string& stmt = getArg( "sql-transactend" );
+ if( !execStmt( stmt.c_str(), stmt.size(), WRITE ) ) { return false; }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " commitTransaction: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::abortTransaction()
+{
+ try
+ {
+ DLOG( L.log( m_myname + " abortTransaction()", Logger::Debug ) );
+
+ if( !m_handle[WRITE] && !connectTo( m_hosts[WRITE], WRITE ) )
+ {
+ L.log( m_myname + " abortTransaction: Master server is unreachable", Logger::Error );
+ return false;
+ }
+
+ const string& stmt = getArg( "sql-transactabort" );
+ if( !execStmt( stmt.c_str(), stmt.size(), WRITE ) ) { return false; }
+ }
+ catch ( std::exception& e )
+ {
+ L.log( m_myname + " abortTransaction: Caught STL exception - " + e.what(), Logger::Error );
+ return false;
+ }
+
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Norbert Sendetzky
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <string>
+#include <cstdlib>
+#include <sstream>
+#include <sys/time.h>
+#include "pdns/dns.hh"
+#include "pdns/utility.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/arguments.hh"
+#include "pdns/logger.hh"
+#include <odbx.h>
+
+
+#ifndef ODBXBACKEND_HH
+#define ODBXBACKEND_HH
+
+
+#define BUFLEN 512
+
+
+using std::string;
+using std::vector;
+
+
+
+bool checkSlave( uint32_t last, uint32_t notified, SOAData* sd, DomainInfo* di );
+bool checkMaster( uint32_t last, uint32_t notified, SOAData* sd, DomainInfo* di );
+
+
+class OdbxBackend : public DNSBackend
+{
+ enum QueryType { READ, WRITE };
+
+ string m_myname;
+ DNSName m_qname;
+ int m_default_ttl;
+ bool m_qlog;
+ odbx_t* m_handle[2];
+ odbx_result_t* m_result;
+ char m_escbuf[BUFLEN];
+ char m_buffer[2*BUFLEN];
+ vector<string> m_hosts[2];
+
+ string escape( const string& str, QueryType type );
+ bool connectTo( const vector<string>& host, QueryType type );
+ bool getDomainList( const string& query, vector<DomainInfo>* list, bool (*check_fcn)(uint32_t,uint32_t,SOAData*,DomainInfo*) );
+ bool execStmt( const char* stmt, unsigned long length, QueryType type );
+ bool getRecord( QueryType type );
+
+
+public:
+
+ OdbxBackend( const string& suffix="" );
+ ~OdbxBackend();
+
+ void lookup( const QType& qtype, const DNSName& qdomain, DNSPacket* p = 0, int zoneid = -1 );
+ bool getSOA( const DNSName& domain, SOAData& sd, DNSPacket* p );
+ bool list( const DNSName& target, int domain_id, bool include_disabled=false );
+ bool get( DNSResourceRecord& rr );
+
+ bool startTransaction( const DNSName& domain, int domain_id ) override;
+ bool commitTransaction() override;
+ bool abortTransaction() override;
+
+ bool isMaster( const DNSName& domain, const string& ip ) override;
+ bool getDomainInfo( const DNSName& domain, DomainInfo& di ) override;
+ bool feedRecord( const DNSResourceRecord& rr, string *ordername=0 ) override;
+ bool createSlaveDomain( const string& ip, const DNSName& domain, const string &nameserver, const string& account ) override;
+ bool superMasterBackend( const string& ip, const DNSName& domain, const vector<DNSResourceRecord>& nsset, string *nameserver, string* account, DNSBackend** ddb ) override;
+
+ void getUpdatedMasters( vector<DomainInfo>* updated );
+ void getUnfreshSlaveInfos( vector<DomainInfo>* unfresh );
+
+ void setFresh( uint32_t domain_id );
+ void setNotified( uint32_t domain_id, uint32_t serial );
+};
+
+
+
+class OdbxFactory : public BackendFactory
+{
+
+public:
+
+ OdbxFactory() : BackendFactory( "opendbx" ) {}
+
+
+ void declareArguments( const string &suffix="" )
+ {
+ declare( suffix, "backend", "OpenDBX backend","mysql" );
+ declare( suffix, "host-read", "Name or address of one or more DBMS server to read from","127.0.0.1" );
+ declare( suffix, "host-write", "Name or address of one or more DBMS server used for updates","127.0.0.1" );
+ declare( suffix, "port", "Port the DBMS server are listening to","" );
+ declare( suffix, "database", "Database name containing the DNS records","powerdns" );
+ declare( suffix, "username","User for connecting to the DBMS","powerdns");
+ declare( suffix, "password","Password for connecting to the DBMS","");
+
+ declare( suffix, "sql-list", "AXFR query", "SELECT r.\"domain_id\", r.\"name\", r.\"type\", r.\"ttl\", r.\"prio\", r.\"content\" FROM \"records\" r WHERE r.\"domain_id\"=:id" );
+
+ declare( suffix, "sql-lookup", "Lookup query","SELECT r.\"domain_id\", r.\"name\", r.\"type\", r.\"ttl\", r.\"prio\", r.\"content\" FROM \"records\" r WHERE r.\"name\"=':name'" );
+ declare( suffix, "sql-lookupid", "Lookup query with id","SELECT r.\"domain_id\", r.\"name\", r.\"type\", r.\"ttl\", r.\"prio\", r.\"content\" FROM \"records\" r WHERE r.\"domain_id\"=:id AND r.\"name\"=':name'" );
+ declare( suffix, "sql-lookuptype", "Lookup query with type","SELECT r.\"domain_id\", r.\"name\", r.\"type\", r.\"ttl\", r.\"prio\", r.\"content\" FROM \"records\" r WHERE r.\"name\"=':name' AND r.\"type\"=':type'" );
+ declare( suffix, "sql-lookuptypeid", "Lookup query with type and id","SELECT r.\"domain_id\", r.\"name\", r.\"type\", r.\"ttl\", r.\"prio\", r.\"content\" FROM \"records\" r WHERE r.\"domain_id\"=:id AND r.\"name\"=':name' AND r.\"type\"=':type'" );
+ declare( suffix, "sql-lookupsoa","Lookup query for SOA record","SELECT d.\"id\", d.\"auto_serial\", r.\"ttl\", r.\"content\" FROM \"records\" r JOIN \"domains\" d ON r.\"domain_id\"=d.\"id\" WHERE r.\"name\"=':name' AND r.\"type\"='SOA' AND d.\"status\"='A'" );
+
+ declare( suffix, "sql-zonedelete","Delete all records for this zone","DELETE FROM \"records\" WHERE \"domain_id\"=:id" );
+ declare( suffix, "sql-zoneinfo","Get domain info","SELECT d.\"id\", d.\"name\", d.\"type\", d.\"master\", d.\"last_check\", d.\"auto_serial\", r.\"content\" FROM \"domains\" d LEFT JOIN \"records\" r ON ( d.\"id\"=r.\"domain_id\" AND r.\"type\"='SOA' ) WHERE d.\"name\"=':name' AND d.\"status\"='A'" );
+
+ declare( suffix, "sql-transactbegin", "Start transaction", "BEGIN" );
+ declare( suffix, "sql-transactend", "Finish transaction", "COMMIT" );
+ declare( suffix, "sql-transactabort", "Abort transaction", "ROLLBACK" );
+
+ declare( suffix, "sql-insert-slave","Add slave domain", "INSERT INTO \"domains\" ( \"name\", \"type\", \"master\", \"account\" ) VALUES ( '%s', 'SLAVE', '%s', '%s' )" );
+ declare( suffix, "sql-insert-record","Feed record into table", "INSERT INTO \"records\" ( \"domain_id\", \"name\", \"type\", \"ttl\", \"prio\", \"content\" ) VALUES ( %d, '%s', '%s', %d, %d, '%s' )" );
+
+ declare( suffix, "sql-update-serial", "Set zone to notified", "UPDATE \"domains\" SET \"notified_serial\"=%d WHERE \"id\"=%d" );
+ declare( suffix, "sql-update-lastcheck", "Set time of last check", "UPDATE \"domains\" SET \"last_check\"=%d WHERE \"id\"=%d" );
+
+ declare( suffix, "sql-master", "Get master record for zone", "SELECT d.\"master\" FROM \"domains\" d WHERE d.\"name\"=':name' AND d.\"status\"='A' AND d.\"type\"='SLAVE'" );
+ declare( suffix, "sql-supermaster","Get supermaster info", "SELECT s.\"account\" FROM \"supermasters\" s WHERE s.\"ip\"=':ip' AND s.\"nameserver\"=':ns'" );
+
+ declare( suffix, "sql-infoslaves", "Get all unfresh slaves", "SELECT d.\"id\", d.\"name\", d.\"master\", d.\"last_check\", d.\"notified_serial\", d.\"auto_serial\", r.\"content\" FROM \"domains\" d LEFT JOIN \"records\" r ON ( d.\"id\"=r.\"domain_id\" AND r.\"type\"='SOA' ) WHERE d.\"status\"='A' AND d.\"type\"='SLAVE'" );
+ declare( suffix, "sql-infomasters", "Get all updated masters", "SELECT d.\"id\", d.\"name\", d.\"master\", d.\"last_check\", d.\"notified_serial\", d.\"auto_serial\", r.\"content\" FROM \"domains\" d LEFT JOIN \"records\" r ON ( d.\"id\"=r.\"domain_id\" AND r.\"type\"='SOA' ) WHERE d.\"status\"='A' AND d.\"type\"='MASTER'" );
+
+ declare( suffix, "host", "deprecated, use host-read and host-write instead","" );
+ }
+
+
+ DNSBackend* make( const string &suffix="" )
+ {
+ return new OdbxBackend( suffix );
+ }
+};
+
+
+class OdbxLoader
+{
+ OdbxFactory factory;
+
+public:
+
+ OdbxLoader()
+ {
+ BackendMakers().report( &factory );
+ L<< Logger::Info << "[opendbxbackend] This is the opendbx backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+
+static OdbxLoader odbxloader;
+
+
+
+#endif /* ODBXBACKEND_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "odbxbackend.hh"
+
+
+
+unsigned int odbx_host_index[2] = { 0, 0 };
+
+
+
+bool OdbxBackend::connectTo( const vector<string>& hosts, QueryType type )
+{
+ int err;
+ unsigned int h, i;
+ int idx = odbx_host_index[type]++ % hosts.size();
+
+
+ if( m_handle[type] != NULL )
+ {
+ odbx_unbind( m_handle[type] );
+ odbx_finish( m_handle[type] );
+ m_handle[type] = NULL;
+ }
+
+ if( type == WRITE && getArg( "backend" ) == "sqlite" )
+ {
+ L.log( m_myname + " Using same SQLite connection for reading and writing to '" + hosts[odbx_host_index[READ]] + "'", Logger::Notice );
+ m_handle[WRITE] = m_handle[READ];
+ return true;
+ }
+
+ for( i = 0; i < hosts.size(); i++ )
+ {
+ h = ( idx + i ) % hosts.size();
+
+ if( ( err = odbx_init( &(m_handle[type]), getArg( "backend" ).c_str(), hosts[h].c_str(), getArg( "port" ).c_str() ) ) == ODBX_ERR_SUCCESS )
+ {
+ if( ( err = odbx_bind( m_handle[type], getArg( "database" ).c_str(), getArg( "username" ).c_str(), getArg( "password" ).c_str(), ODBX_BIND_SIMPLE ) ) == ODBX_ERR_SUCCESS )
+ {
+ L.log( m_myname + " Database connection (" + (type ? "write" : "read") + ") to '" + hosts[h] + "' succeeded", Logger::Notice );
+ return true;
+ }
+
+ L.log( m_myname + " Unable to bind to database on host " + hosts[h] + " - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+ continue;
+ }
+
+ L.log( m_myname + " Unable to connect to server on host " + hosts[h] + " - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+ }
+
+ m_handle[type] = NULL;
+ return false;
+}
+
+
+
+bool OdbxBackend::execStmt( const char* stmt, unsigned long length, QueryType type )
+{
+ int err;
+
+
+ DLOG( L.log( m_myname + " execStmt()", Logger::Debug ) );
+
+ if( m_qlog ) { L.log( m_myname + " Query: " + stmt, Logger::Info ); }
+
+ if( ( err = odbx_query( m_handle[type], stmt, length ) ) < 0 )
+ {
+ L.log( m_myname + " execStmt: Unable to execute query - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+
+ if( err != -ODBX_ERR_PARAM && odbx_error_type( m_handle[type], err ) > 0 ) { return false; } // ODBX_ERR_PARAM workaround
+ if( !connectTo( m_hosts[type], type ) ) { return false; }
+ if( odbx_query( m_handle[type], stmt, length ) < 0 ) { return false; }
+ }
+
+ if( type == WRITE ) { while( getRecord( type ) ); }
+
+ return true;
+}
+
+
+
+bool OdbxBackend::getRecord( QueryType type )
+{
+ int err = 3;
+
+
+ DLOG( L.log( m_myname + " getRecord()", Logger::Debug ) );
+
+ do
+ {
+ if( err < 0 )
+ {
+ L.log( m_myname + " getRecord: Unable to get next result - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+ throw( PDNSException( "Error: odbx_result() failed" ) );
+ }
+
+ if( m_result != NULL )
+ {
+ if( err == 3 )
+ {
+ if( ( err = odbx_row_fetch( m_result ) ) < 0 )
+ {
+ L.log( m_myname + " getRecord: Unable to get next row - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+ throw( PDNSException( "Error: odbx_row_fetch() failed" ) );
+ }
+
+ if( err > 0 )
+ {
+#ifdef VERBOSELOG
+ unsigned int i;
+ string fields;
+
+ for( i = 0; i < odbx_column_count( m_result ); i++ )
+ {
+ fields += string( odbx_column_name( m_result, i ) );
+
+ if( odbx_field_value( m_result, i ) != NULL )
+ {
+ fields += "=" + string( odbx_field_value( m_result, i ) ) + ", ";
+ }
+ else
+ {
+ fields += "=NULL, ";
+ }
+ }
+
+ L.log( m_myname + " Values: " + fields, Logger::Error );
+#endif
+ return true;
+ }
+
+ }
+
+ odbx_result_free( m_result );
+ m_result = NULL;
+ }
+ }
+ while( ( err = odbx_result( m_handle[type], &m_result, NULL, 0 ) ) != 0 );
+
+ m_result = NULL;
+ return false;
+}
+
+
+
+string OdbxBackend::escape( const string& str, QueryType type )
+{
+ int err;
+ unsigned long len = sizeof( m_escbuf );
+
+
+ DLOG( L.log( m_myname + " escape(string)", Logger::Debug ) );
+
+ if( ( err = odbx_escape( m_handle[type], str.c_str(), str.size(), m_escbuf, &len ) ) < 0 )
+ {
+ L.log( m_myname + " escape(string): Unable to escape string - " + string( odbx_error( m_handle[type], err ) ), Logger::Error );
+
+ if( err != -ODBX_ERR_PARAM && odbx_error_type( m_handle[type], err ) > 0 ) { throw( runtime_error( "odbx_escape() failed" ) ); } // ODBX_ERR_PARAM workaround
+ if( !connectTo( m_hosts[type], type ) ) { throw( runtime_error( "odbx_escape() failed" ) ); }
+ if( odbx_escape( m_handle[type], str.c_str(), str.size(), m_escbuf, &len ) < 0 ) { throw( runtime_error( "odbx_escape() failed" ) ); }
+ }
+
+ return string( m_escbuf, len );
+}
+
+
+
+bool OdbxBackend::getDomainList( const string& stmt, vector<DomainInfo>* list, bool (*check_fcn)(uint32_t,uint32_t,SOAData*,DomainInfo*) )
+{
+ const char* tmp;
+ uint32_t nlast, nserial;
+
+ SOAData sd;
+
+ DLOG( L.log( m_myname + " getDomainList()", Logger::Debug ) );
+
+ if( !execStmt( stmt.c_str(), stmt.size(), READ ) ) { return false; }
+ if( !getRecord( READ ) ) { return false; }
+
+ do
+ {
+ DomainInfo di;
+ nlast = 0;
+ nserial = 0;
+ sd.serial = 0;
+ sd.refresh = 0;
+
+ if( ( tmp = odbx_field_value( m_result, 6 ) ) != NULL )
+ {
+ fillSOAData( string( tmp, odbx_field_length( m_result, 6 ) ), sd );
+ }
+
+ if( !sd.serial && ( tmp = odbx_field_value( m_result, 5 ) ) != NULL )
+ {
+ sd.serial = strtol( tmp, NULL, 10 );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 4 ) ) != NULL )
+ {
+ nserial = strtol( tmp, NULL, 10 );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 3 ) ) != NULL )
+ {
+ nlast = strtol( tmp, NULL, 10 );
+ }
+
+ if( (*check_fcn)( nlast, nserial, &sd, &di ) )
+ {
+ if( ( tmp = odbx_field_value( m_result, 2 ) ) != NULL )
+ {
+ stringtok(di.masters, string( tmp, odbx_field_length( m_result, 2 )), ", \t" );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 1 ) ) != NULL )
+ {
+ di.zone = DNSName( string(tmp, odbx_field_length( m_result, 1 )) );
+ }
+
+ if( ( tmp = odbx_field_value( m_result, 0 ) ) != NULL )
+ {
+ di.id = strtol( tmp, NULL, 10 );
+ }
+
+ di.last_check = nlast;
+ di.notified_serial = nserial;
+ di.serial = sd.serial;
+ di.backend = this;
+
+ list->push_back( di );
+ }
+ }
+ while( getRecord( READ ) );
+
+ return true;
+}
+
+
+
+bool checkSlave( uint32_t nlast, uint32_t nserial, SOAData* sd, DomainInfo* di )
+{
+ if( nlast + sd->refresh < (uint32_t) time( 0 ) )
+ {
+ di->kind = DomainInfo::Slave;
+ return true;
+ }
+
+ return false;
+}
+
+
+
+bool checkMaster( uint32_t nlast, uint32_t nserial, SOAData* sd, DomainInfo* di )
+{
+ if( nserial != sd->serial )
+ {
+ di->kind = DomainInfo::Master;
+ return true;
+ }
+
+ return false;
+}
--- /dev/null
+AM_CPPFLAGS += $(ORACLE_CFLAGS)
+
+pkglib_LTLIBRARIES = liboraclebackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ drop-schema.oracle.sql \
+ schema.oracle.sql
+
+dist_doc_DATA = \
+ schema.oracle.sql \
+ drop-schema.oracle.sql
+
+liboraclebackend_la_SOURCES = oraclebackend.cc oraclebackend.hh
+liboraclebackend_la_LDFLAGS = -module -avoid-version
+liboraclebackend_la_LIBADD = $(ORACLE_LIBS) -lclntsh
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/oraclebackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp $(dist_doc_DATA) ChangeLog \
+ INSTALL README TODO
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+liboraclebackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_liboraclebackend_la_OBJECTS = oraclebackend.lo
+liboraclebackend_la_OBJECTS = $(am_liboraclebackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+liboraclebackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(liboraclebackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(liboraclebackend_la_SOURCES)
+DIST_SOURCES = $(liboraclebackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+DATA = $(dist_doc_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(ORACLE_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = liboraclebackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ drop-schema.oracle.sql \
+ schema.oracle.sql
+
+dist_doc_DATA = \
+ schema.oracle.sql \
+ drop-schema.oracle.sql
+
+liboraclebackend_la_SOURCES = oraclebackend.cc oraclebackend.hh
+liboraclebackend_la_LDFLAGS = -module -avoid-version
+liboraclebackend_la_LIBADD = $(ORACLE_LIBS) -lclntsh
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/oraclebackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/oraclebackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+liboraclebackend.la: $(liboraclebackend_la_OBJECTS) $(liboraclebackend_la_DEPENDENCIES) $(EXTRA_liboraclebackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(liboraclebackend_la_LINK) -rpath $(pkglibdir) $(liboraclebackend_la_OBJECTS) $(liboraclebackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/oraclebackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-dist_docDATA: $(dist_doc_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(docdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(docdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(docdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(docdir)" || exit $$?; \
+ done
+
+uninstall-dist_docDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(dist_doc_DATA)'; test -n "$(docdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(docdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)" "$(DESTDIR)$(docdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-dist_docDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-dist_docDATA uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dist_docDATA install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ tags tags-am uninstall uninstall-am uninstall-dist_docDATA \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+oraclebackend.lo
--- /dev/null
+An Oracle Database backend was originally contributed to PowerDNS in
+2002 by Stefan Arentz.
+
+A new version amounting to a complete rewrite was contributed in 2011 by
+Maik Zumstrull <maik@zumstrull.net>, then at the Steinbuch Centre for
+Computing <http://www.scc.kit.edu/> at the Karlsruhe Institute of
+Technology <http://www.kit.edu/>.
+
+---
+
+Licensing
+
+Any contributions submitted to PowerDNS.COM BV by Maik Zumstrull / SCC are
+released under the conditions of the MIT license. Note that additional or
+different licensing terms may apply to code as redistributed by
+PowerDNS.COM BV. The terms of the license are found below.
+
+---
+
+The MIT License
+
+Copyright (c) 2010-2011
+ Maik Zumstrull
+ Steinbuch Centre for Computing
+ Karlsruhe Institute of Technology
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null
+
+Oracle Backend
+
+todo Clean up our stuff in the destructor
+ write configure.in stuff
+
--- /dev/null
+DROP PROCEDURE get_hashed_prev_next;
+DROP PROCEDURE get_canonical_prev_next;
+
+DROP FUNCTION dnsname_to_hashname;
+DROP FUNCTION base32hex_encode;
+DROP FUNCTION dnsname_to_raw;
+DROP FUNCTION label_reverse;
+
+DROP TABLE Records;
+DROP SEQUENCE records_id_seq;
+DROP TABLE AccessControlList;
+DROP TABLE TSIGKeys;
+DROP TABLE ZoneDNSKeys;
+DROP SEQUENCE zonednskeys_id_seq;
+DROP TABLE ZoneMetadata;
+DROP TABLE Supermasters;
+DROP SEQUENCE supermasters_id_seq;
+DROP TABLE Zonemasters;
+DROP TABLE ZoneAlsoNotify;
+DROP TABLE Zones;
+DROP SEQUENCE zones_id_seq;
+
+-- vi: set sw=2 et : --
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Maik Zumstrull
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <stdexcept>
+
+#include "pdns/namespaces.hh"
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "oraclebackend.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/lock.hh"
+
+#include <oci.h>
+
+static const char *basicQueryKey = "PDNS_Basic_Query";
+static const char *basicQueryDefaultAuthSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change, auth "
+ "FROM Records "
+ "WHERE type = :type AND fqdn = lower(:name)";
+
+static const char *basicQueryDefaultSQL = "SELECT fqdn, ttl, type, content, zone_id, last_change "
+ "FROM Records "
+ "WHERE type = :type AND fqdn = lower(:name)";
+
+static const char *basicIdQueryKey = "PDNS_Basic_Id_Query";
+static const char *basicIdQueryDefaultAuthSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change, auth "
+ "FROM Records "
+ "WHERE type = :type AND fqdn = lower(:name) AND zone_id = :zoneid";
+
+static const char *basicIdQueryDefaultSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change "
+ "FROM Records "
+ "WHERE type = :type AND fqdn = lower(:name) AND zone_id = :zoneid";
+
+static const char *anyQueryKey = "PDNS_ANY_Query";
+static const char *anyQueryDefaultAuthSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change, auth "
+ "FROM Records "
+ "WHERE fqdn = lower(:name)"
+ " AND type IS NOT NULL "
+ "ORDER BY type";
+
+static const char *anyQueryDefaultSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change "
+ "FROM Records "
+ "WHERE fqdn = lower(:name)"
+ " AND type IS NOT NULL "
+ "ORDER BY type";
+
+static const char *anyIdQueryKey = "PDNS_ANY_Id_Query";
+static const char *anyIdQueryDefaultAuthSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change, auth "
+ "FROM Records "
+ "WHERE fqdn = lower(:name)"
+ " AND zone_id = :zoneid"
+ " AND type IS NOT NULL "
+ "ORDER BY type";
+
+static const char *anyIdQueryDefaultSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change "
+ "FROM Records "
+ "WHERE fqdn = lower(:name)"
+ " AND zone_id = :zoneid"
+ " AND type IS NOT NULL "
+ "ORDER BY type";
+
+
+static const char *listQueryKey = "PDNS_List_Query";
+static const char *listQueryDefaultAuthSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change, auth "
+ "FROM Records "
+ "WHERE zone_id = :zoneid"
+ " AND type IS NOT NULL "
+ "ORDER BY fqdn, type";
+
+static const char *listQueryDefaultSQL =
+ "SELECT fqdn, ttl, type, content, zone_id, last_change "
+ "FROM Records "
+ "WHERE zone_id = :zoneid"
+ " AND type IS NOT NULL "
+ "ORDER BY fqdn, type";
+
+
+static const char *zoneInfoQueryKey = "PDNS_Zone_Info_Query";
+static const char *zoneInfoQueryDefaultSQL =
+ "SELECT id, name, type, last_check, serial, notified_serial "
+ "FROM Zones "
+ "WHERE name = lower(:name)";
+
+static const char *alsoNotifyQueryKey = "PDNS_Also_Notify_Query";
+static const char *alsoNotifyQueryDefaultSQL =
+ "SELECT an.hostaddr "
+ "FROM Zones z JOIN ZoneAlsoNotify an ON z.id = an.zone_id "
+ "WHERE z.name = lower(:name)";
+
+static const char *zoneMastersQueryKey = "PDNS_Zone_Masters_Query";
+static const char *zoneMastersQueryDefaultSQL =
+ "SELECT master "
+ "FROM Zonemasters "
+ "WHERE zone_id = :zoneid";
+
+static const char *isZoneMasterQueryKey = "PDNS_Is_Zone_Master_Query";
+static const char *isZoneMasterQueryDefaultSQL =
+ "SELECT zm.master "
+ "FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id "
+ "WHERE z.name = lower(:name) AND zm.master = :master";
+
+static const char *deleteZoneQueryKey = "PDNS_Delete_Zone_Query";
+static const char *deleteZoneQueryDefaultSQL =
+ "DELETE FROM Records WHERE zone_id = :zoneid";
+
+static const char *zoneSetLastCheckQueryKey = "PDNS_Zone_Set_Last_Check_Query";
+static const char *zoneSetLastCheckQueryDefaultSQL =
+ "UPDATE Zones SET last_check = :lastcheck WHERE id = :zoneid";
+
+static const char *zoneSetNotifiedSerialQueryKey = "PDNS_Zone_Set_NSerial_Query";
+static const char *zoneSetNotifiedSerialQueryDefaultSQL =
+ "UPDATE Zones SET notified_serial = :serial WHERE id = :zoneid";
+
+static const char *insertRecordQueryKey = "PDNS_Insert_Record_Query";
+static const char *insertRecordQueryDefaultSQL =
+ "INSERT INTO Records (id, fqdn, zone_id, ttl, type, content) "
+ "VALUES (records_id_seq.NEXTVAL, lower(:name), :zoneid, :ttl, :type, :content)";
+
+static const char *finalizeAXFRQueryKey = "PDNS_Finalize_AXFR";
+static const char *finalizeAXFRQueryDefaultSQL =
+ "DECLARE\n"
+ " zone_id INTEGER := :zoneid;\n"
+ "BEGIN\n"
+ " NULL;\n"
+ "END;";
+
+static const char *unfreshZonesQueryKey = "PDNS_Unfresh_Zones_Query";
+static const char *unfreshZonesQueryDefaultSQL =
+ "SELECT z.id, z.name, z.last_check, z.serial, zm.master "
+ "FROM Zones z JOIN Zonemasters zm ON z.id = zm.zone_id "
+ "WHERE z.type = 'SLAVE' "
+ " AND (z.last_check IS NULL OR z.last_check + z.refresh < :ts)"
+ "ORDER BY z.id";
+
+static const char *updatedMastersQueryKey = "PDNS_Updated_Masters_Query";
+static const char *updatedMastersQueryDefaultSQL =
+ "SELECT id, name, serial, notified_serial "
+ "FROM Zones "
+ "WHERE type = 'MASTER' "
+ "AND (notified_serial IS NULL OR notified_serial < serial)";
+
+static const char *acceptSupernotificationQueryKey = "PDNS_Accept_Supernotification_Query";
+static const char *acceptSupernotificationQueryDefaultSQL =
+ "SELECT name "
+ "FROM Supermasters "
+ "WHERE ip = :ip AND nameserver = lower(:ns)";
+
+static const char *insertSlaveQueryKey = "PDNS_Insert_Slave_Query";
+static const char *insertSlaveQueryDefaultSQL =
+ "INSERT INTO Zones (id, name, type) "
+ "VALUES (zones_id_seq.NEXTVAL, lower(:zone), 'SLAVE') "
+ "RETURNING id INTO :zoneid";
+
+static const char *insertMasterQueryKey = "PDNS_Insert_Master_Query";
+static const char *insertMasterQueryDefaultSQL =
+ "INSERT INTO Zonemasters (zone_id, master) "
+ "VALUES (:zoneid, :ip)";
+
+static const char *prevNextNameQueryKey = "PDNS_Prev_Next_Name_Query";
+static const char *prevNextNameQueryDefaultSQL =
+ "BEGIN\n"
+ " get_canonical_prev_next(:zoneid, :name, :prev, :next);\n"
+ "END;";
+
+static const char *prevNextHashQueryKey = "PDNS_Prev_Next_Hash_Query";
+static const char *prevNextHashQueryDefaultSQL =
+ "BEGIN\n"
+ " get_hashed_prev_next(:zoneid, :hash, :unhashed, :prev, :next);\n"
+ "END;";
+
+static const char *getAllZoneMetadataQueryKey = "PDNS_Get_All_Zone_Metadata";
+static const char *getAllZoneMetadataQueryDefaultSQL =
+ "SELECT md.meta_type, md.meta_content "
+ "FROM Zones z JOIN ZoneMetadata md ON z.id = md.zone_id "
+ "WHERE z.name = lower(:name) "
+ "ORDER BY md.meta_ind";
+
+static const char *getZoneMetadataQueryKey = "PDNS_Get_Zone_Metadata";
+static const char *getZoneMetadataQueryDefaultSQL =
+ "SELECT md.meta_content "
+ "FROM Zones z JOIN ZoneMetadata md ON z.id = md.zone_id "
+ "WHERE z.name = lower(:name) AND md.meta_type = :kind "
+ "ORDER BY md.meta_ind";
+
+static const char *delZoneMetadataQueryKey = "PDNS_Del_Zone_Metadata";
+static const char *delZoneMetadataQueryDefaultSQL =
+ "DELETE FROM ZoneMetadata md "
+ "WHERE zone_id = (SELECT id FROM Zones z WHERE z.name = lower(:name)) "
+ " AND md.meta_type = :kind";
+
+static const char *setZoneMetadataQueryKey = "PDNS_Set_Zone_Metadata";
+static const char *setZoneMetadataQueryDefaultSQL =
+ "INSERT INTO ZoneMetadata (zone_id, meta_type, meta_ind, meta_content) "
+ "VALUES ("
+ " (SELECT id FROM Zones WHERE name = lower(:name)),"
+ " :kind, :i, :content"
+ ")";
+
+static const char *getTSIGKeyQueryKey = "PDNS_Get_TSIG_Key";
+static const char *getTSIGKeyQueryDefaultSQL =
+ "SELECT algorithm, secret "
+ "FROM TSIGKeys "
+ "WHERE name = :name";
+
+static const char *delTSIGKeyQueryKey = "PDNS_Del_TSIG_Key";
+static const char *delTSIGKeyQueryDefaultSQL =
+ "DELETE FROM TSIGKeys "
+ "WHERE name = :name";
+
+static const char *setTSIGKeyQueryKey = "PDNS_Set_TSIG_Key";
+static const char *setTSIGKeyQueryDefaultSQL =
+ "INSERT INTO TSIGKeys (name, algorithm, secret) "
+ "VALUES (:name, :algorithm, :secret)";
+
+static const char *getTSIGKeysQueryKey = "PDNS_Get_TSIG_Keys";
+static const char *getTSIGKeysQueryDefaultSQL =
+ "SELECT name, algorithm, secret "
+ "FROM TSIGKeys";
+
+static const char *getZoneKeysQueryKey = "PDNS_Get_Zone_Keys";
+static const char *getZoneKeysQueryDefaultSQL =
+ "SELECT k.id, k.flags, k.active, k.keydata "
+ "FROM ZoneDNSKeys k JOIN Zones z ON z.id = k.zone_id "
+ "WHERE z.name = lower(:name)";
+
+static const char *delZoneKeyQueryKey = "PDNS_Del_Zone_Key";
+static const char *delZoneKeyQueryDefaultSQL =
+ "DELETE FROM ZoneDNSKeys WHERE id = :keyid";
+
+static const char *addZoneKeyQueryKey = "PDNS_Add_Zone_Key";
+static const char *addZoneKeyQueryDefaultSQL =
+ "INSERT INTO ZoneDNSKeys (id, zone_id, flags, active, keydata) "
+ "VALUES ("
+ " zonednskeys_id_seq.NEXTVAL,"
+ " (SELECT id FROM Zones WHERE name = lower(:name)),"
+ " :flags,"
+ " :active,"
+ " :content"
+ ") RETURNING id INTO :keyid";
+
+static const char *setZoneKeyStateQueryKey = "PDNS_Set_Zone_Key_State";
+static const char *setZoneKeyStateQueryDefaultSQL =
+ "UPDATE ZoneDNSKeys SET active = :active WHERE id = :keyid";
+
+
+static void
+string_to_cbuf (char *buf, const string& s, size_t bufsize)
+{
+ if (s.size() >= bufsize) {
+ throw std::overflow_error("OracleBackend: string does not fit into char buffer");
+ }
+ strncpy(buf, s.c_str(), bufsize);
+}
+
+static void
+DNSName_to_cbuf (char *buf, const DNSName& n, size_t bufsize)
+{
+ string s = toLower(n.toStringNoDot());
+ if (s.size() >= bufsize) {
+ throw std::overflow_error("OracleBackend: DNSName does not fit into char buffer");
+ }
+ strncpy(buf, s.c_str(), bufsize);
+}
+
+OracleBackend::OracleBackend (const string &suffix, OCIEnv *envh,
+ char *poolname)
+{
+ setArgPrefix(string("oracle") + suffix);
+ sword err;
+
+ // Initialize everything in a known state
+ oraenv = envh;
+ oraerr = NULL;
+ pooledSvcCtx = NULL;
+ masterAuthHandle = NULL;
+ masterSvcCtx = NULL;
+ curStmtHandle = NULL;
+ openTransactionZoneID = -1;
+
+ try
+ {
+ d_dnssecQueries = mustDo("dnssec");
+ }
+ catch (ArgException e)
+ {
+ d_dnssecQueries = false;
+ }
+
+ // Process configuration options
+ string_to_cbuf(myServerName, getArg("nameserver-name"), sizeof(myServerName));
+
+ if (d_dnssecQueries) {
+ basicQuerySQL = getArg("basic-query-auth");
+ basicIdQuerySQL = getArg("basic-id-query-auth");
+ anyQuerySQL = getArg("any-query-auth");
+ anyIdQuerySQL = getArg("any-id-query-auth");
+ listQuerySQL = getArg("list-query-auth");
+ } else {
+ basicQuerySQL = getArg("basic-query");
+ basicIdQuerySQL = getArg("basic-id-query");
+ anyQuerySQL = getArg("any-query");
+ anyIdQuerySQL = getArg("any-id-query");
+ listQuerySQL = getArg("list-query");
+ }
+
+ zoneInfoQuerySQL = getArg("zone-info-query");
+ alsoNotifyQuerySQL = getArg("also-notify-query");
+ zoneMastersQuerySQL = getArg("zone-masters-query");
+ isZoneMasterQuerySQL = getArg("is-zone-master-query");
+ deleteZoneQuerySQL = getArg("delete-zone-query");
+ zoneSetLastCheckQuerySQL = getArg("zone-set-last-check-query");
+ insertRecordQuerySQL = getArg("insert-record-query");
+ finalizeAXFRQuerySQL = getArg("finalize-axfr-query");
+ unfreshZonesQuerySQL = getArg("unfresh-zones-query");
+ updatedMastersQuerySQL = getArg("updated-masters-query");
+ acceptSupernotificationQuerySQL = getArg("accept-supernotification-query");
+ insertSlaveQuerySQL = getArg("insert-slave-query");
+ insertMasterQuerySQL = getArg("insert-master-query");
+ zoneSetNotifiedSerialQuerySQL = getArg("zone-set-notified-serial-query");
+ prevNextNameQuerySQL = getArg("prev-next-name-query");
+ prevNextHashQuerySQL = getArg("prev-next-hash-query");
+ getAllZoneMetadataQuerySQL = getArg("get-all-zone-metadata-query");
+ getZoneMetadataQuerySQL = getArg("get-zone-metadata-query");
+ delZoneMetadataQuerySQL = getArg("del-zone-metadata-query");
+ setZoneMetadataQuerySQL = getArg("set-zone-metadata-query");
+ getTSIGKeyQuerySQL = getArg("get-tsig-key-query");
+ delTSIGKeyQuerySQL = getArg("del-tsig-key-query");
+ setTSIGKeyQuerySQL = getArg("set-tsig-key-query");
+ getTSIGKeysQuerySQL = getArg("get-tsig-keys-query");
+ getZoneKeysQuerySQL = getArg("get-zone-keys-query");
+ delZoneKeyQuerySQL = getArg("del-zone-key-query");
+ addZoneKeyQuerySQL = getArg("add-zone-key-query");
+ setZoneKeyStateQuerySQL = getArg("set-zone-key-state-query");
+
+ // Allocate an error handle
+ err = OCIHandleAlloc(oraenv, (void**) &oraerr,
+ OCI_HTYPE_ERROR, 0, NULL);
+ if (err == OCI_ERROR) {
+ throw OracleException("OCIHandleAlloc");
+ }
+
+ // Logon to the database
+ err = OCISessionGet(oraenv, oraerr, &pooledSvcCtx, NULL, (OraText*) poolname, strlen(poolname), NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Opening Oracle session", oraerr);
+ }
+}
+
+void
+OracleBackend::openMasterConnection ()
+{
+ sword err;
+
+ if (masterSvcCtx == NULL) {
+ err = OCIHandleAlloc(oraenv, (void**) &masterAuthHandle, OCI_HTYPE_AUTHINFO, 0, NULL);
+ if (err == OCI_ERROR) {
+ throw OracleException("openMasterConnection: allocating auth handle");
+ }
+
+ string database = getArg("master-database");
+ string username = getArg("master-username");
+ string password = getArg("master-password");
+
+ err = OCIAttrSet(masterAuthHandle, OCI_HTYPE_AUTHINFO, (void*)username.c_str(), username.size(), OCI_ATTR_USERNAME, oraerr);
+ if (err == OCI_ERROR) {
+ throw OracleException("openMasterConnection: setting username");
+ }
+
+ err = OCIAttrSet(masterAuthHandle, OCI_HTYPE_AUTHINFO, (void*)password.c_str(), password.size(), OCI_ATTR_PASSWORD, oraerr);
+ if (err == OCI_ERROR) {
+ throw OracleException("openMasterConnection: setting password");
+ }
+
+ err = OCISessionGet(oraenv, oraerr, &masterSvcCtx, masterAuthHandle,
+ (OraText*)database.c_str(), database.size(),
+ NULL, 0, NULL, NULL, NULL, OCI_SESSGET_STMTCACHE);
+ if (err == OCI_ERROR) {
+ throw OracleException("openMasterConnection OCISessionGet");
+ }
+ }
+}
+
+OracleBackend::~OracleBackend ()
+{
+ Cleanup();
+}
+
+void
+OracleBackend::lookup (const QType &qtype, const DNSName& qname,
+ DNSPacket *p, int zoneId)
+{
+ sword rc;
+
+ if (qtype.getCode() != QType::ANY) {
+ if (zoneId < 0) {
+ if (curStmtHandle != NULL) throw OracleException("Invalid state");
+ curStmtHandle = prepare_query(pooledSvcCtx, basicQuerySQL, basicQueryKey);
+ curStmtKey = basicQueryKey;
+ define_fwd_query(curStmtHandle);
+ bind_str_failokay(curStmtHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(curStmtHandle, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(curStmtHandle, ":type", mQueryType, sizeof(mQueryType));
+ } else {
+ if (curStmtHandle != NULL) throw OracleException("Invalid state");
+ curStmtHandle = prepare_query(pooledSvcCtx, basicIdQuerySQL, basicIdQueryKey);
+ curStmtKey = basicIdQueryKey;
+ define_fwd_query(curStmtHandle);
+ bind_str_failokay(curStmtHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(curStmtHandle, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(curStmtHandle, ":type", mQueryType, sizeof(mQueryType));
+ bind_int(curStmtHandle, ":zoneid", &mQueryZoneId);
+ }
+ } else {
+ if (zoneId < 0) {
+ if (curStmtHandle != NULL) throw OracleException("Invalid state");
+ curStmtHandle = prepare_query(pooledSvcCtx, anyQuerySQL, anyQueryKey);
+ curStmtKey = anyQueryKey;
+ define_fwd_query(curStmtHandle);
+ bind_str_failokay(curStmtHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(curStmtHandle, ":name", mQueryName, sizeof(mQueryName));
+ } else {
+ if (curStmtHandle != NULL) throw OracleException("Invalid state");
+ curStmtHandle = prepare_query(pooledSvcCtx, anyIdQuerySQL, anyIdQueryKey);
+ curStmtKey = anyIdQueryKey;
+ define_fwd_query(curStmtHandle);
+ bind_str_failokay(curStmtHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(curStmtHandle, ":name", mQueryName, sizeof(mQueryName));
+ bind_int(curStmtHandle, ":zoneid", &mQueryZoneId);
+ }
+ }
+
+ DNSName_to_cbuf(mQueryName, qname, sizeof(mQueryName));
+ string_to_cbuf(mQueryType, qtype.getName(), sizeof(mQueryType));
+ mQueryZoneId = zoneId;
+
+ rc = OCIStmtExecute(pooledSvcCtx, curStmtHandle, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle Lookup", oraerr);
+ }
+
+ if (rc == OCI_NO_DATA) {
+ release_query(curStmtHandle, curStmtKey);
+ curStmtHandle = NULL;
+ }
+}
+
+bool
+OracleBackend::getBeforeAndAfterNames (
+ uint32_t zoneId, const DNSName& zone,
+ const DNSName& name, DNSName& before, DNSName& after)
+{
+ if(!d_dnssecQueries)
+ return -1;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ (void)zone;
+
+ stmt = prepare_query(pooledSvcCtx, prevNextNameQuerySQL, prevNextNameQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str_ind(stmt, ":prev", mResultPrevName, sizeof(mResultPrevName), &mResultPrevNameInd);
+ bind_str_ind(stmt, ":next", mResultNextName, sizeof(mResultNextName), &mResultNextNameInd);
+ bind_uint32(stmt, ":zoneid", &zoneId);
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ mResultPrevNameInd = -1;
+ mResultNextNameInd = -1;
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "Oracle getBeforeAndAfterNames", oraerr
+ );
+ }
+
+ check_indicator(mResultPrevNameInd, false);
+ check_indicator(mResultNextNameInd, false);
+
+ before = DNSName(mResultPrevName);
+ after = DNSName(mResultNextName);
+
+ release_query(stmt, prevNextNameQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::getBeforeAndAfterNamesAbsolute(uint32_t zoneId,
+ const string& name, DNSName& unhashed, string& before, string& after)
+{
+ if(!d_dnssecQueries)
+ return -1;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, prevNextHashQuerySQL, prevNextHashQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":hash", mQueryName, sizeof(mQueryName));
+ bind_str_ind(stmt, ":unhashed", mResultName, sizeof(mResultName), &mResultNameInd);
+ bind_str_ind(stmt, ":prev", mResultPrevName, sizeof(mResultPrevName), &mResultPrevNameInd);
+ bind_str_ind(stmt, ":next", mResultNextName, sizeof(mResultNextName), &mResultNextNameInd);
+ bind_uint32(stmt, ":zoneid", &zoneId);
+ string_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ mResultNameInd = -1;
+ mResultPrevNameInd = -1;
+ mResultNextNameInd = -1;
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "Oracle getBeforeAndAfterNamesAbsolute", oraerr
+ );
+ }
+
+ check_indicator(mResultNameInd, false);
+ check_indicator(mResultPrevNameInd, false);
+ check_indicator(mResultNextNameInd, false);
+
+ unhashed = DNSName(mResultName);
+ before = mResultPrevName;
+ after = mResultNextName;
+
+ release_query(stmt, prevNextHashQueryKey);
+ return true;
+}
+
+vector<string>
+OracleBackend::getDomainMasters (const DNSName& domain, int zoneId)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ (void)domain;
+
+ vector<string> masters;
+ char master[512];
+ sb2 master_ind;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, zoneMastersQuerySQL, zoneMastersQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":zoneid", &mQueryZoneId);
+
+ mQueryZoneId = zoneId;
+ define_output_str(stmt, 1, &master_ind, master, sizeof(master));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getDomainMasters", oraerr);
+ }
+
+ while (rc != OCI_NO_DATA) {
+ check_indicator(master_ind, false);
+
+ masters.push_back(master);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "OracleBackend, fetching next zone master", oraerr
+ );
+ }
+ }
+
+ release_query(stmt, zoneMastersQueryKey);
+
+ return masters;
+}
+
+bool
+OracleBackend::isMaster (const DNSName& domain, const string &master)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, isZoneMasterQuerySQL, isZoneMasterQueryKey);
+
+ DNSName_to_cbuf(mQueryZone, domain, sizeof(mQueryZone));
+ string_to_cbuf(mQueryName, master, sizeof(mQueryName));
+
+ char res_master[512];
+ sb2 res_master_ind;
+
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":name", mQueryZone, sizeof(mQueryZone));
+ bind_str(stmt, ":master", mQueryName, sizeof(mQueryName));
+ define_output_str(stmt, 1, &res_master_ind, res_master, sizeof(res_master));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle isMaster", oraerr);
+ }
+
+ release_query(stmt, isZoneMasterQueryKey);
+
+ if (rc != OCI_NO_DATA) {
+ check_indicator(res_master_ind, false);
+ return true;
+ }
+
+ return false;
+}
+
+bool
+OracleBackend::getDomainInfo (const DNSName& domain, DomainInfo &di)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ int zone_id;
+ sb2 zone_id_ind;
+ int last_check;
+ sb2 last_check_ind;
+ uint32_t serial;
+ sb2 serial_ind;
+ uint32_t notified_serial;
+ sb2 notified_serial_ind;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, zoneInfoQuerySQL, zoneInfoQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ define_output_int(stmt, 1, &zone_id_ind, &zone_id);
+ define_output_str(stmt, 2, &mResultNameInd, mResultName, sizeof(mResultName));
+ define_output_str(stmt, 3, &mResultTypeInd, mResultType, sizeof(mResultType));
+ define_output_int(stmt, 4, &last_check_ind, &last_check);
+ define_output_uint32(stmt, 5, &serial_ind, &serial);
+ define_output_uint32(stmt, 6, ¬ified_serial_ind, ¬ified_serial);
+
+ DNSName_to_cbuf(mQueryZone, domain, sizeof(mQueryZone));
+ bind_str(stmt, ":name", mQueryZone, sizeof(mQueryZone));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getDomainInfo", oraerr);
+ }
+
+ if (rc == OCI_NO_DATA) {
+ release_query(stmt, zoneInfoQueryKey);
+ return false;
+ }
+
+ check_indicator(zone_id_ind, false);
+ check_indicator(mResultNameInd, false);
+ check_indicator(serial_ind, true);
+
+ if (zone_id < 0) throw std::underflow_error("OracleBackend: Zone ID < 0 when writing into uint32_t");
+
+ di.id = zone_id;
+ di.zone = DNSName(mResultName);
+ di.serial = serial;
+ di.backend = this;
+
+ check_indicator(mResultTypeInd, false);
+ if (strcasecmp(mResultType, "NATIVE") == 0) {
+ di.kind = DomainInfo::Native;
+ } else if (strcasecmp(mResultType, "MASTER") == 0) {
+ di.kind = DomainInfo::Master;
+ check_indicator(notified_serial_ind, false);
+ di.notified_serial = notified_serial;
+ } else if (strcasecmp(mResultType, "SLAVE") == 0) {
+ di.kind = DomainInfo::Slave;
+ check_indicator(last_check_ind, true);
+ di.last_check = last_check;
+ di.masters = getDomainMasters(DNSName(mResultName), zone_id);
+ } else {
+ throw OracleException("Unknown zone type in Oracle backend");
+ }
+
+ di.kind = DomainInfo::Native;
+
+ release_query(stmt, zoneInfoQueryKey);
+ return true;
+}
+
+void OracleBackend::alsoNotifies(const DNSName& domain, set<string> *addrs)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ char hostaddr[512];
+ sb2 hostaddr_ind;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, alsoNotifyQuerySQL, alsoNotifyQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":name", mQueryZone, sizeof(mQueryZone));
+
+ DNSName_to_cbuf(mQueryZone, domain, sizeof(mQueryZone));
+
+ define_output_str(stmt, 1, &hostaddr_ind, hostaddr, sizeof(hostaddr));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle alsoNotifies", oraerr);
+ }
+
+ while (rc != OCI_NO_DATA) {
+ check_indicator(hostaddr_ind, false);
+
+ addrs->insert(hostaddr);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "OracleBackend alsoNotifies fetch", oraerr
+ );
+ }
+ }
+
+ release_query(stmt, alsoNotifyQueryKey);
+}
+
+void
+OracleBackend::getUnfreshSlaveInfos (vector<DomainInfo>* domains)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ mQueryTimestamp = now.tv_sec;
+
+ int last_check;
+ sb2 last_check_ind;
+ uint32_t serial;
+ sb2 serial_ind;
+ char master[512];
+ sb2 master_ind;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, unfreshZonesQuerySQL, unfreshZonesQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":ts", &mQueryTimestamp);
+ define_output_int(stmt, 1, &mResultZoneIdInd, &mResultZoneId);
+ define_output_str(stmt, 2, &mResultNameInd, mResultName, sizeof(mResultName));
+ define_output_int(stmt, 3, &last_check_ind, &last_check);
+ define_output_uint32(stmt, 4, &serial_ind, &serial);
+ define_output_str(stmt, 5, &master_ind, master, sizeof(master));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getUnfreshSlaveInfos", oraerr);
+ }
+
+ while (rc != OCI_NO_DATA) {
+ check_indicator(mResultZoneIdInd, false);
+ check_indicator(mResultNameInd, false);
+ check_indicator(serial_ind, true);
+ check_indicator(last_check_ind, true);
+ int zoneId = mResultZoneId;
+
+ if (mResultZoneId < 0) throw std::underflow_error("OracleBackend: Zone ID < 0 when writing into uint32_t");
+
+ DomainInfo di;
+ di.id = mResultZoneId;
+ di.zone = DNSName(mResultName);
+ di.last_check = last_check;
+ di.kind = DomainInfo::Slave;
+ di.backend = this;
+ if (serial_ind == 0) {
+ di.serial = serial;
+ }
+
+ while (rc != OCI_NO_DATA && zoneId == mResultZoneId) {
+ check_indicator(master_ind, false);
+ di.masters.push_back(master);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "OracleBackend, fetching next unfresh slave master", oraerr
+ );
+ }
+
+ check_indicator(mResultZoneIdInd, false);
+ }
+
+ domains->push_back(di);
+ }
+
+ release_query(stmt, unfreshZonesQueryKey);
+}
+
+void
+OracleBackend::getUpdatedMasters (vector<DomainInfo>* domains)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ uint32_t serial;
+ sb2 serial_ind;
+ uint32_t notified_serial;
+ sb2 notified_serial_ind;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, updatedMastersQuerySQL, updatedMastersQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ define_output_int(stmt, 1, &mResultZoneIdInd, &mResultZoneId);
+ define_output_str(stmt, 2, &mResultNameInd, mResultName, sizeof(mResultName));
+ define_output_uint32(stmt, 3, &serial_ind, &serial);
+ define_output_uint32(stmt, 4, ¬ified_serial_ind, ¬ified_serial);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getUpdatedMasters", oraerr);
+ }
+
+ while (rc != OCI_NO_DATA) {
+ check_indicator(mResultZoneIdInd, false);
+ check_indicator(mResultNameInd, false);
+ check_indicator(serial_ind, false);
+ check_indicator(notified_serial_ind, true);
+
+ if (mResultZoneId < 0) throw std::underflow_error("OracleBackend: Zone ID < 0 when writing into uint32_t");
+
+ DomainInfo di;
+ di.id = mResultZoneId;
+ di.zone = DNSName(mResultName);
+ di.serial = serial;
+ di.notified_serial = notified_serial;
+ di.kind = DomainInfo::Master;
+ di.backend = this;
+
+ domains->push_back(di);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "OracleBackend, fetching next updated master", oraerr
+ );
+ }
+ }
+
+ release_query(stmt, updatedMastersQueryKey);
+}
+
+void
+OracleBackend::setFresh (uint32_t zoneId)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ mQueryZoneId = zoneId;
+
+ struct timeval now;
+ gettimeofday(&now, NULL);
+ mQueryTimestamp = now.tv_sec;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setFresh BEGIN", oraerr);
+ }
+
+ stmt = prepare_query(masterSvcCtx, zoneSetLastCheckQuerySQL, zoneSetLastCheckQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":zoneid", &mQueryZoneId);
+ bind_int(stmt, ":lastcheck", &mQueryTimestamp);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setFresh", oraerr);
+ }
+
+ release_query(stmt, zoneSetLastCheckQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc) {
+ throw OracleException("Oracle setFresh COMMIT", oraerr);
+ }
+}
+
+void
+OracleBackend::setNotified (uint32_t zoneId, uint32_t serial)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setNotified BEGIN", oraerr);
+ }
+
+ stmt = prepare_query(masterSvcCtx, zoneSetNotifiedSerialQuerySQL, zoneSetNotifiedSerialQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_uint32(stmt, ":serial", &serial);
+ bind_uint32(stmt, ":zoneid", &zoneId);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setNotified", oraerr);
+ }
+
+ release_query(stmt, zoneSetNotifiedSerialQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc) {
+ throw OracleException("Oracle setNotified COMMIT", oraerr);
+ }
+}
+
+bool
+OracleBackend::list (const DNSName& domain, int zoneId, bool include_disabled)
+{
+ sword rc;
+
+ // This is only for backends that cannot lookup by zoneId,
+ // we can discard
+ (void)domain;
+
+ if (curStmtHandle != NULL) throw OracleException("Invalid state");
+ curStmtHandle = prepare_query(pooledSvcCtx, listQuerySQL, listQueryKey);
+ curStmtKey = listQueryKey;
+ define_fwd_query(curStmtHandle);
+ bind_str_failokay(curStmtHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(curStmtHandle, ":zoneid", &mQueryZoneId);
+
+ mQueryZoneId = zoneId;
+
+ rc = OCIStmtExecute(pooledSvcCtx, curStmtHandle, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle List", oraerr);
+ }
+
+ if (rc == OCI_SUCCESS || rc == OCI_SUCCESS_WITH_INFO) {
+ return true;
+ }
+
+ if (rc == OCI_NO_DATA) {
+ release_query(curStmtHandle, curStmtKey);
+ curStmtHandle = NULL;
+ }
+
+ return false;
+}
+
+bool OracleBackend::get (DNSResourceRecord &rr)
+{
+ sword rc;
+
+ if (curStmtHandle == NULL) {
+ return false;
+ }
+
+ check_indicator(mResultNameInd, false);
+ check_indicator(mResultTTLInd, false);
+ check_indicator(mResultTypeInd, true);
+ check_indicator(mResultContentInd, true);
+ check_indicator(mResultZoneIdInd, false);
+ check_indicator(mResultLastChangeInd, false);
+ if (d_dnssecQueries)
+ check_indicator(mResultIsAuthInd, false);
+
+ rr.qname = DNSName(mResultName);
+ rr.ttl = mResultTTL;
+ rr.qtype = mResultType;
+ rr.content = mResultContent;
+ rr.domain_id = mResultZoneId;
+ rr.last_modified = mResultLastChange;
+ if (d_dnssecQueries)
+ rr.auth = mResultIsAuth > 0;
+ else
+ rr.auth = 1;
+
+ rc = OCIStmtFetch2(curStmtHandle, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("OracleBackend, fetching next row", oraerr);
+ }
+
+ if (rc == OCI_NO_DATA) {
+ release_query(curStmtHandle, curStmtKey);
+ curStmtHandle = NULL;
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::startTransaction (const DNSName& domain, int zoneId)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ (void)domain;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle startTransaction", oraerr);
+ }
+
+ if (zoneId >= 0) {
+ if (openTransactionZoneID >= 0) {
+ throw OracleException("Attempt to start AXFR during AXFR");
+ }
+
+ mQueryZoneId = openTransactionZoneID = zoneId;
+
+ stmt = prepare_query(masterSvcCtx, deleteZoneQuerySQL, deleteZoneQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":zoneid", &mQueryZoneId);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle startTransaction deleteZone", oraerr);
+ }
+
+ release_query(stmt, deleteZoneQueryKey);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::feedRecord (const DNSResourceRecord &rr, string *ordername)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ uint32_t ttl;
+
+ stmt = prepare_query(masterSvcCtx, insertRecordQuerySQL, insertRecordQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":zoneid", &mQueryZoneId);
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":type", mQueryType, sizeof(mQueryType));
+ bind_uint32(stmt, ":ttl", &ttl);
+ bind_str(stmt, ":content", mQueryContent, sizeof(mQueryContent));
+
+ mQueryZoneId = rr.domain_id;
+ DNSName_to_cbuf(mQueryName, rr.qname, sizeof(mQueryName));
+ ttl = rr.ttl;
+ string_to_cbuf(mQueryType, rr.qtype.getName(), sizeof(mQueryType));
+ string_to_cbuf(mQueryContent, rr.content, sizeof(mQueryContent));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle feedRecord", oraerr);
+ }
+
+ release_query(stmt, insertRecordQueryKey);
+
+ return true;
+}
+
+bool
+OracleBackend::commitTransaction ()
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ if (openTransactionZoneID >= 0) {
+ stmt = prepare_query(masterSvcCtx, finalizeAXFRQuerySQL, finalizeAXFRQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(stmt, ":zoneid", &openTransactionZoneID);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle commitTransaction finalizeAXFR", oraerr);
+ }
+
+ release_query(stmt, finalizeAXFRQueryKey);
+
+ openTransactionZoneID = -1;
+ }
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc) {
+ throw OracleException("Oracle commitTransaction", oraerr);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::abortTransaction ()
+{
+ sword err;
+
+ err = OCITransRollback(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (err) {
+ throw OracleException("Oracle abortTransaction", oraerr);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::superMasterBackend (const string &ip, const DNSName& domain,
+ const vector<DNSResourceRecord> &nsset,
+ string *nameserver, string *account,
+ DNSBackend **backend)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ bool result = false;
+
+ (void)domain;
+
+ string_to_cbuf(mQueryAddr, ip, sizeof(mQueryAddr));
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, acceptSupernotificationQuerySQL, acceptSupernotificationQueryKey);
+ define_output_str(stmt, 1, &mResultNameInd, mResultName, sizeof(mResultName));
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":ns", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":ip", mQueryAddr, sizeof(mQueryAddr));
+
+ for (vector<DNSResourceRecord>::const_iterator i=nsset.begin(); i != nsset.end(); ++i) {
+ string_to_cbuf(mQueryName, i->content, sizeof(mQueryName));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle superMasterBackend", oraerr);
+ }
+
+ if (rc != OCI_NO_DATA) {
+ *account = mResultName;
+ *backend = this;
+ result = true;
+ break;
+ }
+ }
+
+ release_query(stmt, acceptSupernotificationQueryKey);
+
+ return result;
+}
+
+bool
+OracleBackend::createSlaveDomain(const string &ip, const DNSName& domain,
+ const string &nameserver, const string &account)
+{
+ sword rc;
+ OCIStmt *insertSlaveQueryHandle;
+ OCIStmt *insertMasterQueryHandle;
+
+ DNSName_to_cbuf(mQueryZone, domain, sizeof(mQueryZone));
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle createSlaveDomain BEGIN", oraerr);
+ }
+
+ insertSlaveQueryHandle = prepare_query(masterSvcCtx, insertSlaveQuerySQL, insertSlaveQueryKey);
+ bind_str_failokay(insertSlaveQueryHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(insertSlaveQueryHandle, ":zoneid", &mQueryZoneId);
+ bind_str(insertSlaveQueryHandle, ":zone", mQueryZone, sizeof(mQueryZone));
+
+ insertMasterQueryHandle = prepare_query(masterSvcCtx, insertMasterQuerySQL, insertMasterQueryKey);
+ bind_str_failokay(insertMasterQueryHandle, ":nsname", myServerName, sizeof(myServerName));
+ bind_int(insertMasterQueryHandle, ":zoneid", &mQueryZoneId);
+ bind_str(insertMasterQueryHandle, ":ip", mQueryAddr, sizeof(mQueryAddr));
+
+ rc = OCIStmtExecute(masterSvcCtx, insertSlaveQueryHandle, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "Oracle createSlaveDomain insertSlave", oraerr);
+ }
+
+ string_to_cbuf(mQueryAddr, ip, sizeof(mQueryAddr));
+
+ rc = OCIStmtExecute(masterSvcCtx, insertMasterQueryHandle, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException(
+ "Oracle createSlaveDomain insertMaster", oraerr);
+ }
+
+ release_query(insertSlaveQueryHandle, insertSlaveQueryKey);
+ release_query(insertMasterQueryHandle, insertMasterQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc) {
+ throw OracleException("Oracle createSlaveDomain COMMIT", oraerr);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::getAllDomainMetadata (const DNSName& name, std::map<string, vector<string> >& meta)
+{
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, getAllZoneMetadataQuerySQL, getAllZoneMetadataQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+
+ define_output_str(stmt, 1, &mResultTypeInd, mResultType, sizeof(mResultType));
+ define_output_str(stmt, 2, &mResultContentInd, mResultContent, sizeof(mResultContent));
+
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ while (rc != OCI_NO_DATA) {
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getAllDomainMetadata", oraerr);
+ }
+ check_indicator(mResultTypeInd, true);
+ check_indicator(mResultContentInd, true);
+
+ string kind = mResultType;
+ string content = mResultContent;
+ if (!isDnssecDomainMetadata(content))
+ meta[kind].push_back(content);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ release_query(stmt, getAllZoneMetadataQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::getDomainMetadata (const DNSName& name, const string& kind,
+ vector<string>& meta)
+{
+ if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, getZoneMetadataQuerySQL, getZoneMetadataQueryKey);
+ bind_str_failokay(stmt, ":nsname", myServerName, sizeof(myServerName));
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":kind", mQueryType, sizeof(mQueryType));
+ define_output_str(stmt, 1, &mResultContentInd, mResultContent, sizeof(mResultContent));
+
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ string_to_cbuf(mQueryType, kind, sizeof(mQueryType));
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ while (rc != OCI_NO_DATA) {
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getDomainMetadata", oraerr);
+ }
+
+ check_indicator(mResultContentInd, true);
+
+ string content = mResultContent;
+ meta.push_back(content);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ release_query(stmt, getZoneMetadataQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::setDomainMetadata(const DNSName& name, const string& kind,
+ const vector<string>& meta)
+{
+ if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainMetadata BEGIN", oraerr);
+ }
+
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ string_to_cbuf(mQueryType, kind, sizeof(mQueryType));
+
+ stmt = prepare_query(masterSvcCtx, delZoneMetadataQuerySQL, delZoneMetadataQueryKey);
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":kind", mQueryType, sizeof(mQueryType));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainMetadata DELETE", oraerr);
+ }
+
+ release_query(stmt, delZoneMetadataQueryKey);
+
+ stmt = prepare_query(masterSvcCtx, setZoneMetadataQuerySQL, setZoneMetadataQueryKey);
+
+ int i = 0;
+
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":kind", mQueryType, sizeof(mQueryType));
+ bind_int(stmt, ":i", &i);
+ bind_str(stmt, ":content", mQueryContent, sizeof(mQueryContent));
+
+ for (vector<string>::const_iterator it = meta.begin(); it != meta.end(); ++it) {
+ string_to_cbuf(mQueryContent, *it, sizeof(mQueryContent));
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainMetadata INSERT", oraerr);
+ }
+ i++;
+ }
+
+ release_query(stmt, setZoneMetadataQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainMetadata COMMIT", oraerr);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::getTSIGKey (const DNSName& name, DNSName* algorithm, string* content)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, getTSIGKeyQuerySQL, getTSIGKeyQueryKey);
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+
+ define_output_str(stmt, 1, &mResultTypeInd, mResultType, sizeof(mResultType));
+ define_output_str(stmt, 2, &mResultContentInd, mResultContent, sizeof(mResultContent));
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ content->clear();
+ while (rc != OCI_NO_DATA) {
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getTSIGKey", oraerr);
+ }
+
+ check_indicator(mResultTypeInd, false);
+ check_indicator(mResultContentInd, false);
+
+ if(algorithm->empty() || *algorithm==DNSName(mResultType)) {
+ *algorithm = DNSName(mResultType);
+ *content = mResultContent;
+ }
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ release_query(stmt, getTSIGKeyQueryKey);
+ return !content->empty();
+}
+
+bool
+OracleBackend::delTSIGKey(const DNSName& name)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ stmt = prepare_query(masterSvcCtx, delTSIGKeyQuerySQL, delTSIGKeyQueryKey);
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle delTSIGKey", oraerr);
+ }
+
+ release_query(stmt, setTSIGKeyQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle delTSIGKey COMMIT", oraerr);
+ }
+ return true;
+}
+
+bool
+OracleBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setTSIGKey BEGIN", oraerr);
+ }
+
+ stmt = prepare_query(masterSvcCtx, delTSIGKeyQuerySQL, delTSIGKeyQueryKey);
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setTSIGKey DELETE", oraerr);
+ }
+
+ release_query(stmt, delTSIGKeyQueryKey);
+
+ stmt = prepare_query(masterSvcCtx, setTSIGKeyQuerySQL, setTSIGKeyQueryKey);
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ DNSName_to_cbuf(mQueryType, algorithm, sizeof(mQueryType));
+ string_to_cbuf(mQueryContent, content, sizeof(mQueryContent));
+
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_str(stmt, ":algorithm", mQueryType, sizeof(mQueryType));
+ bind_str(stmt, ":secret", mQueryContent, sizeof(mQueryContent));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setTSIGKey INSERT", oraerr);
+ }
+
+ release_query(stmt, setTSIGKeyQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setTSIGKey COMMIT", oraerr);
+ }
+
+ return true;
+}
+
+bool
+OracleBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
+{
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, getTSIGKeysQuerySQL, getTSIGKeysQueryKey);
+ define_output_str(stmt, 1, &mResultNameInd, mResultName, sizeof(mResultName));
+ define_output_str(stmt, 2, &mResultTypeInd, mResultType, sizeof(mResultType));
+ define_output_str(stmt, 3, &mResultContentInd, mResultContent, sizeof(mResultContent));
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ while (rc != OCI_NO_DATA) {
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getDomainMetadata", oraerr);
+ }
+
+ check_indicator(mResultNameInd, true);
+ check_indicator(mResultTypeInd, true);
+ check_indicator(mResultContentInd, true);
+
+ struct TSIGKey key;
+
+ key.name = DNSName(mResultName);
+ key.algorithm = DNSName(mResultType);
+ key.key = mResultContent;
+ keys.push_back(key);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ release_query(stmt, getTSIGKeyQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::getDomainKeys (const DNSName& name, unsigned int kind, vector<KeyData>& keys)
+{
+ if(!d_dnssecQueries)
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ stmt = prepare_query(pooledSvcCtx, getZoneKeysQuerySQL, getZoneKeysQueryKey);
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+
+ sb2 key_id_ind = 0;
+ unsigned int key_id = 0;
+ sb2 key_flags_ind = 0;
+ uint16_t key_flags = 0;
+ sb2 key_active_ind = 0;
+ int key_active = 0;
+
+ define_output_uint(stmt, 1, &key_id_ind, &key_id);
+ define_output_uint16(stmt, 2, &key_flags_ind, &key_flags);
+ define_output_int(stmt, 3, &key_active_ind, &key_active);
+ define_output_str(stmt, 4, &mResultContentInd, mResultContent, sizeof(mResultContent));
+
+ rc = OCIStmtExecute(pooledSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ while (rc != OCI_NO_DATA) {
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle getDomainKeys", oraerr);
+ }
+
+ check_indicator(key_id_ind, false);
+ check_indicator(key_flags_ind, false);
+ check_indicator(key_active_ind, false);
+ check_indicator(mResultContentInd, false);
+
+ KeyData kd;
+ kd.id = key_id;
+ kd.flags = key_flags;
+ kd.active = key_active;
+ kd.content = mResultContent;
+ keys.push_back(kd);
+
+ rc = OCIStmtFetch2(stmt, oraerr, 1, OCI_FETCH_NEXT, 0, OCI_DEFAULT);
+ }
+
+ release_query(stmt, getZoneKeysQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::removeDomainKey (const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle removeDomainKey BEGIN", oraerr);
+ }
+
+ stmt = prepare_query(masterSvcCtx, delZoneKeyQuerySQL, delZoneKeyQueryKey);
+ bind_uint(stmt, ":keyid", &id);
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle removeDomainKey DELETE", oraerr);
+ }
+
+ release_query(stmt, delZoneKeyQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle removeDomainKey COMMIT", oraerr);
+ }
+
+ return true;
+}
+
+int
+OracleBackend::addDomainKey (const DNSName& name, const KeyData& key)
+{
+ if(!d_dnssecQueries)
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ int key_id = -1;
+ uint16_t key_flags = key.flags;
+ int key_active = key.active;
+
+ openMasterConnection();
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle addDomainKey BEGIN", oraerr);
+ }
+
+ DNSName_to_cbuf(mQueryName, name, sizeof(mQueryName));
+ string_to_cbuf(mQueryContent, key.content, sizeof(mQueryContent));
+
+ stmt = prepare_query(masterSvcCtx, addZoneKeyQuerySQL, addZoneKeyQueryKey);
+
+ bind_int(stmt, ":keyid", &key_id);
+ bind_str(stmt, ":name", mQueryName, sizeof(mQueryName));
+ bind_uint16(stmt, ":flags", &key_flags);
+ bind_int(stmt, ":active", &key_active);
+ bind_str(stmt, ":content", mQueryContent, sizeof(mQueryContent));
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle addDomainKey INSERT", oraerr);
+ }
+
+ release_query(stmt, addZoneKeyQueryKey);
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle addDomainKey COMMIT", oraerr);
+ }
+
+ return key_id;
+}
+
+bool
+OracleBackend::setDomainKeyState (const DNSName& name, unsigned int id, int active)
+{
+ if(!d_dnssecQueries)
+ return -1;
+ DomainInfo di;
+ if (getDomainInfo(name, di) == false) return false;
+
+ sword rc;
+ OCIStmt *stmt;
+
+ openMasterConnection();
+
+ stmt = prepare_query(masterSvcCtx, setZoneKeyStateQuerySQL, setZoneKeyStateQueryKey);
+ bind_uint(stmt, ":keyid", &id);
+ bind_int(stmt, ":active", &active);
+
+ rc = OCITransStart(masterSvcCtx, oraerr, 60, OCI_TRANS_NEW);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainKeyState BEGIN", oraerr);
+ }
+
+ rc = OCIStmtExecute(masterSvcCtx, stmt, oraerr, 1, 0, NULL, NULL, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainKeyState UPDATE", oraerr);
+ }
+
+ rc = OCITransCommit(masterSvcCtx, oraerr, OCI_DEFAULT);
+
+ if (rc == OCI_ERROR) {
+ throw OracleException("Oracle setDomainKeyState COMMIT", oraerr);
+ }
+
+ release_query(stmt, setZoneKeyStateQueryKey);
+ return true;
+}
+
+bool
+OracleBackend::activateDomainKey (const DNSName& name, unsigned int id)
+{
+ return setDomainKeyState(name, id, 1);
+}
+
+bool
+OracleBackend::deactivateDomainKey (const DNSName& name, unsigned int id)
+{
+ return setDomainKeyState(name, id, 0);
+}
+
+void
+OracleBackend::Cleanup ()
+{
+ sword err;
+
+ if (masterSvcCtx != NULL) {
+ err = OCITransRollback(masterSvcCtx, oraerr, OCI_DEFAULT);
+ // No error check, we don't care if ROLLBACK failed
+ err = OCISessionRelease(masterSvcCtx, oraerr, NULL, 0, OCI_DEFAULT);
+ if (err == OCI_ERROR) {
+ throw OracleException("Oracle cleanup, OCISessionRelease (master)", oraerr);
+ }
+ masterSvcCtx = NULL;
+ OCIHandleFree(masterAuthHandle, OCI_HTYPE_AUTHINFO);
+ masterAuthHandle = NULL;
+ }
+
+ if (pooledSvcCtx != NULL) {
+ err = OCITransRollback(pooledSvcCtx, oraerr, OCI_DEFAULT);
+ // No error check, we don't care if ROLLBACK failed
+ err = OCISessionRelease(pooledSvcCtx, oraerr, NULL, 0, OCI_DEFAULT);
+ if (err == OCI_ERROR) {
+ throw OracleException("Oracle cleanup, OCISessionRelease (pooled)", oraerr);
+ }
+ pooledSvcCtx = NULL;
+ }
+
+ if (oraerr != NULL) {
+ OCIHandleFree(oraerr, OCI_HTYPE_ERROR);
+ oraerr = NULL;
+ }
+}
+
+OCIStmt*
+OracleBackend::prepare_query (OCISvcCtx *orasvc, string& code, const char *key)
+{
+ sword err;
+
+ OCIStmt *handle = NULL;
+
+ err = OCIStmtPrepare2(orasvc, &handle, oraerr, (OraText*) code.c_str(), code.length(), (OraText*) key, strlen(key), OCI_NTV_SYNTAX, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Preparing Oracle statement", oraerr);
+ }
+
+ return handle;
+}
+
+void
+OracleBackend::release_query (OCIStmt *stmt, const char *key)
+{
+ sword err;
+
+ err = OCIStmtRelease(stmt, oraerr, (OraText*)key, strlen(key), OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Releasing Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::define_output_str (OCIStmt *s, ub4 pos, sb2 *ind,
+ char *buf, sb4 buflen)
+{
+ sword err;
+ OCIDefine *handle = NULL;
+
+ err = OCIDefineByPos(s, &handle, oraerr, pos, buf, buflen, SQLT_STR,
+ ind, NULL, NULL, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Defining output for Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::define_output_int (OCIStmt *s, ub4 pos, sb2 *ind, int *buf)
+{
+ sword err;
+ OCIDefine *handle = NULL;
+
+ err = OCIDefineByPos(s, &handle, oraerr, pos, buf, sizeof(int),
+ SQLT_INT, ind, NULL, NULL, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Defining output for Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::define_output_uint (OCIStmt *s, ub4 pos, sb2 *ind, unsigned int *buf)
+{
+ sword err;
+ OCIDefine *handle = NULL;
+
+ err = OCIDefineByPos(s, &handle, oraerr, pos, buf, sizeof(unsigned int),
+ SQLT_UIN, ind, NULL, NULL, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Defining output for Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::define_output_uint16 (OCIStmt *s, ub4 pos, sb2 *ind,
+ uint16_t *buf)
+{
+ sword err;
+ OCIDefine *handle = NULL;
+
+ err = OCIDefineByPos(s, &handle, oraerr, pos, buf, sizeof(uint16_t),
+ SQLT_UIN, ind, NULL, NULL, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Defining output for Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::define_output_uint32 (OCIStmt *s, ub4 pos, sb2 *ind,
+ uint32_t *buf)
+{
+ sword err;
+ OCIDefine *handle = NULL;
+
+ err = OCIDefineByPos(s, &handle, oraerr, pos, buf, sizeof(uint32_t),
+ SQLT_UIN, ind, NULL, NULL, OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Defining output for Oracle statement", oraerr);
+ }
+}
+
+void
+OracleBackend::check_indicator (sb2 ind, bool null_okay)
+{
+ if ((!null_okay) && (ind == -1)) {
+ throw OracleException("Received NULL where a value was expected");
+ }
+
+ if ((ind < -1) || (ind > 0)) {
+ throw OracleException("Return value truncated");
+ }
+}
+
+void
+OracleBackend::define_fwd_query (OCIStmt *s)
+{
+ const ub4 n = 100;
+ sword err = OCIAttrSet(s, OCI_HTYPE_STMT, (void*) &n, sizeof(ub4),
+ OCI_ATTR_PREFETCH_ROWS, oraerr);
+
+ if (err == OCI_ERROR) {
+ throw OracleException("Activating row prefetching", oraerr);
+ }
+
+ define_output_str(s, 1, &mResultNameInd,
+ mResultName, sizeof(mResultName));
+ define_output_uint32(s, 2, &mResultTTLInd, &mResultTTL);
+ define_output_str(s, 3, &mResultTypeInd,
+ mResultType, sizeof(mResultType));
+ define_output_str(s, 4, &mResultContentInd,
+ mResultContent, sizeof(mResultContent));
+ define_output_int(s, 5, &mResultZoneIdInd, &mResultZoneId);
+ define_output_int(s, 6, &mResultLastChangeInd, &mResultLastChange);
+ if (d_dnssecQueries)
+ define_output_int(s, 7, &mResultIsAuthInd, &mResultIsAuth);
+}
+
+void
+OracleBackend::bind_str (OCIStmt *s, const char *name, char *buf, sb4 buflen)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, buflen, SQLT_STR,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_str (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_str_failokay (OCIStmt *s, const char *name,
+ char *buf, sb4 buflen)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, buflen, SQLT_STR,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ (void)err;
+}
+
+void
+OracleBackend::bind_str_ind (OCIStmt *s, const char *name,
+ char *buf, sb4 buflen, sb2 *ind)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, buflen, SQLT_STR,
+ ind, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_str_ind (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_int (OCIStmt *s, const char *name, int *buf)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, sizeof(int), SQLT_INT,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_int (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_uint (OCIStmt *s, const char *name, unsigned int *buf)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, sizeof(unsigned int), SQLT_UIN,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_uint (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_uint16 (OCIStmt *s, const char *name, uint16_t *buf)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, sizeof(uint16_t), SQLT_UIN,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_uint16 (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_uint16_ind (OCIStmt *s, const char *name, uint16_t *buf,
+ sb2 *ind)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, sizeof(uint16_t), SQLT_UIN,
+ ind, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_uint16_ind (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+void
+OracleBackend::bind_uint32 (OCIStmt *s, const char *name, uint32_t *buf)
+{
+ sword err;
+ OCIBind *handle = NULL;
+
+ err = OCIBindByName(s, &handle, oraerr,
+ (OraText*) name, strlen(name),
+ buf, sizeof(uint32_t), SQLT_UIN,
+ NULL, NULL, NULL, 0, NULL,
+ OCI_DEFAULT);
+
+ if (err == OCI_ERROR) {
+ string msg;
+ msg.append("Oracle bind_uint32 (\"");
+ msg.append(name);
+ msg.append("\")");
+ throw OracleException(msg, oraerr);
+ }
+}
+
+
+class OracleFactory : public BackendFactory
+{
+private:
+ pthread_mutex_t factoryLock;
+ OCIEnv *oraenv;
+ OCIError *oraerr;
+ OCISPool *mSessionPoolHandle;
+ text *mSessionPoolName;
+ ub4 mSessionPoolNameLen;
+
+ void CreateSessionPool ()
+ {
+ sword err;
+
+ try {
+ // set some envionment variables
+ setenv("ORACLE_HOME", arg()["oracle-home"].c_str(), 1);
+ setenv("ORACLE_SID", arg()["oracle-sid"].c_str(), 1);
+ setenv("NLS_LANG", arg()["oracle-nls-lang"].c_str(), 1);
+
+ // Initialize and create the environment
+ err = OCIEnvCreate(&oraenv, OCI_THREADED, NULL, NULL,
+ NULL, NULL, 0, NULL);
+ if (err == OCI_ERROR) {
+ throw OracleException("OCIEnvCreate");
+ }
+ // Allocate an error handle
+ err = OCIHandleAlloc(oraenv, (void**) &oraerr,
+ OCI_HTYPE_ERROR, 0, NULL);
+ if (err == OCI_ERROR) {
+ throw OracleException("OCIHandleAlloc");
+ }
+
+ const char *dbname = arg()["oracle-pool-database"].c_str();
+ const char *dbuser = arg()["oracle-pool-username"].c_str();
+ const char *dbpass = arg()["oracle-pool-password"].c_str();
+
+ ub4 sess_min = arg().asNum("oracle-session-min");
+ ub4 sess_max = arg().asNum("oracle-session-max");
+ ub4 sess_inc = arg().asNum("oracle-session-inc");
+ ub4 get_mode = OCI_SPOOL_ATTRVAL_NOWAIT;
+
+ // Create a session pool
+ err = OCIHandleAlloc(oraenv, (void**) &mSessionPoolHandle,
+ OCI_HTYPE_SPOOL, 0, NULL);
+ if (err == OCI_ERROR) {
+ throw OracleException("OCIHandleAlloc");
+ }
+ err = OCISessionPoolCreate(oraenv, oraerr,
+ mSessionPoolHandle,
+ (OraText **) &mSessionPoolName,
+ &mSessionPoolNameLen,
+ (OraText *) dbname, strlen(dbname),
+ sess_min, sess_max, sess_inc,
+ (OraText *) dbuser, strlen(dbuser),
+ (OraText *) dbpass, strlen(dbpass),
+ OCI_SPC_STMTCACHE | OCI_SPC_HOMOGENEOUS);
+ if (err == OCI_ERROR) {
+ throw OracleException("Creating Oracle session pool", oraerr);
+ }
+
+ // Set session pool NOWAIT
+ err = OCIAttrSet(mSessionPoolHandle, OCI_HTYPE_SPOOL, &get_mode, 0, OCI_ATTR_SPOOL_GETMODE, oraerr);
+ if (err == OCI_ERROR) {
+ throw OracleException("Setting session pool get mode", oraerr);
+ }
+ } catch (OracleException &theException) {
+ L << Logger::Critical << "OracleFactory: "
+ << theException.reason << endl;
+ Cleanup();
+ throw theException;
+ }
+ }
+
+ void Cleanup ()
+ {
+ sword err;
+
+ if (mSessionPoolHandle != NULL) {
+ try {
+ err = OCISessionPoolDestroy(mSessionPoolHandle, oraerr,
+ OCI_SPD_FORCE);
+ OCIHandleFree(mSessionPoolHandle, OCI_HTYPE_SPOOL);
+ mSessionPoolHandle = NULL;
+ if (err == OCI_ERROR) {
+ throw OracleException("OCISessionPoolDestroy", oraerr);
+ }
+ } catch (OracleException &theException) {
+ L << Logger::Error << "Failed to destroy Oracle session pool: "
+ << theException.reason << endl;
+ }
+ }
+
+ if (oraerr != NULL) {
+ OCIHandleFree(oraerr, OCI_HTYPE_ERROR);
+ oraerr = NULL;
+ }
+
+ if (oraenv != NULL) {
+ OCIHandleFree(oraenv, OCI_HTYPE_ENV);
+ oraenv = NULL;
+ }
+ }
+
+public:
+
+OracleFactory () : BackendFactory("oracle") {
+ pthread_mutex_init(&factoryLock, NULL);
+ oraenv = NULL;
+ oraerr = NULL;
+ mSessionPoolHandle = NULL;
+ mSessionPoolName = NULL;
+ mSessionPoolNameLen = 0;
+ }
+
+ ~OracleFactory () {
+ Cleanup();
+ pthread_mutex_destroy(&factoryLock);
+ }
+
+ void declareArguments (const string & suffix = "") {
+ declare(suffix,"home", "Oracle home path", "");
+ declare(suffix,"sid", "Oracle sid", "XE");
+ declare(suffix,"nls-lang", "Oracle language", "AMERICAN_AMERICA.AL32UTF8");
+
+ declare(suffix, "pool-database", "Database to connect to for the session pool", "powerdns");
+ declare(suffix, "pool-username", "Username to connect as for the session pool", "powerdns");
+ declare(suffix, "pool-password", "Password to connect with for the session pool", "");
+ declare(suffix, "session-min", "Number of sessions to open at startup", "4");
+ declare(suffix, "session-inc", "Number of sessions to open when growing", "2");
+ declare(suffix, "session-max", "Max number of sessions to have open", "20");
+ declare(suffix, "master-database", "Database to connect to for write access", "powerdns");
+ declare(suffix, "master-username", "Username to connect as for write access", "powerdns");
+ declare(suffix, "master-password", "Password to connect with for write access", "");
+ declare(suffix, "dnssec", "Assume DNSSEC Schema is in place", "no");
+ declare(suffix, "nameserver-name", "", "");
+
+ declare(suffix, "basic-query", "", basicQueryDefaultSQL);
+ declare(suffix, "basic-query-auth", "", basicQueryDefaultAuthSQL);
+ declare(suffix, "basic-id-query", "", basicIdQueryDefaultSQL);
+ declare(suffix, "basic-id-query-auth", "", basicIdQueryDefaultAuthSQL);
+ declare(suffix, "any-query", "", anyQueryDefaultSQL);
+ declare(suffix, "any-query-auth", "", anyQueryDefaultAuthSQL);
+ declare(suffix, "any-id-query", "", anyIdQueryDefaultSQL);
+ declare(suffix, "any-id-query-auth", "", anyIdQueryDefaultAuthSQL);
+ declare(suffix, "list-query", "", listQueryDefaultSQL);
+ declare(suffix, "list-query-auth", "", listQueryDefaultAuthSQL);
+ declare(suffix, "zone-info-query", "", zoneInfoQueryDefaultSQL);
+ declare(suffix, "also-notify-query", "", alsoNotifyQueryDefaultSQL);
+ declare(suffix, "zone-masters-query", "", zoneMastersQueryDefaultSQL);
+ declare(suffix, "is-zone-master-query", "", isZoneMasterQueryDefaultSQL);
+ declare(suffix, "delete-zone-query", "", deleteZoneQueryDefaultSQL);
+ declare(suffix, "zone-set-last-check-query", "", zoneSetLastCheckQueryDefaultSQL);
+ declare(suffix, "zone-set-notified-serial-query", "", zoneSetNotifiedSerialQueryDefaultSQL);
+ declare(suffix, "insert-record-query", "", insertRecordQueryDefaultSQL);
+ declare(suffix, "finalize-axfr-query", "", finalizeAXFRQueryDefaultSQL);
+ declare(suffix, "unfresh-zones-query", "", unfreshZonesQueryDefaultSQL);
+ declare(suffix, "updated-masters-query", "", updatedMastersQueryDefaultSQL);
+ declare(suffix, "accept-supernotification-query", "", acceptSupernotificationQueryDefaultSQL);
+ declare(suffix, "insert-slave-query", "", insertSlaveQueryDefaultSQL);
+ declare(suffix, "insert-master-query", "", insertMasterQueryDefaultSQL);
+ declare(suffix, "prev-next-name-query", "", prevNextNameQueryDefaultSQL);
+ declare(suffix, "prev-next-hash-query", "", prevNextHashQueryDefaultSQL);
+
+ declare(suffix, "get-all-zone-metadata-query", "", getAllZoneMetadataQueryDefaultSQL);
+ declare(suffix, "get-zone-metadata-query", "", getZoneMetadataQueryDefaultSQL);
+ declare(suffix, "del-zone-metadata-query", "", delZoneMetadataQueryDefaultSQL);
+ declare(suffix, "set-zone-metadata-query", "", setZoneMetadataQueryDefaultSQL);
+
+ declare(suffix, "get-tsig-key-query", "", getTSIGKeyQueryDefaultSQL);
+ declare(suffix, "del-tsig-key-query", "", delTSIGKeyQueryDefaultSQL);
+ declare(suffix, "set-tsig-key-query", "", setTSIGKeyQueryDefaultSQL);
+ declare(suffix, "get-tsig-keys-query", "", getTSIGKeysQueryDefaultSQL);
+
+ declare(suffix, "get-zone-keys-query", "", getZoneKeysQueryDefaultSQL);
+ declare(suffix, "del-zone-key-query", "", delZoneKeyQueryDefaultSQL);
+ declare(suffix, "add-zone-key-query", "", addZoneKeyQueryDefaultSQL);
+ declare(suffix, "set-zone-key-state-query", "", setZoneKeyStateQueryDefaultSQL);
+ }
+
+ DNSBackend *make (const string & suffix = "") {
+ {
+ Lock l(&factoryLock);
+ if (oraenv == NULL) {
+ CreateSessionPool();
+ }
+ }
+ return new OracleBackend(suffix, oraenv,
+ (char *) mSessionPoolName);
+ }
+
+};
+
+
+//! Magic class that is activated when the dynamic library is loaded
+class OracleLoader
+{
+public:
+
+ OracleLoader()
+ {
+ BackendMakers().report(new OracleFactory);
+ L << Logger::Info << "[oraclebackend] This is the oracle backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+
+};
+
+static OracleLoader loader;
+
+/* vi: set sw=2 et : */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ * originally authored by Maik Zumstrull
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_ORACLEBACKEND_HH
+#define PDNS_ORACLEBACKEND_HH
+
+#include <string>
+#include <map>
+#include <fstream>
+
+#include <oci.h>
+
+#include "pdns/namespaces.hh"
+
+class OracleException : public DBException
+{
+public:
+
+ OracleException (string r) : DBException(r) {}
+
+ OracleException (string context, OCIError *theErrorHandle)
+ : DBException(context + ": ORA-UNKNOWN")
+ {
+ if (theErrorHandle != NULL) {
+ char msg[2048];
+ sb4 errcode = 0;
+
+ msg[0] = '\0';
+
+ OCIErrorGet((void *) theErrorHandle, 1, NULL, &errcode, (OraText*) msg,
+ sizeof(msg), OCI_HTYPE_ERROR);
+
+ reason = context + ": " + msg;
+ }
+ }
+
+};
+
+class OracleBackend : public DNSBackend
+{
+public:
+
+ OracleBackend(const string &suffix = "", OCIEnv *envh =
+ NULL, char *poolname = NULL);
+ virtual ~OracleBackend();
+
+ void lookup(const QType &qtype, const DNSName& qname, DNSPacket *p = 0,
+ int zoneId = -1);
+
+ bool getBeforeAndAfterNames(uint32_t zoneId, const DNSName& zone,
+ const DNSName& name,
+ DNSName& before, DNSName& after);
+ bool getBeforeAndAfterNamesAbsolute(uint32_t zoneId,
+ const string& name,
+ DNSName& unhashed,
+ string& before,
+ string& after);
+ bool get(DNSResourceRecord &rr);
+ vector<string> getDomainMasters(const DNSName& domain, int zoneId);
+ bool isMaster(const DNSName& domain, const string &master);
+ bool getDomainInfo(const DNSName& domain, DomainInfo &di);
+ void alsoNotifies(const DNSName& domain, set<string> *addrs);
+ void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+ void getUpdatedMasters(vector<DomainInfo>* domains);
+ void setFresh(uint32_t zoneId);
+ void setNotified(uint32_t zoneId, uint32_t serial);
+ bool list(const DNSName& domain, int zoneId, bool include_disabled=false);
+ bool startTransaction(const DNSName& domain, int zoneId);
+ bool feedRecord(const DNSResourceRecord &rr, string* ordername);
+ bool commitTransaction();
+ bool abortTransaction();
+ bool superMasterBackend(const string &ip, const DNSName& domain,
+ const vector<DNSResourceRecord> &nsset,
+ string *account, string *nameserver,
+ DNSBackend **backend);
+ bool createSlaveDomain(const string &ip, const DNSName& domain,
+ const string &nameserver, const string &account);
+
+ bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta);
+
+ bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content);
+ bool delTSIGKey(const DNSName& name);
+ bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
+ bool getTSIGKeys(std::vector< struct TSIGKey > &keys);
+
+ bool getDomainKeys(const DNSName& name, unsigned int kind, vector<KeyData>& keys);
+ bool removeDomainKey(const DNSName& name, unsigned int id);
+ int addDomainKey(const DNSName& name, const KeyData& key);
+ bool activateDomainKey(const DNSName& name, unsigned int id);
+ bool deactivateDomainKey(const DNSName& name, unsigned int id);
+
+private:
+
+ OCIEnv *oraenv;
+ OCIError *oraerr;
+ OCISvcCtx *pooledSvcCtx;
+ OCIAuthInfo *masterAuthHandle;
+ OCISvcCtx *masterSvcCtx;
+
+ string basicQuerySQL;
+ string basicIdQuerySQL;
+ string anyQuerySQL;
+ string anyIdQuerySQL;
+ string listQuerySQL;
+
+ string zoneInfoQuerySQL;
+ string alsoNotifyQuerySQL;
+ string zoneMastersQuerySQL;
+ string isZoneMasterQuerySQL;
+ string deleteZoneQuerySQL;
+ string zoneSetLastCheckQuerySQL;
+
+ string insertRecordQuerySQL;
+ string finalizeAXFRQuerySQL;
+
+ string unfreshZonesQuerySQL;
+ string updatedMastersQuerySQL;
+ string acceptSupernotificationQuerySQL;
+ string insertSlaveQuerySQL;
+ string insertMasterQuerySQL;
+ string zoneSetNotifiedSerialQuerySQL;
+
+ string prevNextNameQuerySQL;
+ string prevNextHashQuerySQL;
+
+ string getAllZoneMetadataQuerySQL;
+ string getZoneMetadataQuerySQL;
+ string delZoneMetadataQuerySQL;
+ string setZoneMetadataQuerySQL;
+
+ string getTSIGKeyQuerySQL;
+ string delTSIGKeyQuerySQL;
+ string setTSIGKeyQuerySQL;
+ string getTSIGKeysQuerySQL;
+
+ string getZoneKeysQuerySQL;
+ string delZoneKeyQuerySQL;
+ string addZoneKeyQuerySQL;
+ string setZoneKeyStateQuerySQL;
+
+ OCIStmt *curStmtHandle;
+ const char *curStmtKey;
+ int openTransactionZoneID;
+
+ char myServerName[512];
+
+ char mQueryName[512];
+ char mQueryType[64];
+ char mQueryContent[4001];
+ char mQueryZone[512];
+ char mQueryAddr[64];
+ int mQueryZoneId;
+ int mQueryTimestamp;
+
+ char mResultName[512];
+ sb2 mResultNameInd;
+ uint32_t mResultTTL;
+ sb2 mResultTTLInd;
+ char mResultType[64];
+ sb2 mResultTypeInd;
+ char mResultContent[4001];
+ sb2 mResultContentInd;
+ int mResultZoneId;
+ sb2 mResultZoneIdInd;
+ int mResultLastChange;
+ sb2 mResultLastChangeInd;
+ int mResultIsAuth;
+ sb2 mResultIsAuthInd;
+ char mResultPrevName[512];
+ sb2 mResultPrevNameInd;
+ char mResultNextName[512];
+ sb2 mResultNextNameInd;
+ bool d_dnssecQueries;
+
+ void Cleanup();
+
+ void openMasterConnection();
+ bool setDomainKeyState(const DNSName& name, unsigned int id, int active);
+
+ OCIStmt* prepare_query (OCISvcCtx* orasvc, string& code, const char *key);
+ void release_query (OCIStmt *stmt, const char *key);
+ void define_output_str (OCIStmt *s, ub4 pos, sb2 *ind, char *buf, sb4 buflen);
+ void define_output_int (OCIStmt *s, ub4 pos, sb2 *ind, int *buf);
+ void define_output_uint (OCIStmt *s, ub4 pos, sb2 *ind, unsigned int *buf);
+ void define_output_uint16 (OCIStmt *s, ub4 pos, sb2 *ind, uint16_t *buf);
+ void define_output_uint32 (OCIStmt *s, ub4 pos, sb2 *ind, uint32_t *buf);
+ void check_indicator (sb2 ind, bool null_okay);
+ void define_fwd_query (OCIStmt *s);
+ void bind_str (OCIStmt *s, const char *name, char *buf, sb4 buflen);
+ void bind_str_failokay (OCIStmt *s, const char *name, char *buf, sb4 buflen);
+ void bind_str_ind (OCIStmt *s, const char *name, char *buf, sb4 buflen, sb2 *ind);
+ void bind_int (OCIStmt *s, const char *name, int *buf);
+ void bind_uint (OCIStmt *s, const char *name, unsigned int *buf);
+ void bind_uint16 (OCIStmt *s, const char *name, uint16_t *buf);
+ void bind_uint16_ind (OCIStmt *s, const char *name, uint16_t *buf, sb2 *ind);
+ void bind_uint32 (OCIStmt *s, const char *name, uint32_t *buf);
+
+};
+
+#endif /* PDNS_ORACLEBACKEND_HH */
--- /dev/null
+-- THIS IS NOT PRODUCTION-QUALITY CODE
+--
+-- This database schema is meant to serve as documentation-by-example for how
+-- certain things might be done. It has also been used for early testing of the
+-- backend. It should not be deployed as-is.
+
+CREATE SEQUENCE zones_id_seq;
+
+CREATE TABLE Zones (
+ id INTEGER CONSTRAINT pkey_zones PRIMARY KEY,
+ name VARCHAR2(512) NOT NULL,
+ type VARCHAR2(32) NOT NULL,
+ last_check INTEGER,
+ refresh NUMBER(10,0),
+ serial NUMBER(10,0) DEFAULT 0 NOT NULL,
+ notified_serial NUMBER(10,0),
+ CONSTRAINT chk_zones_name CHECK (name = lower(name)),
+ CONSTRAINT unq_zones_name UNIQUE (name),
+ CONSTRAINT chk_zones_type CHECK (
+ type IN ('NATIVE', 'MASTER', 'SLAVE')
+ AND (type = 'SLAVE' OR last_check IS NULL)
+ ),
+ CONSTRAINT chk_zones_serial CHECK (serial BETWEEN 0 AND 4294967295),
+ CONSTRAINT chk_zones_nserial CHECK (notified_serial BETWEEN 0 AND 4294967295),
+ CONSTRAINT chk_zones_refresh CHECK (refresh BETWEEN 0 AND 4294967295),
+ CONSTRAINT chk_zones_master CHECK (type = 'MASTER' OR notified_serial IS NULL)
+);
+
+CREATE INDEX zones_type_ind ON Zones (type);
+
+
+CREATE TABLE Zonemasters (
+ zone_id INTEGER NOT NULL CONSTRAINT fkey_zonemasters_zones REFERENCES Zones ON DELETE CASCADE,
+ master VARCHAR2(512) NOT NULL,
+ CONSTRAINT unq_zonemasters_zone_master UNIQUE (zone_id, master)
+);
+
+CREATE INDEX zonemasters_zone_id_ind ON Zonemasters (zone_id);
+
+
+CREATE TABLE ZoneAlsoNotify (
+ zone_id INTEGER NOT NULL CONSTRAINT fkey_zonealsonotify_zones REFERENCES Zones ON DELETE CASCADE,
+ hostaddr VARCHAR2(512) NOT NULL,
+ CONSTRAINT unq_zonealsonotify_zone_host UNIQUE (zone_id, hostaddr)
+);
+
+CREATE INDEX zonealsonotify_zone_id_ind ON ZoneAlsoNotify (zone_id);
+
+
+CREATE SEQUENCE supermasters_id_seq;
+
+CREATE TABLE Supermasters (
+ id INTEGER CONSTRAINT pkey_supermasters PRIMARY KEY,
+ name VARCHAR2(64) NOT NULL,
+ ip VARCHAR2(64) NOT NULL,
+ nameserver VARCHAR2(512) NOT NULL
+);
+
+CREATE INDEX supermasters_ip_ind ON Supermasters (ip);
+
+
+CREATE TABLE ZoneMetadata (
+ zone_id INTEGER NOT NULL CONSTRAINT fkey_zonemetadata_zones REFERENCES Zones,
+ meta_type VARCHAR2(64) NOT NULL,
+ meta_ind INTEGER NOT NULL,
+ meta_content VARCHAR2(4000),
+ CONSTRAINT pkey_zonemetadata PRIMARY KEY (zone_id, meta_type, meta_ind)
+);
+
+
+CREATE SEQUENCE zonednskeys_id_seq;
+
+CREATE TABLE ZoneDNSKeys (
+ id INTEGER CONSTRAINT pkey_zonednskeys PRIMARY KEY,
+ zone_id INTEGER NOT NULL CONSTRAINT fkey_zonednskeys_zones REFERENCES Zones,
+ flags NUMBER(5,0) NOT NULL,
+ active NUMBER(1,0) NOT NULL,
+ keydata VARCHAR2(4000) NOT NULL,
+ CONSTRAINT chk_zonednskeys_flags CHECK (flags BETWEEN 0 AND 65535),
+ CONSTRAINT chk_zonednskeys_active CHECK (active IN (0, 1))
+);
+
+CREATE INDEX zonednskeys_zone_ind ON ZoneDNSKeys (zone_id);
+
+
+CREATE TABLE TSIGKeys (
+ name VARCHAR2(256),
+ algorithm VARCHAR2(64) NOT NULL,
+ secret VARCHAR2(2048) NOT NULL,
+ CONSTRAINT chk_tsigkeys_name CHECK (name = lower(name)),
+ CONSTRAINT chk_tsigkeys_algorithm CHECK (algorithm = lower(algorithm)),
+ CONSTRAINT unq_tsigkeys_nav UNIQUE (name, algorithm, secret)
+);
+
+
+CREATE TABLE AccessControlList (
+ acl_type VARCHAR2(64) NOT NULL,
+ acl_key VARCHAR2(256) NOT NULL,
+ acl_val VARCHAR2(2048),
+ CONSTRAINT chk_acl_type CHECK (acl_type = 'allow-axfr'),
+ CONSTRAINT unq_acl_tkv UNIQUE (acl_type, acl_key, acl_val)
+);
+
+CREATE INDEX acl_tk ON AccessControlList (acl_type, acl_key);
+
+
+CREATE SEQUENCE records_id_seq;
+
+CREATE TABLE Records (
+ id INTEGER CONSTRAINT pkey_records PRIMARY KEY,
+ zone_id INTEGER NOT NULL CONSTRAINT fkey_records_zones REFERENCES Zones,
+ fqdn VARCHAR2(512) NOT NULL,
+ revfqdn VARCHAR2(512) NOT NULL,
+ fqdnhash VARCHAR2(512),
+ ttl NUMBER(10,0) NOT NULL,
+ type VARCHAR2(32),
+ content VARCHAR2(2048),
+ last_change INTEGER DEFAULT 0 NOT NULL,
+ auth NUMBER(1,0) DEFAULT 1 NOT NULL,
+ CONSTRAINT chk_records_fqdn CHECK (fqdn = lower(fqdn)),
+ CONSTRAINT chk_records_ttl CHECK (ttl BETWEEN 0 AND 4294967295),
+ CONSTRAINT chk_records_type CHECK (type = upper(type)),
+ CONSTRAINT unq_records_zntc UNIQUE (zone_id, fqdn, type, content),
+ CONSTRAINT chk_records_tc CHECK (
+ content IS NOT NULL OR
+ type IN('NS', 'CNAME') OR
+ type IS NULL
+ ),
+ CONSTRAINT chk_records_auth CHECK (auth IN (0, 1))
+);
+
+CREATE INDEX records_zone_id_ind ON Records (zone_id);
+CREATE INDEX records_revfqdn_ind ON Records (zone_id, revfqdn);
+CREATE INDEX records_fqdnhash_ind ON Records (zone_id, fqdnhash);
+CREATE INDEX records_last_change_ind ON Records (last_change);
+
+-- Only one SOA and NSEC3PARAM record per zone
+CREATE UNIQUE INDEX records_zonesoa_unq_ind ON Records (
+ CASE
+ WHEN type IN ('SOA', 'NSEC3PARAM') THEN zone_id
+ ELSE NULL
+ END,
+ CASE
+ WHEN type IN ('SOA', 'NSEC3PARAM') THEN type
+ ELSE NULL
+ END
+);
+
+
+CREATE FUNCTION label_reverse (dnsname IN VARCHAR2) RETURN VARCHAR2 AS
+ pattern VARCHAR2(32) := '[^.]+';
+ match BINARY_INTEGER := 1;
+ label VARCHAR2(63);
+ out_dnsname VARCHAR2(512);
+BEGIN
+ label := REGEXP_SUBSTR(dnsname, pattern, 1, match);
+ match := match + 1;
+ out_dnsname := label;
+ LOOP
+ label := REGEXP_SUBSTR(dnsname, pattern, 1, match);
+ EXIT WHEN label IS NULL;
+ out_dnsname := label || ' ' || out_dnsname;
+ match := match + 1;
+ END LOOP;
+ RETURN(out_dnsname);
+END;
+/
+
+SHOW ERRORS
+
+CREATE FUNCTION dnsname_to_raw (in_dnsname IN VARCHAR2) RETURN RAW AS
+ dnsname VARCHAR2(512) := LOWER(in_dnsname);
+ rawname RAW(512);
+
+ lpos BINARY_INTEGER := 1;
+ rpos BINARY_INTEGER;
+ label VARCHAR2(63);
+
+ TYPE convarray IS VARRAY(64) OF RAW(1);
+ byteval convarray := convarray(
+ '00', '01', '02', '03', '04', '05', '06', '07',
+ '08', '09', '0A', '0B', '0C', '0D', '0E', '0F',
+ '10', '11', '12', '13', '14', '15', '16', '17',
+ '18', '19', '1A', '1B', '1C', '1D', '1E', '1F',
+ '20', '21', '22', '23', '24', '25', '26', '27',
+ '28', '29', '2A', '2B', '2C', '2D', '2E', '2F',
+ '30', '31', '32', '33', '34', '35', '36', '37',
+ '38', '39', '3A', '3B', '3C', '3D', '3E', '3F'
+ );
+BEGIN
+ IF dnsname IS NULL THEN
+ RETURN('00');
+ END IF;
+
+ WHILE lpos <= LENGTH(dnsname) LOOP
+ rpos := INSTR(dnsname, '.', lpos);
+ IF rpos = 0 THEN
+ rpos := LENGTH(dnsname) + 1;
+ END IF;
+ label := SUBSTR(dnsname, lpos, rpos - lpos);
+ rawname := UTL_RAW.CONCAT(
+ rawname,
+ byteval(LENGTH(label) + 1),
+ UTL_I18N.STRING_TO_RAW(label, 'US7ASCII')
+ );
+ lpos := rpos + 1;
+ END LOOP;
+
+ IF rpos = LENGTH(dnsname) THEN
+ rawname := UTL_RAW.CONCAT(rawname, '00');
+ END IF;
+
+ RETURN(rawname);
+END;
+/
+
+SHOW ERRORS
+
+-- This is clearly terrible, though it appears to work.
+-- For real deployment, you could upload the dnsjava
+-- library into your database and use its facilities.
+CREATE FUNCTION base32hex_encode (
+ in_string RAW
+) RETURN VARCHAR2 AS
+ off BINARY_INTEGER := 1;
+ out_string VARCHAR2(6554);
+ sub RAW(5);
+ num INTEGER;
+ TYPE convarray IS VARRAY(32) OF VARCHAR2(1);
+ digit convarray := convarray(
+ '0', '1', '2', '3', '4', '5', '6', '7',
+ '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
+ 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n',
+ 'o', 'p', 'q', 'r', 's', 't', 'u', 'v'
+ );
+BEGIN
+
+ WHILE off + 4 <= UTL_RAW.LENGTH(in_string) LOOP
+ sub := UTL_RAW.SUBSTR(in_string, off, 2);
+ num := TO_NUMBER(sub, 'XXXX');
+ out_string := out_string
+ || digit(FLOOR(num / 2048) + 1)
+ || digit(FLOOR(MOD(num / 64, 32)) + 1)
+ || digit(FLOOR(MOD(num / 2, 32)) + 1);
+ sub := UTL_RAW.SUBSTR(in_string, off + 1, 3);
+ num := TO_NUMBER(sub, 'XXXXXX');
+ out_string := out_string
+ || digit(FLOOR(MOD(num / 4096, 32)) + 1)
+ || digit(FLOOR(MOD(num / 128, 32)) + 1)
+ || digit(FLOOR(MOD(num / 4, 32)) + 1);
+ sub := UTL_RAW.SUBSTR(in_string, off + 3, 2);
+ num := TO_NUMBER(sub, 'XXXX');
+ out_string := out_string
+ || digit(FLOOR(MOD(num / 32, 32)) + 1)
+ || digit(FLOOR(MOD(num, 32)) + 1);
+ off := off + 5;
+ END LOOP;
+
+ IF off <= UTL_RAW.LENGTH(in_string) THEN
+ sub := UTL_RAW.SUBSTR(in_string, off);
+ CASE UTL_RAW.LENGTH(sub)
+ WHEN 1 THEN
+ num := TO_NUMBER(sub, 'XX');
+ out_string := out_string
+ || digit(FLOOR(num / 8) + 1)
+ || digit(FLOOR(MOD(num, 8)) * 4 + 1);
+ WHEN 2 THEN
+ num := TO_NUMBER(sub, 'XXXX');
+ out_string := out_string
+ || digit(FLOOR(num / 2048) + 1)
+ || digit(FLOOR(MOD(num / 64, 32)) + 1)
+ || digit(FLOOR(MOD(num / 2, 32)) + 1)
+ || digit(FLOOR(MOD(num, 2)) * 16 + 1);
+ WHEN 3 THEN
+ num := TO_NUMBER(sub, 'XXXXXX');
+ out_string := out_string
+ || digit(FLOOR(num / 524288) + 1)
+ || digit(FLOOR(MOD(num / 16384, 32)) + 1)
+ || digit(FLOOR(MOD(num / 512, 32)) + 1)
+ || digit(FLOOR(MOD(num / 16, 32)) + 1)
+ || digit(FLOOR(MOD(num, 16)) * 2 + 1);
+ WHEN 4 THEN
+ num := TO_NUMBER(sub, 'XXXXXXXX');
+ out_string := out_string
+ || digit(FLOOR(num / 134217728) + 1)
+ || digit(FLOOR(MOD(num / 4194304, 32)) + 1)
+ || digit(FLOOR(MOD(num / 131072, 32)) + 1)
+ || digit(FLOOR(MOD(num / 4096, 32)) + 1)
+ || digit(FLOOR(MOD(num / 128, 32)) + 1)
+ || digit(FLOOR(MOD(num / 4, 32)) + 1)
+ || digit(FLOOR(MOD(num, 4)) * 8 + 1);
+ END CASE;
+ END IF;
+
+ RETURN(out_string);
+END;
+/
+
+SHOW ERRORS
+
+CREATE FUNCTION dnsname_to_hashname (
+ in_dnsname IN VARCHAR2,
+ salt RAW,
+ itercnt BINARY_INTEGER
+) RETURN VARCHAR2 AS
+ rawname RAW(512) := dnsname_to_raw(RTRIM(in_dnsname, '.') || '.');
+ rawsalt RAW(32) := salt;
+ hashname RAW(64);
+ iter BINARY_INTEGER := 0;
+BEGIN
+ hashname := UTL_RAW.CONCAT(rawname, rawsalt);
+ hashname := DBMS_CRYPTO.HASH(hashname, DBMS_CRYPTO.HASH_SH1);
+ WHILE iter < itercnt LOOP
+ hashname := UTL_RAW.CONCAT(hashname, rawsalt);
+ hashname := DBMS_CRYPTO.HASH(hashname, DBMS_CRYPTO.HASH_SH1);
+ iter := iter + 1;
+ END LOOP;
+ RETURN(base32hex_encode(hashname));
+END;
+/
+
+SHOW ERRORS
+
+CREATE PROCEDURE get_canonical_prev_next (
+ in_zone_id INTEGER,
+ in_fqdn VARCHAR2,
+ out_prev OUT VARCHAR2,
+ out_next OUT VARCHAR2
+) AS
+BEGIN
+ SELECT * INTO out_prev
+ FROM (
+ SELECT fqdn
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND revfqdn <= label_reverse(LOWER(in_fqdn))
+ AND auth = 1
+ ORDER BY revfqdn DESC
+ ) WHERE ROWNUM = 1;
+
+ BEGIN
+ SELECT * INTO out_next
+ FROM (
+ SELECT fqdn
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND revfqdn > label_reverse(LOWER(in_fqdn))
+ AND auth = 1
+ ORDER BY revfqdn ASC
+ ) WHERE ROWNUM = 1;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ SELECT name INTO out_next
+ FROM Zones
+ WHERE id = in_zone_id;
+ END;
+END;
+/
+
+SHOW ERRORS
+
+CREATE PROCEDURE get_hashed_prev_next (
+ in_zone_id INTEGER,
+ in_fqdnhash VARCHAR2,
+ out_fqdn OUT VARCHAR2,
+ out_prev OUT VARCHAR2,
+ out_next OUT VARCHAR2
+) AS
+BEGIN
+ BEGIN
+ SELECT * INTO out_prev, out_fqdn
+ FROM (
+ SELECT fqdnhash, fqdn
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND fqdnhash <= in_fqdnhash
+ AND auth = 1
+ ORDER BY fqdnhash DESC
+ ) WHERE ROWNUM = 1;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ SELECT * INTO out_prev, out_fqdn
+ FROM (
+ SELECT fqdnhash, fqdn
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND auth = 1
+ ORDER BY fqdnhash DESC
+ ) WHERE ROWNUM = 1;
+ END;
+
+ BEGIN
+ SELECT * INTO out_next
+ FROM (
+ SELECT fqdnhash
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND fqdnhash > in_fqdnhash
+ AND auth = 1
+ ORDER BY fqdnhash ASC
+ ) WHERE ROWNUM = 1;
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ SELECT * INTO out_next
+ FROM (
+ SELECT fqdnhash
+ FROM Records
+ WHERE zone_id = in_zone_id
+ AND auth = 1
+ ORDER BY fqdnhash ASC
+ ) WHERE ROWNUM = 1;
+ END;
+END;
+/
+
+SHOW ERRORS
+
+CREATE TRIGGER records_fill_columns
+ BEFORE INSERT OR UPDATE ON Records
+ FOR EACH ROW
+BEGIN
+ -- 'www.site.example' => 'example site www' for NSEC ordering
+ :NEW.revfqdn := label_reverse(LOWER(:NEW.fqdn));
+
+ -- Hash the FQDN for NSEC3 ordering
+ IF :NEW.type != 'RRSIG' THEN
+ DECLARE
+ nsec3param_string VARCHAR2(512);
+ nsec3param_pattern VARCHAR2(512) := '^(\d+) +(\d+) +(\d+) +([0-9A-Fa-f]+)';
+ hashalgo BINARY_INTEGER;
+ itcount BINARY_INTEGER;
+ salt RAW(256);
+ BEGIN
+ SELECT meta_content INTO nsec3param_string
+ FROM ZoneMetadata
+ WHERE zone_id = :NEW.zone_id
+ AND meta_type = 'NSEC3PARAM';
+ hashalgo := REGEXP_SUBSTR(nsec3param_string, nsec3param_pattern, 1, 1, '', 1);
+ IF hashalgo != 1 THEN
+ RAISE_APPLICATION_ERROR(-20000, 'NSEC3 hash is not SHA-1');
+ END IF;
+ itcount := REGEXP_SUBSTR(nsec3param_string, nsec3param_pattern, 1, 1, '', 3);
+ salt := REGEXP_SUBSTR(nsec3param_string, nsec3param_pattern, 1, 1, '', 4);
+ :NEW.fqdnhash := dnsname_to_hashname(:NEW.fqdn, salt, itcount);
+ EXCEPTION
+ WHEN NO_DATA_FOUND THEN
+ NULL;
+ END;
+ END IF;
+END;
+/
+
+SHOW ERRORS
+
+CREATE TRIGGER parse_zone_defining_records
+ AFTER INSERT OR UPDATE ON Records
+ FOR EACH ROW
+ WHEN (NEW.type IN ('SOA'))
+BEGIN
+ CASE :NEW.type
+ WHEN 'SOA' THEN
+ DECLARE
+ pattern VARCHAR2(32) := '^[^ ]+ +[^ ]+ +(\d+) +(\d+)';
+ serial_str VARCHAR2(32) := REGEXP_SUBSTR(:NEW.content, pattern, 1, 1, '', 1);
+ serial_num NUMBER(10,0) := TO_NUMBER(serial_str);
+ refresh_str VARCHAR2(32) := REGEXP_SUBSTR(:NEW.content, pattern, 1, 1, '', 2);
+ BEGIN
+ IF serial_num = 0 THEN
+ SELECT NVL(max(last_change), 0) INTO serial_num
+ FROM Records
+ WHERE zone_id = :NEW.zone_id;
+ END IF;
+
+ UPDATE Zones
+ SET serial = serial_num, refresh = TO_NUMBER(refresh_str)
+ WHERE id = :NEW.zone_id;
+ END;
+ END CASE;
+END;
+/
+
+SHOW ERRORS
+
+-- End of schema
+-- vi: set sw=2 et : --
--- /dev/null
+pkglib_LTLIBRARIES = libpipebackend.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ backend.pl
+
+libpipebackend_la_SOURCES = \
+ coprocess.cc coprocess.hh \
+ pipebackend.cc pipebackend.hh
+
+libpipebackend_la_LDFLAGS = -module -avoid-version
+
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/pipebackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+libpipebackend_la_LIBADD =
+am_libpipebackend_la_OBJECTS = coprocess.lo pipebackend.lo
+libpipebackend_la_OBJECTS = $(am_libpipebackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libpipebackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libpipebackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libpipebackend_la_SOURCES)
+DIST_SOURCES = $(libpipebackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libpipebackend.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ backend.pl
+
+libpipebackend_la_SOURCES = \
+ coprocess.cc coprocess.hh \
+ pipebackend.cc pipebackend.hh
+
+libpipebackend_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/pipebackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/pipebackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libpipebackend.la: $(libpipebackend_la_OBJECTS) $(libpipebackend_la_DEPENDENCIES) $(EXTRA_libpipebackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libpipebackend_la_LINK) -rpath $(pkglibdir) $(libpipebackend_la_OBJECTS) $(libpipebackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/coprocess.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipebackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+coprocess.lo pipebackend.lo
--- /dev/null
+#!/usr/bin/perl -w
+# sample PowerDNS Coprocess backend
+#
+
+use strict;
+
+
+$|=1; # no buffering
+
+my $line=<>;
+chomp($line);
+
+unless($line eq "HELO\t1") {
+ print "FAIL\n";
+ print STDERR "Received '$line'\n";
+ <>;
+ exit;
+}
+print "OK Sample backend firing up\n"; # print our banner
+
+while(<>)
+{
+ print STDERR "$$ Received: $_";
+ chomp();
+ my @arr=split(/\t/);
+ if(@arr<6) {
+ print "LOG PowerDNS sent unparseable line\n";
+ print "FAIL\n";
+ next;
+ }
+
+ # note! the qname is what PowerDNS asks the backend. It need not be what the internet asked PowerDNS!
+ my ($type,$qname,$qclass,$qtype,$id,$ip)=split(/\t/);
+
+ if(($qtype eq "SOA" || $qtype eq "ANY") && $qname eq "example.com") {
+ print STDERR "$$ Sent SOA records\n";
+ print "DATA $qname $qclass SOA 3600 -1 ns1.example.com ahu.example.com 2008080300 1800 3600 604800 3600\n";
+ }
+ if(($qtype eq "NS" || $qtype eq "ANY") && $qname eq "example.com") {
+ print STDERR "$$ Sent NS records\n";
+ print "DATA $qname $qclass NS 3600 -1 ns1.example.com\n";
+ print "DATA $qname $qclass NS 3600 -1 ns2.example.com\n";
+ }
+ if(($qtype eq "TXT" || $qtype eq "ANY") && $qname eq "example.com") {
+ print STDERR "$$ Sent NS records\n";
+ print "DATA $qname $qclass TXT 3600 -1 \"hallo allemaal!\"\n";
+ }
+ if(($qtype eq "A" || $qtype eq "ANY") && $qname eq "webserver.example.com") {
+ print STDERR "$$ Sent A records\n";
+ print "DATA $qname $qclass A 3600 -1 1.2.3.4\n";
+ print "DATA $qname $qclass A 3600 -1 1.2.3.5\n";
+ print "DATA $qname $qclass A 3600 -1 1.2.3.6\n";
+ }
+ elsif(($qtype eq "CNAME" || $qtype eq "ANY") && $qname eq "www.example.com") {
+ print STDERR "$$ Sent CNAME records\n";
+ print "DATA $qname $qclass CNAME 3600 -1 webserver.example.com\n";
+ }
+
+
+ print STDERR "$$ End of data\n";
+ print "END\n";
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "coprocess.hh"
+#include <stdlib.h>
+#include <unistd.h>
+#include <string>
+#include <errno.h>
+#include <signal.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include "pdns/utility.hh"
+#include <sys/un.h>
+#include "pdns/misc.hh"
+#include "pdns/pdnsexception.hh"
+#include <sys/stat.h>
+#include <unistd.h>
+#include <boost/algorithm/string.hpp>
+#include <vector>
+
+CoProcess::CoProcess(const string &command,int timeout, int infd, int outfd)
+{
+ vector <string> v;
+ split(v, command, is_any_of(" "));
+
+ const char *argv[v.size()+1];
+ argv[v.size()]=0;
+
+ for (size_t n = 0; n < v.size(); n++)
+ argv[n]=v[n].c_str();
+ // we get away with not copying since nobody resizes v
+ launch(argv, timeout, infd, outfd);
+}
+
+void CoProcess::launch(const char **argv, int timeout, int infd, int outfd)
+{
+ d_timeout=timeout;
+ d_infd=infd;
+ d_outfd=outfd;
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if(access(argv[0],X_OK)) // check before fork so we can throw
+ throw PDNSException("Command '"+string(argv[0])+"' cannot be executed: "+stringerror());
+
+ if(pipe(d_fd1)<0 || pipe(d_fd2)<0)
+ throw PDNSException("Unable to open pipe for coprocess: "+string(strerror(errno)));
+
+ if((d_pid=fork())<0)
+ throw PDNSException("Unable to fork for coprocess: "+stringerror());
+ else if(d_pid>0) { // parent speaking
+ close(d_fd1[0]);
+ setCloseOnExec(d_fd1[1]);
+ close(d_fd2[1]);
+ setCloseOnExec(d_fd2[0]);
+ if(!(d_fp=fdopen(d_fd2[0],"r")))
+ throw PDNSException("Unable to associate a file pointer with pipe: "+stringerror());
+ if( d_timeout)
+ setbuf(d_fp,0); // no buffering please, confuses select
+ }
+ else if(!d_pid) { // child
+ signal(SIGCHLD, SIG_DFL); // silence a warning from perl
+ close(d_fd1[1]);
+ close(d_fd2[0]);
+
+ if(d_fd1[0]!= infd) {
+ dup2(d_fd1[0], infd);
+ close(d_fd1[0]);
+ }
+
+ if(d_fd2[1]!= outfd) {
+ dup2(d_fd2[1], outfd);
+ close(d_fd2[1]);
+ }
+
+ // stdin & stdout are now connected, fire up our coprocess!
+
+ if(execv(argv[0], const_cast<char * const *>(argv))<0) // now what
+ exit(123);
+
+ /* not a lot we can do here. We shouldn't return because that will leave a forked process around.
+ no way to log this either - only thing we can do is make sure that our parent catches this soonest! */
+ }
+}
+
+CoProcess::~CoProcess()
+{
+ int status;
+ if(!waitpid(d_pid, &status, WNOHANG)) {
+ kill(d_pid, 9);
+ waitpid(d_pid, &status, 0);
+ }
+
+ close(d_fd1[1]);
+ fclose(d_fp);
+}
+
+void CoProcess::checkStatus()
+{
+ int status;
+ int ret=waitpid(d_pid, &status, WNOHANG);
+ if(ret<0)
+ throw PDNSException("Unable to ascertain status of coprocess "+itoa(d_pid)+" from "+itoa(getpid())+": "+string(strerror(errno)));
+ else if(ret) {
+ if(WIFEXITED(status)) {
+ int ret=WEXITSTATUS(status);
+ throw PDNSException("Coprocess exited with code "+itoa(ret));
+ }
+ if(WIFSIGNALED(status)) {
+ int sig=WTERMSIG(status);
+ string reason="CoProcess died on receiving signal "+itoa(sig);
+#ifdef WCOREDUMP
+ if(WCOREDUMP(status))
+ reason+=". Dumped core";
+#endif
+
+ throw PDNSException(reason);
+ }
+ }
+}
+
+void CoProcess::send(const string &snd)
+{
+ checkStatus();
+ string line(snd);
+ line.append(1,'\n');
+
+ unsigned int sent=0;
+ int bytes;
+
+ // writen routine - socket may not accept al data in one go
+ while(sent<line.size()) {
+ bytes=write(d_fd1[1],line.c_str()+sent,line.length()-sent);
+ if(bytes<0)
+ throw PDNSException("Writing to coprocess failed: "+string(strerror(errno)));
+
+ sent+=bytes;
+ }
+}
+
+void CoProcess::receive(string &receive)
+{
+ receive.clear();
+
+ if(d_timeout) {
+ struct timeval tv;
+ tv.tv_sec=d_timeout/1000;
+ tv.tv_usec=(d_timeout % 1000) * 1000;
+
+ fd_set rds;
+ FD_ZERO(&rds);
+ FD_SET(fileno(d_fp),&rds);
+ int ret=select(fileno(d_fp)+1,&rds,0,0,&tv);
+ if(ret<0)
+ throw PDNSException("Error waiting on data from coprocess: "+stringerror());
+ if(!ret)
+ throw PDNSException("Timeout waiting for data from coprocess");
+ }
+
+ if(!stringfgets(d_fp, receive))
+ throw PDNSException("Child closed pipe");
+
+ trim_right(receive);
+}
+
+void CoProcess::sendReceive(const string &snd, string &rcv)
+{
+ checkStatus();
+ send(snd);
+ receive(rcv);
+
+}
+
+UnixRemote::UnixRemote(const string& path, int timeout)
+{
+ d_fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(d_fd < 0)
+ throw PDNSException("Unable to create UNIX domain socket: "+string(strerror(errno)));
+
+ struct sockaddr_un remote;
+ if (makeUNsockaddr(path, &remote))
+ throw PDNSException("Unable to create UNIX domain socket: Path '"+path+"' is not a valid UNIX socket path.");
+
+ // fcntl(fd, F_SETFL, O_NONBLOCK, &sock);
+
+ if(connect(d_fd, (struct sockaddr*)&remote, sizeof(remote)) < 0)
+ unixDie("Unable to connect to remote '"+path+"' using UNIX domain socket");
+
+ d_fp = fdopen(d_fd, "r");
+}
+
+UnixRemote::~UnixRemote()
+{
+ fclose(d_fp);
+}
+
+void UnixRemote::send(const string& line)
+{
+ string nline(line);
+ nline.append(1, '\n');
+ writen2(d_fd, nline);
+}
+
+void UnixRemote::receive(string& line)
+{
+ line.clear();
+ stringfgets(d_fp, line);
+ trim_right(line);
+}
+
+void UnixRemote::sendReceive(const string &snd, string &rcv)
+{
+ // checkStatus();
+ send(snd);
+ receive(rcv);
+}
+
+bool isUnixSocket(const string& fname)
+{
+ struct stat st;
+ if(stat(fname.c_str(), &st) < 0)
+ return false; // not a unix socket in any case ;-)
+
+ return (st.st_mode & S_IFSOCK) == S_IFSOCK;
+}
+
+
+#ifdef TESTDRIVER
+main()
+{
+ try {
+ CoProcess cp("./irc.pl");
+ string reply;
+ cp.sendReceive("www.trilab.com", reply);
+ cout<<"Answered: '"<<reply<<"'"<<endl;
+ }
+ catch(PDNSException &ae) {
+ cerr<<ae.reason<<endl;
+ }
+
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_COPROCESS_HH
+#define PDNS_COPROCESS_HH
+
+#include <iostream>
+#include <stdio.h>
+#include <string>
+
+#include "pdns/namespaces.hh"
+
+class CoRemote
+{
+public:
+ virtual ~CoRemote() {}
+ virtual void sendReceive(const string &send, string &receive) = 0;
+ virtual void receive(string &rcv) = 0;
+ virtual void send(const string &send) = 0;
+
+};
+
+class CoProcess : public CoRemote
+{
+public:
+ CoProcess(const string &command,int timeout=0, int infd=0, int outfd=1);
+ ~CoProcess();
+ void sendReceive(const string &send, string &receive);
+ void receive(string &rcv);
+ void send(const string &send);
+private:
+ void launch(const char **argv, int timeout=0, int infd=0, int outfd=1);
+ void checkStatus();
+ int d_fd1[2], d_fd2[2];
+ int d_pid;
+ int d_infd;
+ int d_outfd;
+ int d_timeout;
+ FILE *d_fp;
+};
+
+class UnixRemote : public CoRemote
+{
+public:
+ UnixRemote(const string &path, int timeout=0);
+ ~UnixRemote();
+ void sendReceive(const string &send, string &receive);
+ void receive(string &rcv);
+ void send(const string &send);
+private:
+ int d_fd;
+ FILE *d_fp;
+};
+bool isUnixSocket(const string& fname);
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <map>
+#include <unistd.h>
+#include <stdlib.h>
+#include <sstream>
+#include "coprocess.hh"
+
+#include "pdns/namespaces.hh"
+
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "pipebackend.hh"
+
+static const char *kBackendId = "[PIPEBackend]";
+
+CoWrapper::CoWrapper(const string &command, int timeout, int abiVersion)
+{
+ d_cp=0;
+ d_command=command;
+ d_timeout=timeout;
+ d_abiVersion = abiVersion;
+ launch(); // let exceptions fall through - if initial launch fails, we want to die
+ // I think
+}
+
+CoWrapper::~CoWrapper()
+{
+ if(d_cp)
+ delete d_cp;
+}
+
+
+void CoWrapper::launch()
+{
+ if(d_cp)
+ return;
+
+ if(d_command.empty())
+ throw ArgException("pipe-command is not specified");
+
+ if(isUnixSocket(d_command))
+ d_cp = new UnixRemote(d_command, d_timeout);
+ else
+ d_cp = new CoProcess(d_command, d_timeout);
+
+ d_cp->send("HELO\t"+std::to_string(d_abiVersion));
+ string banner;
+ d_cp->receive(banner);
+ L<<Logger::Error<<"Backend launched with banner: "<<banner<<endl;
+}
+
+void CoWrapper::send(const string &line)
+{
+ launch();
+ try {
+ d_cp->send(line);
+ return;
+ }
+ catch(PDNSException &ae) {
+ delete d_cp;
+ d_cp=0;
+ throw;
+ }
+}
+void CoWrapper::receive(string &line)
+{
+ launch();
+ try {
+ d_cp->receive(line);
+ return;
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Warning<<kBackendId<<" Unable to receive data from coprocess. "<<ae.reason<<endl;
+ delete d_cp;
+ d_cp=0;
+ throw;
+ }
+}
+
+PipeBackend::PipeBackend(const string &suffix)
+{
+ d_disavow=false;
+ d_regex=nullptr;
+ signal(SIGCHLD, SIG_IGN);
+ setArgPrefix("pipe"+suffix);
+ try {
+ launch();
+ }
+ catch(const ArgException &A) {
+ L<<Logger::Error<<kBackendId<<" Unable to launch, fatal argument error: "<<A.reason<<endl;
+ throw;
+ }
+ catch(...) {
+ throw;
+ }
+}
+
+void PipeBackend::launch()
+{
+ if(d_coproc)
+ return;
+
+ try {
+ d_regex=getArg("regex").empty() ? 0 : new Regex(getArg("regex"));
+ d_regexstr=getArg("regex");
+ d_abiVersion = getArgAsNum("abi-version");
+ d_coproc=unique_ptr<CoWrapper> (new CoWrapper(getArg("command"), getArgAsNum("timeout"), getArgAsNum("abi-version")));
+ }
+
+ catch(const ArgException &A) {
+ cleanup();
+ throw;
+ }
+}
+
+/*
+ * Cleans up the co-process wrapper
+ */
+void PipeBackend::cleanup()
+{
+ d_coproc.reset(0);
+ delete d_regex;
+ d_regexstr = string();
+ d_abiVersion = 0;
+}
+
+void PipeBackend::lookup(const QType& qtype,const DNSName& qname, DNSPacket *pkt_p, int zoneId)
+{
+ try {
+ launch();
+ d_disavow=false;
+ if(d_regex && !d_regex->match(qname.toStringRootDot())) {
+ if(::arg().mustDo("query-logging"))
+ L<<Logger::Error<<"Query for '"<<qname<<"' failed regex '"<<d_regexstr<<"'"<<endl;
+ d_disavow=true; // don't pass to backend
+ } else {
+ ostringstream query;
+ string localIP="0.0.0.0";
+ string remoteIP="0.0.0.0";
+ Netmask realRemote("0.0.0.0/0");
+ if (pkt_p) {
+ localIP=pkt_p->getLocal().toString();
+ realRemote = pkt_p->getRealRemote();
+ remoteIP = pkt_p->getRemote().toString();
+ }
+ // abi-version = 1
+ // type qname qclass qtype id remote-ip-address
+ query<<"Q\t"<<qname.toStringRootDot()<<"\tIN\t"<<qtype.getName()<<"\t"<<zoneId<<"\t"<<remoteIP;
+
+ // add the local-ip-address if abi-version is set to 2
+ if (d_abiVersion >= 2)
+ query<<"\t"<<localIP;
+ if(d_abiVersion >= 3)
+ query <<"\t"<<realRemote.toString();
+
+ if(::arg().mustDo("query-logging"))
+ L<<Logger::Error<<"Query: '"<<query.str()<<"'"<<endl;
+ d_coproc->send(query.str());
+ }
+ }
+ catch(PDNSException &pe) {
+ L<<Logger::Error<<kBackendId<<" Error from coprocess: "<<pe.reason<<endl;
+ d_disavow = true;
+ }
+ d_qtype=qtype;
+ d_qname=qname;
+}
+
+bool PipeBackend::list(const DNSName& target, int inZoneId, bool include_disabled)
+{
+ try {
+ launch();
+ d_disavow=false;
+ ostringstream query;
+ // The question format:
+
+ // type qname qclass qtype id ip-address
+ if (d_abiVersion >= 4)
+ query<<"AXFR\t"<<inZoneId<<"\t"<<target.toStringRootDot();
+ else
+ query<<"AXFR\t"<<inZoneId;
+
+ d_coproc->send(query.str());
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<kBackendId<<" Error from coprocess: "<<ae.reason<<endl;
+ }
+ d_qname=DNSName(itoa(inZoneId)); // why do we store a number here??
+ return true;
+}
+
+string PipeBackend::directBackendCmd(const string &query) {
+ if (d_abiVersion < 5)
+ return "not supported on ABI version " + std::to_string(d_abiVersion) + "(use ABI version 5 or later)\n";
+
+ ostringstream oss;
+
+ try {
+ launch();
+ ostringstream oss;
+ oss<<"CMD\t"<<query;
+ d_coproc->send(oss.str());
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<kBackendId<<" Error from coprocess: "<<ae.reason<<endl;
+ cleanup();
+ }
+ oss.str("");
+
+ while(true) {
+ string line;
+ d_coproc->receive(line);
+ if (line == "END") break;
+ oss << line << std::endl;
+ };
+
+ return oss.str();
+}
+
+//! For the dynamic loader
+DNSBackend *PipeBackend::maker()
+{
+ try {
+ return new PipeBackend();
+ }
+ catch(...) {
+ L<<Logger::Error<<kBackendId<<" Unable to instantiate a pipebackend!"<<endl;
+ return 0;
+ }
+}
+
+PipeBackend::~PipeBackend()
+{
+ cleanup();
+}
+
+bool PipeBackend::get(DNSResourceRecord &r)
+{
+ if(d_disavow) // this query has been blocked
+ return false;
+
+ string line;
+
+ // The answer format:
+ // DATA qname qclass qtype ttl id content
+ unsigned int extraFields = 0;
+ if(d_abiVersion >= 3)
+ extraFields = 2;
+
+ try{
+ launch();
+ for(;;) {
+ d_coproc->receive(line);
+ vector<string>parts;
+ stringtok(parts,line,"\t");
+ if(parts.empty()) {
+ L<<Logger::Error<<kBackendId<<" Coprocess returned empty line in query for "<<d_qname<<endl;
+ throw PDNSException("Format error communicating with coprocess");
+ }
+ else if(parts[0]=="FAIL") {
+ throw DBException("coprocess returned a FAIL");
+ }
+ else if(parts[0]=="END") {
+ return false;
+ }
+ else if(parts[0]=="LOG") {
+ L<<Logger::Error<<"Coprocess: "<<line.substr(4)<<endl;
+ continue;
+ }
+ else if(parts[0]=="DATA") { // yay
+ if(parts.size() < 7 + extraFields) {
+ L<<Logger::Error<<kBackendId<<" Coprocess returned incomplete or empty line in data section for query for "<<d_qname<<endl;
+ throw PDNSException("Format error communicating with coprocess in data section");
+ // now what?
+ }
+
+ if(d_abiVersion >= 3) {
+ r.scopeMask = std::stoi(parts[1]);
+ r.auth = (parts[2] == "1");
+ } else {
+ r.scopeMask = 0;
+ r.auth = 1;
+ }
+ r.qname=DNSName(parts[1+extraFields]);
+ r.qtype=parts[3+extraFields];
+ r.ttl=pdns_stou(parts[4+extraFields]);
+ r.domain_id=std::stoi(parts[5+extraFields]);
+
+ if(r.qtype.getCode() != QType::MX && r.qtype.getCode() != QType::SRV) {
+ r.content.clear();
+ for(unsigned int n= 6 + extraFields; n < parts.size(); ++n) {
+ if(n!=6+extraFields)
+ r.content.append(1,' ');
+ r.content.append(parts[n]);
+ }
+ }
+ else {
+ if(parts.size()< 8 + extraFields) {
+ L<<Logger::Error<<kBackendId<<" Coprocess returned incomplete MX/SRV line in data section for query for "<<d_qname<<endl;
+ throw PDNSException("Format error communicating with coprocess in data section of MX/SRV record");
+ }
+
+ r.content=parts[6+extraFields]+" "+parts[7+extraFields];
+ }
+ break;
+ }
+ else
+ throw PDNSException("Coprocess backend sent incorrect response '"+line+"'");
+ }
+ }
+ catch (DBException &dbe) {
+ L<<Logger::Error<<kBackendId<<" "<<dbe.reason<<endl;
+ throw;
+ }
+ catch (PDNSException &pe) {
+ L<<Logger::Error<<kBackendId<<" "<<pe.reason<<endl;
+ cleanup();
+ throw;
+ }
+ return true;
+}
+
+//
+// Magic class that is activated when the dynamic library is loaded
+//
+
+class PipeFactory : public BackendFactory
+{
+ public:
+ PipeFactory() : BackendFactory("pipe") {}
+
+ void declareArguments(const string &suffix="")
+ {
+ declare(suffix,"command","Command to execute for piping questions to","");
+ declare(suffix,"timeout","Number of milliseconds to wait for an answer","2000");
+ declare(suffix,"regex","Regular expression of queries to pass to coprocess","");
+ declare(suffix,"abi-version","Version of the pipe backend ABI","1");
+ }
+
+ DNSBackend *make(const string &suffix="")
+ {
+ return new PipeBackend(suffix);
+ }
+};
+
+class PipeLoader
+{
+ public:
+ PipeLoader()
+ {
+ BackendMakers().report(new PipeFactory);
+ L << Logger::Info << kBackendId <<" This is the pipe backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static PipeLoader pipeloader;
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PIPEBACKEND_HH
+#define PIPEBACKEND_HH
+
+#include <string>
+#include <map>
+#include <sys/types.h>
+
+
+#include "pdns/namespaces.hh"
+#include "pdns/misc.hh"
+
+
+/** The CoWrapper class wraps around a coprocess and restarts it if needed.
+ It may also send out pings and expect banners */
+class CoWrapper
+{
+public:
+ CoWrapper(const string &command, int timeout, int abiVersion);
+ ~CoWrapper();
+ void send(const string &line);
+ void receive(string &line);
+private:
+ CoRemote* d_cp;
+ string d_command;
+ void launch();
+ int d_timeout;
+ int d_abiVersion;
+};
+
+class PipeBackend : public DNSBackend
+{
+public:
+ PipeBackend(const string &suffix="");
+ ~PipeBackend();
+ void lookup(const QType&, const DNSName& qdomain, DNSPacket *p=0, int zoneId=-1);
+ bool list(const DNSName& target, int domain_id, bool include_disabled=false);
+ bool get(DNSResourceRecord &r);
+ string directBackendCmd(const string &query);
+ static DNSBackend *maker();
+
+private:
+ void launch();
+ void cleanup();
+ unique_ptr<CoWrapper> d_coproc;
+ DNSName d_qname;
+ QType d_qtype;
+ Regex* d_regex;
+ string d_regexstr;
+ bool d_disavow;
+ int d_abiVersion;
+};
+
+
+#endif
+
--- /dev/null
+pkglib_LTLIBRARIES = librandombackend.la
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+librandombackend_la_SOURCES = randombackend.cc
+librandombackend_la_LDFLAGS = -module -avoid-version
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/randombackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+librandombackend_la_LIBADD =
+am_librandombackend_la_OBJECTS = randombackend.lo
+librandombackend_la_OBJECTS = $(am_librandombackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+librandombackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(librandombackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+SOURCES = $(librandombackend_la_SOURCES)
+DIST_SOURCES = $(librandombackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = librandombackend.la
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+librandombackend_la_SOURCES = randombackend.cc
+librandombackend_la_LDFLAGS = -module -avoid-version
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/randombackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/randombackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+librandombackend.la: $(librandombackend_la_OBJECTS) $(librandombackend_la_DEPENDENCIES) $(EXTRA_librandombackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(librandombackend_la_LINK) -rpath $(pkglibdir) $(librandombackend_la_OBJECTS) $(librandombackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randombackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+randombackend.lo
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/utility.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/version.hh"
+#include <boost/algorithm/string.hpp>
+
+/* FIRST PART */
+class RandomBackend : public DNSBackend
+{
+public:
+ RandomBackend(const string &suffix="")
+ {
+ setArgPrefix("random"+suffix);
+ d_ourname=DNSName(getArg("hostname"));
+ d_ourdomain = d_ourname;
+ d_ourdomain.chopOff();
+ }
+
+ bool list(const DNSName &target, int id, bool include_disabled) {
+ return false; // we don't support AXFR
+ }
+
+ void lookup(const QType &type, const DNSName &qdomain, DNSPacket *p, int zoneId)
+ {
+ if(qdomain == d_ourdomain){
+ if(type.getCode() == QType::SOA || type.getCode() == QType::ANY) {
+ d_answer="ns1." + d_ourdomain.toString() + " hostmaster." + d_ourdomain.toString() + " 1234567890 86400 7200 604800 300";
+ } else {
+ d_answer="";
+ }
+ } else if (qdomain == d_ourname) {
+ if(type.getCode() == QType::A || type.getCode() == QType::ANY) {
+ ostringstream os;
+ os<<Utility::random()%256<<"."<<Utility::random()%256<<"."<<Utility::random()%256<<"."<<Utility::random()%256;
+ d_answer=os.str(); // our random ip address
+ } else {
+ d_answer="";
+ }
+ } else {
+ d_answer="";
+ }
+ }
+
+ bool get(DNSResourceRecord &rr)
+ {
+ if(!d_answer.empty()) {
+ if(d_answer.find("ns1.") == 0){
+ rr.qname=d_ourdomain;
+ rr.qtype=QType::SOA;
+ } else {
+ rr.qname=d_ourname;
+ rr.qtype=QType::A;
+ }
+ rr.ttl=5; // 5 seconds
+ rr.auth = 1; // it may be random.. but it is auth!
+ rr.content=d_answer;
+
+ d_answer=""; // this was the last answer
+ return true;
+ }
+ return false;
+ }
+
+private:
+ string d_answer;
+ DNSName d_ourname;
+ DNSName d_ourdomain;
+};
+
+/* SECOND PART */
+
+class RandomFactory : public BackendFactory
+{
+public:
+ RandomFactory() : BackendFactory("random") {}
+ void declareArguments(const string &suffix="")
+ {
+ declare(suffix,"hostname","Hostname which is to be random","random.example.com");
+ }
+ DNSBackend *make(const string &suffix="")
+ {
+ return new RandomBackend(suffix);
+ }
+};
+
+/* THIRD PART */
+
+class RandomLoader
+{
+public:
+ RandomLoader()
+ {
+ BackendMakers().report(new RandomFactory);
+ L << Logger::Info << "[randombackend] This is the random backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static RandomLoader randomLoader;
--- /dev/null
+source "https://rubygems.org"
+
+gem "json"
+gem "webrick"
+gem "zeromqrb"
+gem "sqlite3"
--- /dev/null
+GEM
+ remote: https://rubygems.org/
+ specs:
+ ffi (1.9.6)
+ ffi-rzmq (2.0.1)
+ ffi-rzmq-core (>= 1.0.1)
+ ffi-rzmq-core (1.0.3)
+ ffi (~> 1.9)
+ json (1.8.5)
+ sqlite3 (1.3.9)
+ webrick (1.3.1)
+ zeromqrb (0.1.3)
+ ffi-rzmq
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ json
+ sqlite3
+ webrick
+ zeromqrb
+
+BUNDLED WITH
+ 1.10.2
--- /dev/null
+AM_CPPFLAGS += \
+ -I$(top_srcdir)/ext/json11 \
+ $(YAHTTP_CFLAGS) \
+ $(LIBCRYPTO_CFLAGS) \
+ $(LIBZMQ_CFLAGS)
+
+AM_LDFLAGS = $(THREADFLAGS)
+
+JSON11_LIBS = $(top_srcdir)/ext/json11/libjson11.la
+
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ testrunner.sh \
+ unittest_http.rb \
+ unittest_json.rb \
+ unittest_pipe.rb \
+ unittest_zeromq.rb \
+ unittest_post.rb \
+ unittest.rb \
+ Gemfile \
+ Gemfile.lock
+
+EXTRA_PROGRAMS = \
+ remotebackend_pipe.test \
+ remotebackend_unix.test \
+ remotebackend_http.test \
+ remotebackend_post.test \
+ remotebackend_json.test \
+ remotebackend_zeromq.test
+
+EXTRA_LTLIBRARIES = libtestremotebackend.la
+
+clean-local:
+ rm -f $(EXTRA_PROGRAMS)
+
+pkglib_LTLIBRARIES = libremotebackend.la
+
+libremotebackend_la_SOURCES = \
+ remotebackend.hh \
+ remotebackend.cc \
+ unixconnector.cc \
+ httpconnector.cc \
+ pipeconnector.cc \
+ zmqconnector.cc
+
+libremotebackend_la_LDFLAGS = -module -avoid-version
+
+libremotebackend_la_LIBADD = $(YAHTTP_LIBS) $(JSON11_LIBS)
+
+if REMOTEBACKEND_ZEROMQ
+libremotebackend_la_LIBADD += $(LIBZMQ_LIBS)
+endif
+
+TESTS_ENVIRONMENT = \
+ BOOST_TEST_LOG_LEVEL=message; \
+ export BOOST_TEST_LOG_LEVEL; \
+ REMOTEBACKEND_ZEROMQ=$(REMOTEBACKEND_ZEROMQ); \
+ export REMOTEBACKEND_ZEROMQ;
+
+TEST_EXTENSIONS = .test
+
+TEST_LOG_COMPILER = $(abs_srcdir)/testrunner.sh
+
+RECHECK_LOGS = \
+ $(TEST_LOGS) \
+ remotebackend_http_server.log \
+ remotebackend_post_server.log \
+ remotebackend_json_server.log \
+ remotebackend_zeromq_server.log
+
+## The http, post and json test are using the same TCP port.
+## To prevent "Address already in use - bind(2) (Errno::EADDRINUSE)"
+## errors when running `make check` in parallel, we need to specify
+## an order
+remotebackend_post.log: remotebackend_http.log
+
+remotebackend_json.log: remotebackend_http.log remotebackend_post.log
+
+if BACKEND_UNIT_TESTS
+TESTS = \
+ remotebackend_pipe.test \
+ remotebackend_unix.test \
+ remotebackend_http.test \
+ remotebackend_post.test \
+ remotebackend_json.test \
+ remotebackend_zeromq.test
+
+endif
+
+BUILT_SOURCES = ../../pdns/dnslabeltext.cc
+
+../../pdns/dnslabeltext.cc: ../../pdns/dnslabeltext.rl
+ $(MAKE) -C ../../pdns dnslabeltext.cc
+
+libtestremotebackend_la_SOURCES = \
+ ../../pdns/arguments.hh ../../pdns/arguments.cc \
+ ../../pdns/base32.cc \
+ ../../pdns/base64.cc \
+ ../../pdns/dnsbackend.hh ../../pdns/dnsbackend.cc \
+ ../../pdns/dnslabeltext.cc \
+ ../../pdns/dnsname.cc ../../pdns/dnsname.hh \
+ ../../pdns/dnspacket.cc \
+ ../../pdns/dnsparser.cc \
+ ../../pdns/dnsrecords.cc \
+ ../../pdns/dnssecinfra.cc \
+ ../../pdns/ednssubnet.cc \
+ ../../pdns/logger.cc \
+ ../../pdns/misc.cc \
+ ../../pdns/nsecrecords.cc \
+ ../../pdns/packetcache.hh ../../pdns/packetcache.cc \
+ ../../pdns/qtype.cc \
+ ../../pdns/sillyrecords.cc \
+ ../../pdns/statbag.cc \
+ ../../pdns/ueberbackend.hh ../../pdns/ueberbackend.cc \
+ ../../pdns/dns.hh ../../pdns/dns.cc \
+ ../../pdns/dns_random.cc \
+ ../../pdns/dnswriter.cc \
+ ../../pdns/nameserver.cc \
+ ../../pdns/rcpgenerator.cc \
+ ../../pdns/unix_utility.cc \
+ ../../pdns/gss_context.cc ../../pdns/gss_context.hh \
+ ../../pdns/json.hh ../../pdns/json.cc \
+ httpconnector.cc \
+ pipeconnector.cc \
+ unixconnector.cc \
+ zmqconnector.cc \
+ remotebackend.hh remotebackend.cc
+
+libtestremotebackend_la_CPPFLAGS = $(AM_CPPFLAGS)
+
+libtestremotebackend_la_LIBADD = \
+ $(YAHTTP_LIBS) \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(LIBDL) $(JSON11_LIBS)
+
+libtestremotebackend_la_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS)
+
+if REMOTEBACKEND_ZEROMQ
+libtestremotebackend_la_LIBADD += $(LIBZMQ_LIBS)
+endif
+
+if PKCS11
+libtestremotebackend_la_SOURCES += \
+ ../../pdns/pkcs11signers.hh \
+ ../../pdns/pkcs11signers.cc
+
+libtestremotebackend_la_LIBADD += \
+ $(P11KIT1_LIBS)
+
+libtestremotebackend_la_CPPFLAGS += \
+ $(P11KIT1_CFLAGS)
+endif
+
+if GSS_TSIG
+libtestremotebackend_la_LIBADD += \
+ $(GSS_LIBS)
+libtestremotebackend_la_CPPFLAGS+= \
+ $(GSS_CFLAGS)
+endif
+
+remotebackend_http_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-http.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_http_test_LDADD = libtestremotebackend.la
+
+remotebackend_json_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-json.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_json_test_LDADD = libtestremotebackend.la
+
+remotebackend_pipe_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-pipe.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_pipe_test_LDADD = libtestremotebackend.la
+
+remotebackend_post_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-post.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_post_test_LDADD = libtestremotebackend.la
+
+remotebackend_unix_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-unix.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_unix_test_LDADD = libtestremotebackend.la
+
+remotebackend_zeromq_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-zeromq.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_zeromq_test_LDADD = libtestremotebackend.la
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+EXTRA_PROGRAMS = remotebackend_pipe.test$(EXEEXT) \
+ remotebackend_unix.test$(EXEEXT) \
+ remotebackend_http.test$(EXEEXT) \
+ remotebackend_post.test$(EXEEXT) \
+ remotebackend_json.test$(EXEEXT) \
+ remotebackend_zeromq.test$(EXEEXT)
+@REMOTEBACKEND_ZEROMQ_TRUE@am__append_1 = $(LIBZMQ_LIBS)
+@BACKEND_UNIT_TESTS_TRUE@TESTS = remotebackend_pipe.test$(EXEEXT) \
+@BACKEND_UNIT_TESTS_TRUE@ remotebackend_unix.test$(EXEEXT) \
+@BACKEND_UNIT_TESTS_TRUE@ remotebackend_http.test$(EXEEXT) \
+@BACKEND_UNIT_TESTS_TRUE@ remotebackend_post.test$(EXEEXT) \
+@BACKEND_UNIT_TESTS_TRUE@ remotebackend_json.test$(EXEEXT) \
+@BACKEND_UNIT_TESTS_TRUE@ remotebackend_zeromq.test$(EXEEXT)
+@REMOTEBACKEND_ZEROMQ_TRUE@am__append_2 = $(LIBZMQ_LIBS)
+@PKCS11_TRUE@am__append_3 = \
+@PKCS11_TRUE@ ../../pdns/pkcs11signers.hh \
+@PKCS11_TRUE@ ../../pdns/pkcs11signers.cc
+
+@PKCS11_TRUE@am__append_4 = \
+@PKCS11_TRUE@ $(P11KIT1_LIBS)
+
+@PKCS11_TRUE@am__append_5 = \
+@PKCS11_TRUE@ $(P11KIT1_CFLAGS)
+
+@GSS_TSIG_TRUE@am__append_6 = \
+@GSS_TSIG_TRUE@ $(GSS_LIBS)
+
+@GSS_TSIG_TRUE@am__append_7 = \
+@GSS_TSIG_TRUE@ $(GSS_CFLAGS)
+
+subdir = modules/remotebackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp \
+ $(top_srcdir)/build-aux/test-driver
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+@REMOTEBACKEND_ZEROMQ_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+libremotebackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(JSON11_LIBS) $(am__DEPENDENCIES_2)
+am_libremotebackend_la_OBJECTS = remotebackend.lo unixconnector.lo \
+ httpconnector.lo pipeconnector.lo zmqconnector.lo
+libremotebackend_la_OBJECTS = $(am_libremotebackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libremotebackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libremotebackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+@PKCS11_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+@GSS_TSIG_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+libtestremotebackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) $(JSON11_LIBS) \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_4)
+am__libtestremotebackend_la_SOURCES_DIST = ../../pdns/arguments.hh \
+ ../../pdns/arguments.cc ../../pdns/base32.cc \
+ ../../pdns/base64.cc ../../pdns/dnsbackend.hh \
+ ../../pdns/dnsbackend.cc ../../pdns/dnslabeltext.cc \
+ ../../pdns/dnsname.cc ../../pdns/dnsname.hh \
+ ../../pdns/dnspacket.cc ../../pdns/dnsparser.cc \
+ ../../pdns/dnsrecords.cc ../../pdns/dnssecinfra.cc \
+ ../../pdns/ednssubnet.cc ../../pdns/logger.cc \
+ ../../pdns/misc.cc ../../pdns/nsecrecords.cc \
+ ../../pdns/packetcache.hh ../../pdns/packetcache.cc \
+ ../../pdns/qtype.cc ../../pdns/sillyrecords.cc \
+ ../../pdns/statbag.cc ../../pdns/ueberbackend.hh \
+ ../../pdns/ueberbackend.cc ../../pdns/dns.hh ../../pdns/dns.cc \
+ ../../pdns/dns_random.cc ../../pdns/dnswriter.cc \
+ ../../pdns/nameserver.cc ../../pdns/rcpgenerator.cc \
+ ../../pdns/unix_utility.cc ../../pdns/gss_context.cc \
+ ../../pdns/gss_context.hh ../../pdns/json.hh \
+ ../../pdns/json.cc httpconnector.cc pipeconnector.cc \
+ unixconnector.cc zmqconnector.cc remotebackend.hh \
+ remotebackend.cc ../../pdns/pkcs11signers.hh \
+ ../../pdns/pkcs11signers.cc
+am__dirstamp = $(am__leading_dot)dirstamp
+@PKCS11_TRUE@am__objects_1 = ../../pdns/libtestremotebackend_la-pkcs11signers.lo
+am_libtestremotebackend_la_OBJECTS = \
+ ../../pdns/libtestremotebackend_la-arguments.lo \
+ ../../pdns/libtestremotebackend_la-base32.lo \
+ ../../pdns/libtestremotebackend_la-base64.lo \
+ ../../pdns/libtestremotebackend_la-dnsbackend.lo \
+ ../../pdns/libtestremotebackend_la-dnslabeltext.lo \
+ ../../pdns/libtestremotebackend_la-dnsname.lo \
+ ../../pdns/libtestremotebackend_la-dnspacket.lo \
+ ../../pdns/libtestremotebackend_la-dnsparser.lo \
+ ../../pdns/libtestremotebackend_la-dnsrecords.lo \
+ ../../pdns/libtestremotebackend_la-dnssecinfra.lo \
+ ../../pdns/libtestremotebackend_la-ednssubnet.lo \
+ ../../pdns/libtestremotebackend_la-logger.lo \
+ ../../pdns/libtestremotebackend_la-misc.lo \
+ ../../pdns/libtestremotebackend_la-nsecrecords.lo \
+ ../../pdns/libtestremotebackend_la-packetcache.lo \
+ ../../pdns/libtestremotebackend_la-qtype.lo \
+ ../../pdns/libtestremotebackend_la-sillyrecords.lo \
+ ../../pdns/libtestremotebackend_la-statbag.lo \
+ ../../pdns/libtestremotebackend_la-ueberbackend.lo \
+ ../../pdns/libtestremotebackend_la-dns.lo \
+ ../../pdns/libtestremotebackend_la-dns_random.lo \
+ ../../pdns/libtestremotebackend_la-dnswriter.lo \
+ ../../pdns/libtestremotebackend_la-nameserver.lo \
+ ../../pdns/libtestremotebackend_la-rcpgenerator.lo \
+ ../../pdns/libtestremotebackend_la-unix_utility.lo \
+ ../../pdns/libtestremotebackend_la-gss_context.lo \
+ ../../pdns/libtestremotebackend_la-json.lo \
+ libtestremotebackend_la-httpconnector.lo \
+ libtestremotebackend_la-pipeconnector.lo \
+ libtestremotebackend_la-unixconnector.lo \
+ libtestremotebackend_la-zmqconnector.lo \
+ libtestremotebackend_la-remotebackend.lo $(am__objects_1)
+libtestremotebackend_la_OBJECTS = \
+ $(am_libtestremotebackend_la_OBJECTS)
+libtestremotebackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libtestremotebackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_remotebackend_http_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-http.$(OBJEXT)
+remotebackend_http_test_OBJECTS = \
+ $(am_remotebackend_http_test_OBJECTS)
+remotebackend_http_test_DEPENDENCIES = libtestremotebackend.la
+am_remotebackend_json_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-json.$(OBJEXT)
+remotebackend_json_test_OBJECTS = \
+ $(am_remotebackend_json_test_OBJECTS)
+remotebackend_json_test_DEPENDENCIES = libtestremotebackend.la
+am_remotebackend_pipe_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-pipe.$(OBJEXT)
+remotebackend_pipe_test_OBJECTS = \
+ $(am_remotebackend_pipe_test_OBJECTS)
+remotebackend_pipe_test_DEPENDENCIES = libtestremotebackend.la
+am_remotebackend_post_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-post.$(OBJEXT)
+remotebackend_post_test_OBJECTS = \
+ $(am_remotebackend_post_test_OBJECTS)
+remotebackend_post_test_DEPENDENCIES = libtestremotebackend.la
+am_remotebackend_unix_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-unix.$(OBJEXT)
+remotebackend_unix_test_OBJECTS = \
+ $(am_remotebackend_unix_test_OBJECTS)
+remotebackend_unix_test_DEPENDENCIES = libtestremotebackend.la
+am_remotebackend_zeromq_test_OBJECTS = test-remotebackend.$(OBJEXT) \
+ test-remotebackend-zeromq.$(OBJEXT)
+remotebackend_zeromq_test_OBJECTS = \
+ $(am_remotebackend_zeromq_test_OBJECTS)
+remotebackend_zeromq_test_DEPENDENCIES = libtestremotebackend.la
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libremotebackend_la_SOURCES) \
+ $(libtestremotebackend_la_SOURCES) \
+ $(remotebackend_http_test_SOURCES) \
+ $(remotebackend_json_test_SOURCES) \
+ $(remotebackend_pipe_test_SOURCES) \
+ $(remotebackend_post_test_SOURCES) \
+ $(remotebackend_unix_test_SOURCES) \
+ $(remotebackend_zeromq_test_SOURCES)
+DIST_SOURCES = $(libremotebackend_la_SOURCES) \
+ $(am__libtestremotebackend_la_SOURCES_DIST) \
+ $(remotebackend_http_test_SOURCES) \
+ $(remotebackend_json_test_SOURCES) \
+ $(remotebackend_pipe_test_SOURCES) \
+ $(remotebackend_post_test_SOURCES) \
+ $(remotebackend_unix_test_SOURCES) \
+ $(remotebackend_zeromq_test_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red='\e[0;31m'; \
+ grn='\e[0;32m'; \
+ lgn='\e[1;32m'; \
+ blu='\e[1;34m'; \
+ mgn='\e[0;35m'; \
+ brg='\e[1m'; \
+ std='\e[m'; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/ext/json11 \
+ $(YAHTTP_CFLAGS) $(LIBCRYPTO_CFLAGS) $(LIBZMQ_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+AM_LDFLAGS = $(THREADFLAGS)
+JSON11_LIBS = $(top_srcdir)/ext/json11/libjson11.la
+EXTRA_DIST = \
+ OBJECTFILES \
+ OBJECTLIBS \
+ testrunner.sh \
+ unittest_http.rb \
+ unittest_json.rb \
+ unittest_pipe.rb \
+ unittest_zeromq.rb \
+ unittest_post.rb \
+ unittest.rb \
+ Gemfile \
+ Gemfile.lock
+
+EXTRA_LTLIBRARIES = libtestremotebackend.la
+pkglib_LTLIBRARIES = libremotebackend.la
+libremotebackend_la_SOURCES = \
+ remotebackend.hh \
+ remotebackend.cc \
+ unixconnector.cc \
+ httpconnector.cc \
+ pipeconnector.cc \
+ zmqconnector.cc
+
+libremotebackend_la_LDFLAGS = -module -avoid-version
+libremotebackend_la_LIBADD = $(YAHTTP_LIBS) $(JSON11_LIBS) \
+ $(am__append_1)
+TESTS_ENVIRONMENT = \
+ BOOST_TEST_LOG_LEVEL=message; \
+ export BOOST_TEST_LOG_LEVEL; \
+ REMOTEBACKEND_ZEROMQ=$(REMOTEBACKEND_ZEROMQ); \
+ export REMOTEBACKEND_ZEROMQ;
+
+TEST_EXTENSIONS = .test
+TEST_LOG_COMPILER = $(abs_srcdir)/testrunner.sh
+RECHECK_LOGS = \
+ $(TEST_LOGS) \
+ remotebackend_http_server.log \
+ remotebackend_post_server.log \
+ remotebackend_json_server.log \
+ remotebackend_zeromq_server.log
+
+BUILT_SOURCES = ../../pdns/dnslabeltext.cc
+libtestremotebackend_la_SOURCES = ../../pdns/arguments.hh \
+ ../../pdns/arguments.cc ../../pdns/base32.cc \
+ ../../pdns/base64.cc ../../pdns/dnsbackend.hh \
+ ../../pdns/dnsbackend.cc ../../pdns/dnslabeltext.cc \
+ ../../pdns/dnsname.cc ../../pdns/dnsname.hh \
+ ../../pdns/dnspacket.cc ../../pdns/dnsparser.cc \
+ ../../pdns/dnsrecords.cc ../../pdns/dnssecinfra.cc \
+ ../../pdns/ednssubnet.cc ../../pdns/logger.cc \
+ ../../pdns/misc.cc ../../pdns/nsecrecords.cc \
+ ../../pdns/packetcache.hh ../../pdns/packetcache.cc \
+ ../../pdns/qtype.cc ../../pdns/sillyrecords.cc \
+ ../../pdns/statbag.cc ../../pdns/ueberbackend.hh \
+ ../../pdns/ueberbackend.cc ../../pdns/dns.hh ../../pdns/dns.cc \
+ ../../pdns/dns_random.cc ../../pdns/dnswriter.cc \
+ ../../pdns/nameserver.cc ../../pdns/rcpgenerator.cc \
+ ../../pdns/unix_utility.cc ../../pdns/gss_context.cc \
+ ../../pdns/gss_context.hh ../../pdns/json.hh \
+ ../../pdns/json.cc httpconnector.cc pipeconnector.cc \
+ unixconnector.cc zmqconnector.cc remotebackend.hh \
+ remotebackend.cc $(am__append_3)
+libtestremotebackend_la_CPPFLAGS = $(AM_CPPFLAGS) $(am__append_5) \
+ $(am__append_7)
+libtestremotebackend_la_LIBADD = $(YAHTTP_LIBS) $(LIBCRYPTO_LIBS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) $(LIBDL) $(JSON11_LIBS) \
+ $(am__append_2) $(am__append_4) $(am__append_6)
+libtestremotebackend_la_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS)
+
+remotebackend_http_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-http.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_http_test_LDADD = libtestremotebackend.la
+remotebackend_json_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-json.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_json_test_LDADD = libtestremotebackend.la
+remotebackend_pipe_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-pipe.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_pipe_test_LDADD = libtestremotebackend.la
+remotebackend_post_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-post.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_post_test_LDADD = libtestremotebackend.la
+remotebackend_unix_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-unix.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_unix_test_LDADD = libtestremotebackend.la
+remotebackend_zeromq_test_SOURCES = \
+ test-remotebackend.cc \
+ test-remotebackend-zeromq.cc \
+ test-remotebackend-keys.hh
+
+remotebackend_zeromq_test_LDADD = libtestremotebackend.la
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .log .o .obj .test .test$(EXEEXT) .trs
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/remotebackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/remotebackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libremotebackend.la: $(libremotebackend_la_OBJECTS) $(libremotebackend_la_DEPENDENCIES) $(EXTRA_libremotebackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libremotebackend_la_LINK) -rpath $(pkglibdir) $(libremotebackend_la_OBJECTS) $(libremotebackend_la_LIBADD) $(LIBS)
+../../pdns/$(am__dirstamp):
+ @$(MKDIR_P) ../../pdns
+ @: > ../../pdns/$(am__dirstamp)
+../../pdns/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) ../../pdns/$(DEPDIR)
+ @: > ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-arguments.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-base32.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-base64.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnsbackend.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnslabeltext.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnsname.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnspacket.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnsparser.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnsrecords.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnssecinfra.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-ednssubnet.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-logger.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-misc.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-nsecrecords.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-packetcache.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-qtype.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-sillyrecords.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-statbag.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-ueberbackend.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dns.lo: ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dns_random.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-dnswriter.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-nameserver.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-rcpgenerator.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-unix_utility.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-gss_context.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-json.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+../../pdns/libtestremotebackend_la-pkcs11signers.lo: \
+ ../../pdns/$(am__dirstamp) \
+ ../../pdns/$(DEPDIR)/$(am__dirstamp)
+
+libtestremotebackend.la: $(libtestremotebackend_la_OBJECTS) $(libtestremotebackend_la_DEPENDENCIES) $(EXTRA_libtestremotebackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libtestremotebackend_la_LINK) $(libtestremotebackend_la_OBJECTS) $(libtestremotebackend_la_LIBADD) $(LIBS)
+
+remotebackend_http.test$(EXEEXT): $(remotebackend_http_test_OBJECTS) $(remotebackend_http_test_DEPENDENCIES) $(EXTRA_remotebackend_http_test_DEPENDENCIES)
+ @rm -f remotebackend_http.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_http_test_OBJECTS) $(remotebackend_http_test_LDADD) $(LIBS)
+
+remotebackend_json.test$(EXEEXT): $(remotebackend_json_test_OBJECTS) $(remotebackend_json_test_DEPENDENCIES) $(EXTRA_remotebackend_json_test_DEPENDENCIES)
+ @rm -f remotebackend_json.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_json_test_OBJECTS) $(remotebackend_json_test_LDADD) $(LIBS)
+
+remotebackend_pipe.test$(EXEEXT): $(remotebackend_pipe_test_OBJECTS) $(remotebackend_pipe_test_DEPENDENCIES) $(EXTRA_remotebackend_pipe_test_DEPENDENCIES)
+ @rm -f remotebackend_pipe.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_pipe_test_OBJECTS) $(remotebackend_pipe_test_LDADD) $(LIBS)
+
+remotebackend_post.test$(EXEEXT): $(remotebackend_post_test_OBJECTS) $(remotebackend_post_test_DEPENDENCIES) $(EXTRA_remotebackend_post_test_DEPENDENCIES)
+ @rm -f remotebackend_post.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_post_test_OBJECTS) $(remotebackend_post_test_LDADD) $(LIBS)
+
+remotebackend_unix.test$(EXEEXT): $(remotebackend_unix_test_OBJECTS) $(remotebackend_unix_test_DEPENDENCIES) $(EXTRA_remotebackend_unix_test_DEPENDENCIES)
+ @rm -f remotebackend_unix.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_unix_test_OBJECTS) $(remotebackend_unix_test_LDADD) $(LIBS)
+
+remotebackend_zeromq.test$(EXEEXT): $(remotebackend_zeromq_test_OBJECTS) $(remotebackend_zeromq_test_DEPENDENCIES) $(EXTRA_remotebackend_zeromq_test_DEPENDENCIES)
+ @rm -f remotebackend_zeromq.test$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(remotebackend_zeromq_test_OBJECTS) $(remotebackend_zeromq_test_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f ../../pdns/*.$(OBJEXT)
+ -rm -f ../../pdns/*.lo
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-arguments.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-base32.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-base64.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dns.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dns_random.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnslabeltext.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsname.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnspacket.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsparser.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsrecords.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnssecinfra.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-dnswriter.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-ednssubnet.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-gss_context.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-json.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-logger.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-misc.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-nameserver.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-nsecrecords.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-packetcache.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-pkcs11signers.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-qtype.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-rcpgenerator.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-sillyrecords.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-statbag.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-ueberbackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@../../pdns/$(DEPDIR)/libtestremotebackend_la-unix_utility.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/httpconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestremotebackend_la-httpconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestremotebackend_la-pipeconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestremotebackend_la-remotebackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestremotebackend_la-unixconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libtestremotebackend_la-zmqconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pipeconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/remotebackend.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-http.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-pipe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-post.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-unix.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend-zeromq.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-remotebackend.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unixconnector.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zmqconnector.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+../../pdns/libtestremotebackend_la-arguments.lo: ../../pdns/arguments.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-arguments.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-arguments.Tpo -c -o ../../pdns/libtestremotebackend_la-arguments.lo `test -f '../../pdns/arguments.cc' || echo '$(srcdir)/'`../../pdns/arguments.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-arguments.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-arguments.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/arguments.cc' object='../../pdns/libtestremotebackend_la-arguments.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-arguments.lo `test -f '../../pdns/arguments.cc' || echo '$(srcdir)/'`../../pdns/arguments.cc
+
+../../pdns/libtestremotebackend_la-base32.lo: ../../pdns/base32.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-base32.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-base32.Tpo -c -o ../../pdns/libtestremotebackend_la-base32.lo `test -f '../../pdns/base32.cc' || echo '$(srcdir)/'`../../pdns/base32.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-base32.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-base32.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/base32.cc' object='../../pdns/libtestremotebackend_la-base32.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-base32.lo `test -f '../../pdns/base32.cc' || echo '$(srcdir)/'`../../pdns/base32.cc
+
+../../pdns/libtestremotebackend_la-base64.lo: ../../pdns/base64.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-base64.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-base64.Tpo -c -o ../../pdns/libtestremotebackend_la-base64.lo `test -f '../../pdns/base64.cc' || echo '$(srcdir)/'`../../pdns/base64.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-base64.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-base64.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/base64.cc' object='../../pdns/libtestremotebackend_la-base64.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-base64.lo `test -f '../../pdns/base64.cc' || echo '$(srcdir)/'`../../pdns/base64.cc
+
+../../pdns/libtestremotebackend_la-dnsbackend.lo: ../../pdns/dnsbackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnsbackend.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsbackend.Tpo -c -o ../../pdns/libtestremotebackend_la-dnsbackend.lo `test -f '../../pdns/dnsbackend.cc' || echo '$(srcdir)/'`../../pdns/dnsbackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsbackend.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsbackend.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnsbackend.cc' object='../../pdns/libtestremotebackend_la-dnsbackend.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnsbackend.lo `test -f '../../pdns/dnsbackend.cc' || echo '$(srcdir)/'`../../pdns/dnsbackend.cc
+
+../../pdns/libtestremotebackend_la-dnslabeltext.lo: ../../pdns/dnslabeltext.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnslabeltext.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnslabeltext.Tpo -c -o ../../pdns/libtestremotebackend_la-dnslabeltext.lo `test -f '../../pdns/dnslabeltext.cc' || echo '$(srcdir)/'`../../pdns/dnslabeltext.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnslabeltext.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnslabeltext.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnslabeltext.cc' object='../../pdns/libtestremotebackend_la-dnslabeltext.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnslabeltext.lo `test -f '../../pdns/dnslabeltext.cc' || echo '$(srcdir)/'`../../pdns/dnslabeltext.cc
+
+../../pdns/libtestremotebackend_la-dnsname.lo: ../../pdns/dnsname.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnsname.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsname.Tpo -c -o ../../pdns/libtestremotebackend_la-dnsname.lo `test -f '../../pdns/dnsname.cc' || echo '$(srcdir)/'`../../pdns/dnsname.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsname.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsname.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnsname.cc' object='../../pdns/libtestremotebackend_la-dnsname.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnsname.lo `test -f '../../pdns/dnsname.cc' || echo '$(srcdir)/'`../../pdns/dnsname.cc
+
+../../pdns/libtestremotebackend_la-dnspacket.lo: ../../pdns/dnspacket.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnspacket.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnspacket.Tpo -c -o ../../pdns/libtestremotebackend_la-dnspacket.lo `test -f '../../pdns/dnspacket.cc' || echo '$(srcdir)/'`../../pdns/dnspacket.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnspacket.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnspacket.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnspacket.cc' object='../../pdns/libtestremotebackend_la-dnspacket.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnspacket.lo `test -f '../../pdns/dnspacket.cc' || echo '$(srcdir)/'`../../pdns/dnspacket.cc
+
+../../pdns/libtestremotebackend_la-dnsparser.lo: ../../pdns/dnsparser.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnsparser.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsparser.Tpo -c -o ../../pdns/libtestremotebackend_la-dnsparser.lo `test -f '../../pdns/dnsparser.cc' || echo '$(srcdir)/'`../../pdns/dnsparser.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsparser.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsparser.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnsparser.cc' object='../../pdns/libtestremotebackend_la-dnsparser.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnsparser.lo `test -f '../../pdns/dnsparser.cc' || echo '$(srcdir)/'`../../pdns/dnsparser.cc
+
+../../pdns/libtestremotebackend_la-dnsrecords.lo: ../../pdns/dnsrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnsrecords.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsrecords.Tpo -c -o ../../pdns/libtestremotebackend_la-dnsrecords.lo `test -f '../../pdns/dnsrecords.cc' || echo '$(srcdir)/'`../../pdns/dnsrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsrecords.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnsrecords.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnsrecords.cc' object='../../pdns/libtestremotebackend_la-dnsrecords.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnsrecords.lo `test -f '../../pdns/dnsrecords.cc' || echo '$(srcdir)/'`../../pdns/dnsrecords.cc
+
+../../pdns/libtestremotebackend_la-dnssecinfra.lo: ../../pdns/dnssecinfra.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnssecinfra.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnssecinfra.Tpo -c -o ../../pdns/libtestremotebackend_la-dnssecinfra.lo `test -f '../../pdns/dnssecinfra.cc' || echo '$(srcdir)/'`../../pdns/dnssecinfra.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnssecinfra.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnssecinfra.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnssecinfra.cc' object='../../pdns/libtestremotebackend_la-dnssecinfra.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnssecinfra.lo `test -f '../../pdns/dnssecinfra.cc' || echo '$(srcdir)/'`../../pdns/dnssecinfra.cc
+
+../../pdns/libtestremotebackend_la-ednssubnet.lo: ../../pdns/ednssubnet.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-ednssubnet.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-ednssubnet.Tpo -c -o ../../pdns/libtestremotebackend_la-ednssubnet.lo `test -f '../../pdns/ednssubnet.cc' || echo '$(srcdir)/'`../../pdns/ednssubnet.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-ednssubnet.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-ednssubnet.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/ednssubnet.cc' object='../../pdns/libtestremotebackend_la-ednssubnet.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-ednssubnet.lo `test -f '../../pdns/ednssubnet.cc' || echo '$(srcdir)/'`../../pdns/ednssubnet.cc
+
+../../pdns/libtestremotebackend_la-logger.lo: ../../pdns/logger.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-logger.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-logger.Tpo -c -o ../../pdns/libtestremotebackend_la-logger.lo `test -f '../../pdns/logger.cc' || echo '$(srcdir)/'`../../pdns/logger.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-logger.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-logger.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/logger.cc' object='../../pdns/libtestremotebackend_la-logger.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-logger.lo `test -f '../../pdns/logger.cc' || echo '$(srcdir)/'`../../pdns/logger.cc
+
+../../pdns/libtestremotebackend_la-misc.lo: ../../pdns/misc.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-misc.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-misc.Tpo -c -o ../../pdns/libtestremotebackend_la-misc.lo `test -f '../../pdns/misc.cc' || echo '$(srcdir)/'`../../pdns/misc.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-misc.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-misc.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/misc.cc' object='../../pdns/libtestremotebackend_la-misc.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-misc.lo `test -f '../../pdns/misc.cc' || echo '$(srcdir)/'`../../pdns/misc.cc
+
+../../pdns/libtestremotebackend_la-nsecrecords.lo: ../../pdns/nsecrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-nsecrecords.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-nsecrecords.Tpo -c -o ../../pdns/libtestremotebackend_la-nsecrecords.lo `test -f '../../pdns/nsecrecords.cc' || echo '$(srcdir)/'`../../pdns/nsecrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-nsecrecords.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-nsecrecords.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/nsecrecords.cc' object='../../pdns/libtestremotebackend_la-nsecrecords.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-nsecrecords.lo `test -f '../../pdns/nsecrecords.cc' || echo '$(srcdir)/'`../../pdns/nsecrecords.cc
+
+../../pdns/libtestremotebackend_la-packetcache.lo: ../../pdns/packetcache.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-packetcache.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-packetcache.Tpo -c -o ../../pdns/libtestremotebackend_la-packetcache.lo `test -f '../../pdns/packetcache.cc' || echo '$(srcdir)/'`../../pdns/packetcache.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-packetcache.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-packetcache.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/packetcache.cc' object='../../pdns/libtestremotebackend_la-packetcache.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-packetcache.lo `test -f '../../pdns/packetcache.cc' || echo '$(srcdir)/'`../../pdns/packetcache.cc
+
+../../pdns/libtestremotebackend_la-qtype.lo: ../../pdns/qtype.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-qtype.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-qtype.Tpo -c -o ../../pdns/libtestremotebackend_la-qtype.lo `test -f '../../pdns/qtype.cc' || echo '$(srcdir)/'`../../pdns/qtype.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-qtype.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-qtype.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/qtype.cc' object='../../pdns/libtestremotebackend_la-qtype.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-qtype.lo `test -f '../../pdns/qtype.cc' || echo '$(srcdir)/'`../../pdns/qtype.cc
+
+../../pdns/libtestremotebackend_la-sillyrecords.lo: ../../pdns/sillyrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-sillyrecords.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-sillyrecords.Tpo -c -o ../../pdns/libtestremotebackend_la-sillyrecords.lo `test -f '../../pdns/sillyrecords.cc' || echo '$(srcdir)/'`../../pdns/sillyrecords.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-sillyrecords.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-sillyrecords.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/sillyrecords.cc' object='../../pdns/libtestremotebackend_la-sillyrecords.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-sillyrecords.lo `test -f '../../pdns/sillyrecords.cc' || echo '$(srcdir)/'`../../pdns/sillyrecords.cc
+
+../../pdns/libtestremotebackend_la-statbag.lo: ../../pdns/statbag.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-statbag.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-statbag.Tpo -c -o ../../pdns/libtestremotebackend_la-statbag.lo `test -f '../../pdns/statbag.cc' || echo '$(srcdir)/'`../../pdns/statbag.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-statbag.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-statbag.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/statbag.cc' object='../../pdns/libtestremotebackend_la-statbag.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-statbag.lo `test -f '../../pdns/statbag.cc' || echo '$(srcdir)/'`../../pdns/statbag.cc
+
+../../pdns/libtestremotebackend_la-ueberbackend.lo: ../../pdns/ueberbackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-ueberbackend.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-ueberbackend.Tpo -c -o ../../pdns/libtestremotebackend_la-ueberbackend.lo `test -f '../../pdns/ueberbackend.cc' || echo '$(srcdir)/'`../../pdns/ueberbackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-ueberbackend.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-ueberbackend.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/ueberbackend.cc' object='../../pdns/libtestremotebackend_la-ueberbackend.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-ueberbackend.lo `test -f '../../pdns/ueberbackend.cc' || echo '$(srcdir)/'`../../pdns/ueberbackend.cc
+
+../../pdns/libtestremotebackend_la-dns.lo: ../../pdns/dns.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dns.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns.Tpo -c -o ../../pdns/libtestremotebackend_la-dns.lo `test -f '../../pdns/dns.cc' || echo '$(srcdir)/'`../../pdns/dns.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dns.cc' object='../../pdns/libtestremotebackend_la-dns.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dns.lo `test -f '../../pdns/dns.cc' || echo '$(srcdir)/'`../../pdns/dns.cc
+
+../../pdns/libtestremotebackend_la-dns_random.lo: ../../pdns/dns_random.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dns_random.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns_random.Tpo -c -o ../../pdns/libtestremotebackend_la-dns_random.lo `test -f '../../pdns/dns_random.cc' || echo '$(srcdir)/'`../../pdns/dns_random.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns_random.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dns_random.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dns_random.cc' object='../../pdns/libtestremotebackend_la-dns_random.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dns_random.lo `test -f '../../pdns/dns_random.cc' || echo '$(srcdir)/'`../../pdns/dns_random.cc
+
+../../pdns/libtestremotebackend_la-dnswriter.lo: ../../pdns/dnswriter.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-dnswriter.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnswriter.Tpo -c -o ../../pdns/libtestremotebackend_la-dnswriter.lo `test -f '../../pdns/dnswriter.cc' || echo '$(srcdir)/'`../../pdns/dnswriter.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnswriter.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-dnswriter.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/dnswriter.cc' object='../../pdns/libtestremotebackend_la-dnswriter.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-dnswriter.lo `test -f '../../pdns/dnswriter.cc' || echo '$(srcdir)/'`../../pdns/dnswriter.cc
+
+../../pdns/libtestremotebackend_la-nameserver.lo: ../../pdns/nameserver.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-nameserver.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-nameserver.Tpo -c -o ../../pdns/libtestremotebackend_la-nameserver.lo `test -f '../../pdns/nameserver.cc' || echo '$(srcdir)/'`../../pdns/nameserver.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-nameserver.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-nameserver.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/nameserver.cc' object='../../pdns/libtestremotebackend_la-nameserver.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-nameserver.lo `test -f '../../pdns/nameserver.cc' || echo '$(srcdir)/'`../../pdns/nameserver.cc
+
+../../pdns/libtestremotebackend_la-rcpgenerator.lo: ../../pdns/rcpgenerator.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-rcpgenerator.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-rcpgenerator.Tpo -c -o ../../pdns/libtestremotebackend_la-rcpgenerator.lo `test -f '../../pdns/rcpgenerator.cc' || echo '$(srcdir)/'`../../pdns/rcpgenerator.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-rcpgenerator.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-rcpgenerator.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/rcpgenerator.cc' object='../../pdns/libtestremotebackend_la-rcpgenerator.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-rcpgenerator.lo `test -f '../../pdns/rcpgenerator.cc' || echo '$(srcdir)/'`../../pdns/rcpgenerator.cc
+
+../../pdns/libtestremotebackend_la-unix_utility.lo: ../../pdns/unix_utility.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-unix_utility.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-unix_utility.Tpo -c -o ../../pdns/libtestremotebackend_la-unix_utility.lo `test -f '../../pdns/unix_utility.cc' || echo '$(srcdir)/'`../../pdns/unix_utility.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-unix_utility.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-unix_utility.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/unix_utility.cc' object='../../pdns/libtestremotebackend_la-unix_utility.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-unix_utility.lo `test -f '../../pdns/unix_utility.cc' || echo '$(srcdir)/'`../../pdns/unix_utility.cc
+
+../../pdns/libtestremotebackend_la-gss_context.lo: ../../pdns/gss_context.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-gss_context.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-gss_context.Tpo -c -o ../../pdns/libtestremotebackend_la-gss_context.lo `test -f '../../pdns/gss_context.cc' || echo '$(srcdir)/'`../../pdns/gss_context.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-gss_context.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-gss_context.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/gss_context.cc' object='../../pdns/libtestremotebackend_la-gss_context.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-gss_context.lo `test -f '../../pdns/gss_context.cc' || echo '$(srcdir)/'`../../pdns/gss_context.cc
+
+../../pdns/libtestremotebackend_la-json.lo: ../../pdns/json.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-json.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-json.Tpo -c -o ../../pdns/libtestremotebackend_la-json.lo `test -f '../../pdns/json.cc' || echo '$(srcdir)/'`../../pdns/json.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-json.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-json.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/json.cc' object='../../pdns/libtestremotebackend_la-json.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-json.lo `test -f '../../pdns/json.cc' || echo '$(srcdir)/'`../../pdns/json.cc
+
+libtestremotebackend_la-httpconnector.lo: httpconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libtestremotebackend_la-httpconnector.lo -MD -MP -MF $(DEPDIR)/libtestremotebackend_la-httpconnector.Tpo -c -o libtestremotebackend_la-httpconnector.lo `test -f 'httpconnector.cc' || echo '$(srcdir)/'`httpconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestremotebackend_la-httpconnector.Tpo $(DEPDIR)/libtestremotebackend_la-httpconnector.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='httpconnector.cc' object='libtestremotebackend_la-httpconnector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libtestremotebackend_la-httpconnector.lo `test -f 'httpconnector.cc' || echo '$(srcdir)/'`httpconnector.cc
+
+libtestremotebackend_la-pipeconnector.lo: pipeconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libtestremotebackend_la-pipeconnector.lo -MD -MP -MF $(DEPDIR)/libtestremotebackend_la-pipeconnector.Tpo -c -o libtestremotebackend_la-pipeconnector.lo `test -f 'pipeconnector.cc' || echo '$(srcdir)/'`pipeconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestremotebackend_la-pipeconnector.Tpo $(DEPDIR)/libtestremotebackend_la-pipeconnector.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='pipeconnector.cc' object='libtestremotebackend_la-pipeconnector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libtestremotebackend_la-pipeconnector.lo `test -f 'pipeconnector.cc' || echo '$(srcdir)/'`pipeconnector.cc
+
+libtestremotebackend_la-unixconnector.lo: unixconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libtestremotebackend_la-unixconnector.lo -MD -MP -MF $(DEPDIR)/libtestremotebackend_la-unixconnector.Tpo -c -o libtestremotebackend_la-unixconnector.lo `test -f 'unixconnector.cc' || echo '$(srcdir)/'`unixconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestremotebackend_la-unixconnector.Tpo $(DEPDIR)/libtestremotebackend_la-unixconnector.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='unixconnector.cc' object='libtestremotebackend_la-unixconnector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libtestremotebackend_la-unixconnector.lo `test -f 'unixconnector.cc' || echo '$(srcdir)/'`unixconnector.cc
+
+libtestremotebackend_la-zmqconnector.lo: zmqconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libtestremotebackend_la-zmqconnector.lo -MD -MP -MF $(DEPDIR)/libtestremotebackend_la-zmqconnector.Tpo -c -o libtestremotebackend_la-zmqconnector.lo `test -f 'zmqconnector.cc' || echo '$(srcdir)/'`zmqconnector.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestremotebackend_la-zmqconnector.Tpo $(DEPDIR)/libtestremotebackend_la-zmqconnector.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='zmqconnector.cc' object='libtestremotebackend_la-zmqconnector.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libtestremotebackend_la-zmqconnector.lo `test -f 'zmqconnector.cc' || echo '$(srcdir)/'`zmqconnector.cc
+
+libtestremotebackend_la-remotebackend.lo: remotebackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT libtestremotebackend_la-remotebackend.lo -MD -MP -MF $(DEPDIR)/libtestremotebackend_la-remotebackend.Tpo -c -o libtestremotebackend_la-remotebackend.lo `test -f 'remotebackend.cc' || echo '$(srcdir)/'`remotebackend.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libtestremotebackend_la-remotebackend.Tpo $(DEPDIR)/libtestremotebackend_la-remotebackend.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='remotebackend.cc' object='libtestremotebackend_la-remotebackend.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o libtestremotebackend_la-remotebackend.lo `test -f 'remotebackend.cc' || echo '$(srcdir)/'`remotebackend.cc
+
+../../pdns/libtestremotebackend_la-pkcs11signers.lo: ../../pdns/pkcs11signers.cc
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ../../pdns/libtestremotebackend_la-pkcs11signers.lo -MD -MP -MF ../../pdns/$(DEPDIR)/libtestremotebackend_la-pkcs11signers.Tpo -c -o ../../pdns/libtestremotebackend_la-pkcs11signers.lo `test -f '../../pdns/pkcs11signers.cc' || echo '$(srcdir)/'`../../pdns/pkcs11signers.cc
+@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) ../../pdns/$(DEPDIR)/libtestremotebackend_la-pkcs11signers.Tpo ../../pdns/$(DEPDIR)/libtestremotebackend_la-pkcs11signers.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='../../pdns/pkcs11signers.cc' object='../../pdns/libtestremotebackend_la-pkcs11signers.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libtestremotebackend_la_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -c -o ../../pdns/libtestremotebackend_la-pkcs11signers.lo `test -f '../../pdns/pkcs11signers.cc' || echo '$(srcdir)/'`../../pdns/pkcs11signers.cc
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+ -rm -rf ../../pdns/.libs ../../pdns/_libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f ../../pdns/$(DEPDIR)/$(am__dirstamp)
+ -rm -f ../../pdns/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-local \
+ clean-pkglibLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ../../pdns/$(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ../../pdns/$(DEPDIR) ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am clean \
+ clean-generic clean-libtool clean-local \
+ clean-pkglibLTLIBRARIES cscopelist-am ctags ctags-am distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-am install-data install-data-am install-dvi \
+ install-dvi-am install-exec install-exec-am install-html \
+ install-html-am install-info install-info-am install-man \
+ install-pdf install-pdf-am install-pkglibLTLIBRARIES \
+ install-ps install-ps-am install-strip installcheck \
+ installcheck-am installdirs maintainer-clean \
+ maintainer-clean-generic mostlyclean mostlyclean-compile \
+ mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
+ recheck tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+clean-local:
+ rm -f $(EXTRA_PROGRAMS)
+
+remotebackend_post.log: remotebackend_http.log
+
+remotebackend_json.log: remotebackend_http.log remotebackend_post.log
+
+../../pdns/dnslabeltext.cc: ../../pdns/dnslabeltext.rl
+ $(MAKE) -C ../../pdns dnslabeltext.cc
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+remotebackend.lo unixconnector.lo httpconnector.lo pipeconnector.lo zmqconnector.lo
--- /dev/null
+$(LIBZMQ_LIBS)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "remotebackend.hh"
+#include <sys/socket.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#include <sstream>
+#include "pdns/lock.hh"
+
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+HTTPConnector::HTTPConnector(std::map<std::string,std::string> options) {
+ this->d_url = options.find("url")->second;
+ if (options.find("url-suffix") != options.end()) {
+ this->d_url_suffix = options.find("url-suffix")->second;
+ } else {
+ this->d_url_suffix = "";
+ }
+ this->timeout = 2;
+ this->d_post = false;
+ this->d_post_json = false;
+ this->d_socket = NULL;
+
+ if (options.find("timeout") != options.end()) {
+ this->timeout = std::stoi(options.find("timeout")->second)/1000;
+ }
+ if (options.find("post") != options.end()) {
+ std::string val = options.find("post")->second;
+ if (val == "yes" || val == "true" || val == "on" || val == "1") {
+ this->d_post = true;
+ }
+ }
+ if (options.find("post_json") != options.end()) {
+ std::string val = options.find("post_json")->second;
+ if (val == "yes" || val == "true" || val == "on" || val == "1") {
+ this->d_post_json = true;
+ }
+ }
+}
+
+HTTPConnector::~HTTPConnector() {
+ if (d_socket != NULL)
+ delete d_socket;
+}
+
+void HTTPConnector::addUrlComponent(const Json ¶meters, const string& element, std::stringstream& ss) {
+ std::string sparam;
+ if (parameters[element] != Json())
+ ss << "/" << asString(parameters[element]);
+}
+
+std::string HTTPConnector::buildMemberListArgs(std::string prefix, const Json& args) {
+ std::stringstream stream;
+
+ for(const auto& pair: args.object_items()) {
+ if (pair.second.is_bool()) {
+ stream << (pair.second.bool_value()?"1":"0");
+ } else {
+ stream << prefix << "[" << pair.first << "]=" << this->asString(pair.second);
+ }
+
+ stream << "&";
+ }
+
+ return stream.str().substr(0, stream.str().size()-1); // snip the trailing &
+}
+
+// builds our request (near-restful)
+void HTTPConnector::restful_requestbuilder(const std::string &method, const Json& parameters, YaHTTP::Request& req)
+{
+ std::stringstream ss;
+ std::string sparam;
+ std::string verb;
+
+ // special names are qname, name, zonename, kind, others go to headers
+
+ ss << d_url;
+
+ ss << "/" << method;
+
+ // add the url components, if found, in following order.
+ // id must be first due to the fact that the qname/name can be empty
+
+ addUrlComponent(parameters, "id", ss);
+ addUrlComponent(parameters, "domain_id", ss);
+ addUrlComponent(parameters, "zonename", ss);
+ addUrlComponent(parameters, "qname", ss);
+ addUrlComponent(parameters, "name", ss);
+ addUrlComponent(parameters, "kind", ss);
+ addUrlComponent(parameters, "qtype", ss);
+
+ // set the correct type of request based on method
+ if (method == "activateDomainKey" || method == "deactivateDomainKey") {
+ // create an empty post
+ req.preparePost();
+ verb = "POST";
+ } else if (method == "setTSIGKey") {
+ req.POST()["algorithm"] = parameters["algorithm"].string_value();
+ req.POST()["content"] = parameters["content"].string_value();
+ req.preparePost();
+ verb = "PATCH";
+ } else if (method == "deleteTSIGKey") {
+ verb = "DELETE";
+ } else if (method == "addDomainKey") {
+ const Json& param = parameters["key"];
+ req.POST()["flags"] = asString(param["flags"]);
+ req.POST()["active"] = (param["active"].bool_value() ? "1" : "0");
+ req.POST()["content"] = param["content"].string_value();
+ req.preparePost();
+ verb = "PUT";
+ } else if (method == "isMaster") {
+ addUrlComponent(parameters, "ip", ss);
+ verb = "GET";
+ } else if (method == "superMasterBackend") {
+ std::stringstream ss2;
+ addUrlComponent(parameters, "ip", ss);
+ addUrlComponent(parameters, "domain", ss);
+ // then we need to serialize rrset payload into POST
+ for(size_t index = 0; index < parameters["nsset"].array_items().size(); index++) {
+ ss2 << buildMemberListArgs("nsset[" + std::to_string(index) + "]", parameters["nsset"][index]) << "&";
+ }
+ req.body = ss2.str().substr(0, ss2.str().size()-1);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "POST";
+ } else if (method == "createSlaveDomain") {
+ addUrlComponent(parameters, "ip", ss);
+ addUrlComponent(parameters, "domain", ss);
+ if (parameters["account"].is_null() == false && parameters["account"].is_string()) {
+ req.POST()["account"] = parameters["account"].string_value();
+ }
+ req.preparePost();
+ verb = "PUT";
+ } else if (method == "replaceRRSet") {
+ std::stringstream ss2;
+ for(size_t index = 0; index < parameters["rrset"].array_items().size(); index++) {
+ ss2 << buildMemberListArgs("rrset[" + std::to_string(index) + "]", parameters["rrset"][index]);
+ }
+ req.body = ss2.str();
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "PATCH";
+ } else if (method == "feedRecord") {
+ addUrlComponent(parameters, "trxid", ss);
+ req.body = buildMemberListArgs("rr", parameters["rr"]);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "PATCH";
+ } else if (method == "feedEnts") {
+ std::stringstream ss2;
+ addUrlComponent(parameters, "trxid", ss);
+ for(const auto& param: parameters["nonterm"].array_items()) {
+ ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(param.string_value(), false) << "&";
+ }
+ for(const auto& param: parameters["auth"].array_items()) {
+ ss2 << "auth[]=" << (param["auth"].bool_value()?"1":"0") << "&";
+ }
+ req.body = ss2.str().substr(0, ss2.str().size()-1);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "PATCH";
+ } else if (method == "feedEnts3") {
+ std::stringstream ss2;
+ addUrlComponent(parameters, "domain", ss);
+ addUrlComponent(parameters, "trxid", ss);
+ ss2 << "times=" << parameters["times"].int_value() << "&salt=" << YaHTTP::Utility::encodeURL(parameters["salt"].string_value(), false) << "&narrow=" << (parameters["narrow"].bool_value() ? 1 : 0) << "&";
+ for(const auto& param: parameters["nonterm"].array_items()) {
+ ss2 << "nonterm[]=" << YaHTTP::Utility::encodeURL(param.string_value(), false) << "&";
+ }
+ for(const auto& param: parameters["auth"].array_items()) {
+ ss2 << "auth[]=" << (param["auth"].bool_value()?"1":"0") << "&";
+ }
+ req.body = ss2.str().substr(0, ss2.str().size()-1);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "PATCH";
+ } else if (method == "startTransaction") {
+ addUrlComponent(parameters, "domain", ss);
+ addUrlComponent(parameters, "trxid", ss);
+ req.preparePost();
+ verb = "POST";
+ } else if (method == "commitTransaction" || method == "abortTransaction") {
+ addUrlComponent(parameters, "trxid", ss);
+ req.preparePost();
+ verb = "POST";
+ } else if (method == "calculateSOASerial") {
+ addUrlComponent(parameters, "domain", ss);
+ req.body = buildMemberListArgs("sd", parameters["sd"]);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "POST";
+ } else if (method == "setDomainMetadata") {
+ // copy all metadata values into post
+ std::stringstream ss2;
+ // this one has values too
+ if (parameters["value"].is_array()) {
+ for(const auto& val: parameters["value"].array_items()) {
+ ss2 << "value[]=" << YaHTTP::Utility::encodeURL(val.string_value(), false) << "&";
+ }
+ }
+ req.body = ss2.str().substr(0, ss2.str().size()-1);
+ req.headers["content-type"] = "application/x-www-form-urlencoded; charset=utf-8";
+ req.headers["content-length"] = std::to_string(req.body.size());
+ verb = "PATCH";
+ } else if (method == "removeDomainKey") {
+ // this one is delete
+ verb = "DELETE";
+ } else if (method == "setNotified") {
+ req.POST()["serial"] = std::to_string(parameters["serial"].number_value());
+ req.preparePost();
+ verb = "PATCH";
+ } else if (method == "directBackendCmd") {
+ req.POST()["query"] = parameters["query"].string_value();
+ req.preparePost();
+ verb = "POST";
+ } else if (method == "searchRecords" || method == "searchComments") {
+ req.GET()["pattern"] = parameters["pattern"].string_value();
+ req.GET()["maxResults"] = std::to_string(parameters["maxResults"].int_value());
+ verb = "GET";
+ } else if (method == "getAllDomains") {
+ req.GET()["includeDisabled"] = (parameters["include_disabled"].bool_value()?"true":"false");
+ verb = "GET";
+ } else {
+ // perform normal get
+ verb = "GET";
+ }
+
+ // put everything else into headers
+ for(const auto& pair: parameters.object_items()) {
+ std::string member = pair.first;
+ // whitelist header parameters
+ if ((member == "trxid" ||
+ member == "local" ||
+ member == "remote" ||
+ member == "real-remote" ||
+ member == "zone-id")) {
+ std::string hdr = "x-remotebackend-" + member;
+ req.headers[hdr] = asString(pair.second);
+ }
+ };
+
+ // finally add suffix and store url
+ ss << d_url_suffix;
+
+ req.setup(verb, ss.str());
+ req.headers["accept"] = "application/json";
+}
+
+void HTTPConnector::post_requestbuilder(const Json& input, YaHTTP::Request& req) {
+ if (this->d_post_json) {
+ std::string out = input.dump();
+ req.setup("POST", d_url);
+ // simple case, POST JSON into url. nothing fancy.
+ req.headers["Content-Type"] = "text/javascript; charset=utf-8";
+ req.headers["Content-Length"] = std::to_string(out.size());
+ req.headers["accept"] = "application/json";
+ req.body = out;
+ } else {
+ std::stringstream url,content;
+ // call url/method.suffix
+ url << d_url << "/" << input["method"].string_value() << d_url_suffix;
+ req.setup("POST", url.str());
+ // then build content
+ req.POST()["parameters"] = input["parameters"].dump();
+ req.preparePost();
+ req.headers["accept"] = "application/json";
+ }
+}
+
+int HTTPConnector::send_message(const Json& input) {
+ int rv,ec,fd;
+
+ std::vector<std::string> members;
+ std::string method;
+ std::ostringstream out;
+
+ // perform request
+ YaHTTP::Request req;
+
+ if (d_post)
+ post_requestbuilder(input, req);
+ else
+ restful_requestbuilder(input["method"].string_value(), input["parameters"], req);
+
+ rv = -1;
+ req.headers["connection"] = "Keep-Alive"; // see if we can streamline requests (not needed, strictly speaking)
+
+ out << req;
+
+ // try sending with current socket, if it fails retry with new socket
+ if (this->d_socket != NULL) {
+ fd = this->d_socket->getHandle();
+ // there should be no data waiting
+ if (waitForRWData(fd, true, 0, 1000) < 1) {
+ try {
+ d_socket->writenWithTimeout(out.str().c_str(), out.str().size(), timeout);
+ rv = 1;
+ } catch (NetworkError& ne) {
+ L<<Logger::Error<<"While writing to HTTP endpoint "<<d_addr.toStringWithPort()<<": "<<ne.what()<<std::endl;
+ } catch (...) {
+ L<<Logger::Error<<"While writing to HTTP endpoint "<<d_addr.toStringWithPort()<<": exception caught"<<std::endl;
+ }
+ }
+ }
+
+ if (rv == 1) return rv;
+
+ delete this->d_socket;
+ this->d_socket = NULL;
+
+ if (req.url.protocol == "unix") {
+ // connect using unix socket
+ } else {
+ // connect using tcp
+ struct addrinfo *gAddr, *gAddrPtr, hints;
+ std::string sPort = std::to_string(req.url.port);
+ memset(&hints,0,sizeof hints);
+ hints.ai_family = AF_UNSPEC;
+ hints.ai_flags = AI_ADDRCONFIG;
+ hints.ai_socktype = SOCK_STREAM;
+ hints.ai_protocol = 6; // tcp
+ if ((ec = getaddrinfo(req.url.host.c_str(), sPort.c_str(), &hints, &gAddr)) == 0) {
+ // try to connect to each address.
+ gAddrPtr = gAddr;
+
+ while(gAddrPtr) {
+ try {
+ d_socket = new Socket(gAddrPtr->ai_family, gAddrPtr->ai_socktype, gAddrPtr->ai_protocol);
+ d_addr.setSockaddr(gAddrPtr->ai_addr, gAddrPtr->ai_addrlen);
+ d_socket->connect(d_addr);
+ d_socket->setNonBlocking();
+ d_socket->writenWithTimeout(out.str().c_str(), out.str().size(), timeout);
+ rv = 1;
+ } catch (NetworkError& ne) {
+ L<<Logger::Error<<"While writing to HTTP endpoint "<<d_addr.toStringWithPort()<<": "<<ne.what()<<std::endl;
+ } catch (...) {
+ L<<Logger::Error<<"While writing to HTTP endpoint "<<d_addr.toStringWithPort()<<": exception caught"<<std::endl;
+ }
+
+ if (rv > -1) break;
+ delete d_socket;
+ d_socket = NULL;
+ gAddrPtr = gAddrPtr->ai_next;
+
+ }
+ freeaddrinfo(gAddr);
+ } else {
+ L<<Logger::Error<<"Unable to resolve " << req.url.host << ": " << gai_strerror(ec) << std::endl;
+ }
+ }
+
+ return rv;
+}
+
+int HTTPConnector::recv_message(Json& output) {
+ YaHTTP::AsyncResponseLoader arl;
+ YaHTTP::Response resp;
+
+ if (d_socket == NULL ) return -1; // cannot receive :(
+ char buffer[4096];
+ int rd = -1;
+ bool fail = false;
+ time_t t0;
+
+ arl.initialize(&resp);
+
+ try {
+ t0 = time((time_t*)NULL);
+ while(arl.ready() == false && (labs(time((time_t*)NULL) - t0) <= timeout)) {
+ rd = d_socket->readWithTimeout(buffer, sizeof(buffer), timeout);
+ if (rd==0)
+ throw NetworkError("EOF while reading");
+ if (rd<0)
+ throw NetworkError(std::string(strerror(rd)));
+ arl.feed(std::string(buffer, rd));
+ }
+ // timeout occured.
+ if (arl.ready() == false)
+ throw NetworkError("timeout");
+ } catch (NetworkError &ne) {
+ L<<Logger::Error<<"While reading from HTTP endpoint "<<d_addr.toStringWithPort()<<": "<<ne.what()<<std::endl;
+ delete d_socket;
+ d_socket = NULL;
+ fail = true;
+ } catch (...) {
+ L<<Logger::Error<<"While reading from HTTP endpoint "<<d_addr.toStringWithPort()<<": exception caught"<<std::endl;
+ delete d_socket;
+ fail = true;
+ }
+
+ if (fail) {
+ return -1;
+ }
+
+ arl.finalize();
+
+ if (resp.status < 200 || resp.status >= 400) {
+ // bad.
+ return -1;
+ }
+
+ int rv = -1;
+ std::string err;
+ output = Json::parse(resp.body, err);
+ if (output != nullptr) return resp.body.size();
+ L<<Logger::Error<<"Cannot parse JSON reply: "<<err<<endl;
+
+ return rv;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "remotebackend.hh"
+
+PipeConnector::PipeConnector(std::map<std::string,std::string> options) {
+ if (options.count("command") == 0) {
+ L<<Logger::Error<<"Cannot find 'command' option in connection string"<<endl;
+ throw PDNSException();
+ }
+ this->command = options.find("command")->second;
+ this->options = options;
+ d_timeout=2000;
+
+ if (options.find("timeout") != options.end()) {
+ d_timeout = std::stoi(options.find("timeout")->second);
+ }
+
+ d_pid = -1;
+ d_fp = NULL;
+ d_fd1[0] = d_fd1[1] = -1;
+ d_fd2[0] = d_fd2[1] = -1;
+}
+
+PipeConnector::~PipeConnector(){
+ int status;
+ // just in case...
+ if (d_pid == -1) return;
+
+ if(!waitpid(d_pid, &status, WNOHANG)) {
+ kill(d_pid, 9);
+ waitpid(d_pid, &status, 0);
+ }
+
+ close(d_fd1[1]);
+ if (d_fp != NULL) fclose(d_fp);
+}
+
+void PipeConnector::launch() {
+ // no relaunch
+ if (d_pid > 0 && checkStatus()) return;
+
+ std::vector <std::string> v;
+ split(v, command, is_any_of(" "));
+
+ const char *argv[v.size()+1];
+ argv[v.size()]=0;
+
+ for (size_t n = 0; n < v.size(); n++)
+ argv[n]=v[n].c_str();
+
+ signal(SIGPIPE, SIG_IGN);
+
+ if(access(argv[0],X_OK)) // check before fork so we can throw
+ throw PDNSException("Command '"+string(argv[0])+"' cannot be executed: "+stringerror());
+
+ if(pipe(d_fd1)<0 || pipe(d_fd2)<0)
+ throw PDNSException("Unable to open pipe for coprocess: "+string(strerror(errno)));
+
+ if((d_pid=fork())<0)
+ throw PDNSException("Unable to fork for coprocess: "+stringerror());
+ else if(d_pid>0) { // parent speaking
+ close(d_fd1[0]);
+ setCloseOnExec(d_fd1[1]);
+ close(d_fd2[1]);
+ setCloseOnExec(d_fd2[0]);
+ if(!(d_fp=fdopen(d_fd2[0],"r")))
+ throw PDNSException("Unable to associate a file pointer with pipe: "+stringerror());
+ if (d_timeout)
+ setbuf(d_fp,0); // no buffering please, confuses select
+ }
+ else if(!d_pid) { // child
+ signal(SIGCHLD, SIG_DFL); // silence a warning from perl
+ close(d_fd1[1]);
+ close(d_fd2[0]);
+
+ if(d_fd1[0]!= 0) {
+ dup2(d_fd1[0], 0);
+ close(d_fd1[0]);
+ }
+
+ if(d_fd2[1]!= 1) {
+ dup2(d_fd2[1], 1);
+ close(d_fd2[1]);
+ }
+
+ // stdin & stdout are now connected, fire up our coprocess!
+
+ if(execv(argv[0], const_cast<char * const *>(argv))<0) // now what
+ exit(123);
+
+ /* not a lot we can do here. We shouldn't return because that will leave a forked process around.
+ no way to log this either - only thing we can do is make sure that our parent catches this soonest! */
+ }
+
+ Json::array parameters;
+ Json msg = Json(Json::object{
+ { "method", "initialize" },
+ { "parameters", Json(options) },
+ });
+
+ this->send(msg);
+ msg = nullptr;
+ if (this->recv(msg)==false) {
+ L<<Logger::Error<<"Failed to initialize coprocess"<<std::endl;
+ }
+}
+
+int PipeConnector::send_message(const Json& input)
+{
+ auto line = input.dump();
+ launch();
+
+ line.append(1,'\n');
+
+ unsigned int sent=0;
+ int bytes;
+
+ // writen routine - socket may not accept al data in one go
+ while(sent<line.size()) {
+ bytes=write(d_fd1[1],line.c_str()+sent,line.length()-sent);
+ if(bytes<0)
+ throw PDNSException("Writing to coprocess failed: "+std::string(strerror(errno)));
+
+ sent+=bytes;
+ }
+ return sent;
+}
+
+int PipeConnector::recv_message(Json& output)
+{
+ std::string receive;
+ std::string err;
+ std::string s_output;
+ launch();
+
+ while(1) {
+ receive.clear();
+ if(d_timeout) {
+ struct timeval tv;
+ tv.tv_sec = d_timeout/1000;
+ tv.tv_usec = (d_timeout % 1000) * 1000;
+ fd_set rds;
+ FD_ZERO(&rds);
+ FD_SET(fileno(d_fp),&rds);
+ int ret=select(fileno(d_fp)+1,&rds,0,0,&tv);
+ if(ret<0)
+ throw PDNSException("Error waiting on data from coprocess: "+stringerror());
+ if(!ret)
+ throw PDNSException("Timeout waiting for data from coprocess");
+ }
+
+ if(!stringfgets(d_fp, receive))
+ throw PDNSException("Child closed pipe");
+
+ s_output.append(receive);
+ // see if it can be parsed
+ output = Json::parse(s_output, err);
+ if (output != nullptr) return s_output.size();
+ }
+ return 0;
+}
+
+bool PipeConnector::checkStatus()
+{
+ int status;
+ int ret=waitpid(d_pid, &status, WNOHANG);
+ if(ret<0)
+ throw PDNSException("Unable to ascertain status of coprocess "+itoa(d_pid)+" from "+itoa(getpid())+": "+string(strerror(errno)));
+ else if(ret) {
+ if(WIFEXITED(status)) {
+ int ret=WEXITSTATUS(status);
+ throw PDNSException("Coprocess exited with code "+itoa(ret));
+ }
+ if(WIFSIGNALED(status)) {
+ int sig=WTERMSIG(status);
+ string reason="CoProcess died on receiving signal "+itoa(sig);
+#ifdef WCOREDUMP
+ if(WCOREDUMP(status))
+ reason+=". Dumped core";
+#endif
+
+ throw PDNSException(reason);
+ }
+ }
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "remotebackend.hh"
+
+static const char *kBackendId = "[RemoteBackend]";
+
+/**
+ * Forwarder for value. This is just in case
+ * we need to do some treatment to the value before
+ * sending it downwards.
+ */
+bool Connector::send(Json& value) {
+ return send_message(value)>0;
+}
+
+/**
+ * Helper for handling receiving of data.
+ * Basically what happens here is that we check
+ * that the receiving happened ok, and extract
+ * result. Logging is performed here, too.
+ */
+bool Connector::recv(Json& value) {
+ if (recv_message(value)>0) {
+ bool rv = true;
+ // check for error
+ if (value["result"] == Json())
+ return false;
+ if (value["result"].is_bool() && boolFromJson(value, "result", false) == false)
+ rv = false;
+ for(const auto& message: value["log"].array_items())
+ L<<Logger::Info<<"[remotebackend]: "<< message.string_value() <<std::endl;
+ return rv;
+ }
+ return false;
+}
+
+/**
+ * Standard ctor and dtor
+ */
+RemoteBackend::RemoteBackend(const std::string &suffix)
+{
+ setArgPrefix("remote"+suffix);
+
+ this->d_connstr = getArg("connection-string");
+ this->d_dnssec = mustDo("dnssec");
+ this->d_index = -1;
+ this->d_trxid = 0;
+
+ build();
+}
+
+RemoteBackend::~RemoteBackend() {
+ if (connector != NULL) {
+ delete connector;
+ }
+}
+
+bool RemoteBackend::send(Json& value) {
+ try {
+ return connector->send(value);
+ } catch (PDNSException &ex) {
+ L<<Logger::Error<<"Exception caught when sending: "<<ex.reason<<std::endl;
+ }
+
+ delete this->connector;
+ build();
+ return false;
+}
+
+bool RemoteBackend::recv(Json& value) {
+ try {
+ return connector->recv(value);
+ } catch (PDNSException &ex) {
+ L<<Logger::Error<<"Exception caught when receiving: "<<ex.reason<<std::endl;
+ } catch (...) {
+ L<<Logger::Error<<"Exception caught when receiving"<<std::endl;;
+ }
+
+ delete this->connector;
+ build();
+ return false;
+}
+
+
+/**
+ * Builds connector based on options
+ * Currently supports unix,pipe and http
+ */
+int RemoteBackend::build() {
+ std::vector<std::string> parts;
+ std::string type;
+ std::string opts;
+ std::map<std::string, std::string> options;
+
+ // connstr is of format "type:options"
+ size_t pos;
+ pos = d_connstr.find_first_of(":");
+ if (pos == std::string::npos)
+ throw PDNSException("Invalid connection string: malformed");
+
+ type = d_connstr.substr(0, pos);
+ opts = d_connstr.substr(pos+1);
+
+ // tokenize the string on comma
+ stringtok(parts, opts, ",");
+
+ // find out some options and parse them while we're at it
+ for(const auto& opt: parts) {
+ std::string key,val;
+ // make sure there is something else than air in the option...
+ if (opt.find_first_not_of(" ") == std::string::npos) continue;
+
+ // split it on '='. if not found, we treat it as "yes"
+ pos = opt.find_first_of("=");
+
+ if (pos == std::string::npos) {
+ key = opt;
+ val = "yes";
+ } else {
+ key = opt.substr(0,pos);
+ val = opt.substr(pos+1);
+ }
+ options[key] = val;
+ }
+
+ // connectors know what they are doing
+ if (type == "unix") {
+ this->connector = new UnixsocketConnector(options);
+ } else if (type == "http") {
+ this->connector = new HTTPConnector(options);
+ } else if (type == "zeromq") {
+#ifdef REMOTEBACKEND_ZEROMQ
+ this->connector = new ZeroMQConnector(options);
+#else
+ throw PDNSException("Invalid connection string: zeromq connector support not enabled. Recompile with --enable-remotebackend-zeromq");
+#endif
+ } else if (type == "pipe") {
+ this->connector = new PipeConnector(options);
+ } else {
+ throw PDNSException("Invalid connection string: unknown connector");
+ }
+
+ return -1;
+}
+
+/**
+ * The functions here are just remote json stubs that send and receive the method call
+ * data is mainly left alone, some defaults are assumed.
+ */
+void RemoteBackend::lookup(const QType &qtype, const DNSName& qdomain, DNSPacket *pkt_p, int zoneId) {
+ if (d_index != -1)
+ throw PDNSException("Attempt to lookup while one running");
+
+ string localIP="0.0.0.0";
+ string remoteIP="0.0.0.0";
+ string realRemote="0.0.0.0/0";
+
+ if (pkt_p) {
+ localIP=pkt_p->getLocal().toString();
+ realRemote = pkt_p->getRealRemote().toString();
+ remoteIP = pkt_p->getRemote().toString();
+ }
+
+ Json query = Json::object{
+ { "method", "lookup" },
+ { "parameters", Json::object{
+ { "qtype", qtype.getName() },
+ { "qname", qdomain.toString() },
+ { "remote", remoteIP },
+ { "local", localIP },
+ { "real-remote", realRemote },
+ { "zone-id", zoneId }
+ }}
+ };
+
+ if (this->send(query) == false || this->recv(d_result) == false) {
+ return;
+ }
+
+ // OK. we have result parameters in result. do not process empty result.
+ if (d_result["result"].is_array() == false || d_result["result"].array_items().size() < 1)
+ return;
+
+ d_index = 0;
+}
+
+bool RemoteBackend::list(const DNSName& target, int domain_id, bool include_disabled) {
+ if (d_index != -1)
+ throw PDNSException("Attempt to lookup while one running");
+
+ Json query = Json::object{
+ { "method", "list" },
+ { "parameters", Json::object{
+ { "zonename", target.toString() },
+ { "domain-id", domain_id },
+ { "include-disabled", include_disabled }
+ }}
+ };
+
+ if (this->send(query) == false || this->recv(d_result) == false)
+ return false;
+ if (d_result["result"].is_array() == false || d_result["result"].array_items().size() < 1)
+ return false;
+
+ d_index = 0;
+ return true;
+}
+
+bool RemoteBackend::get(DNSResourceRecord &rr) {
+ if (d_index == -1) return false;
+
+ rr.qtype = stringFromJson(d_result["result"][d_index], "qtype");
+ rr.qname = DNSName(stringFromJson(d_result["result"][d_index], "qname"));
+ rr.qclass = QClass::IN;
+ rr.content = stringFromJson(d_result["result"][d_index], "content");
+ rr.ttl = d_result["result"][d_index]["ttl"].int_value();
+ rr.domain_id = intFromJson(d_result["result"][d_index], "domain_id", -1);
+ if (d_dnssec)
+ rr.auth = intFromJson(d_result["result"][d_index], "auth", 1);
+ else
+ rr.auth = 1;
+ rr.scopeMask = d_result["result"][d_index]["scopeMask"].int_value();
+ d_index++;
+
+ // id index is out of bounds, we know the results end here.
+ if (d_index == static_cast<int>(d_result["result"].array_items().size())) {
+ d_result = Json();
+ d_index = -1;
+ }
+ return true;
+}
+
+bool RemoteBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const std::string& qname, DNSName& unhashed, std::string& before, std::string& after) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "getBeforeAndAfterNamesAbsolute" },
+ { "parameters", Json::object {
+ { "id", Json(static_cast<double>(id)) },
+ { "qname", qname }
+ }}
+ };
+ Json answer;
+
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ unhashed = DNSName(stringFromJson(answer["result"], "unhashed"));
+ before = "";
+ after = "";
+ if (answer["result"]["before"] != Json())
+ before = stringFromJson(answer["result"], "before");
+ if (answer["result"]["after"] != Json())
+ after = stringFromJson(answer["result"], "after");
+
+ return true;
+}
+
+bool RemoteBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) {
+ Json query = Json::object{
+ { "method", "getAllDomainMetadata" },
+ { "parameters", Json::object {
+ { "name", name.toString() }
+ }}
+ };
+
+ if (this->send(query) == false)
+ return false;
+
+ meta.clear();
+
+ Json answer;
+ // not mandatory to implement
+ if (this->recv(answer) == false)
+ return true;
+
+ for(const auto& pair: answer["result"].object_items()) {
+ if (pair.second.is_array()) {
+ for(const auto& val: pair.second.array_items())
+ meta[pair.first].push_back(asString(val));
+ } else {
+ meta[pair.first].push_back(asString(pair.second));
+ }
+ }
+
+ return true;
+}
+
+bool RemoteBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) {
+ Json query = Json::object{
+ { "method", "getDomainMetadata" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "kind", kind }
+ }}
+ };
+
+ if (this->send(query) == false)
+ return false;
+
+ meta.clear();
+
+ Json answer;
+ // not mandatory to implement
+ if (this->recv(answer) == false)
+ return true;
+
+ if (answer["result"].is_array()) {
+ for(const auto& row: answer["result"].array_items())
+ meta.push_back(row.string_value());
+ } else if (answer["result"].is_string()) {
+ meta.push_back(answer["result"].string_value());
+ }
+
+ return true;
+}
+
+bool RemoteBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) {
+ Json query = Json::object{
+ { "method", "setDomainMetadata" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "kind", kind },
+ { "value", meta }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return boolFromJson(answer, "result", false);
+}
+
+
+bool RemoteBackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "getDomainKeys" },
+ { "parameters", Json::object{
+ { "name", name.toString() },
+ { "kind", static_cast<int>(kind) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ keys.clear();
+
+ for(const auto& jsonKey: answer["result"].array_items()) {
+ DNSBackend::KeyData key;
+ key.id = intFromJson(jsonKey, "id");
+ key.flags = intFromJson(jsonKey, "flags");
+ key.active = asBool(jsonKey["active"]);
+ key.content = stringFromJson(jsonKey, "content");
+ keys.push_back(key);
+ }
+
+ return true;
+}
+
+bool RemoteBackend::removeDomainKey(const DNSName& name, unsigned int id) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "removeDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "id", static_cast<int>(id) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+int RemoteBackend::addDomainKey(const DNSName& name, const KeyData& key) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "addDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "key", Json::object {
+ { "flags", static_cast<int>(key.flags) },
+ { "active", key.active },
+ { "content", key.content }
+ }}
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return answer["result"].int_value();
+}
+
+bool RemoteBackend::activateDomainKey(const DNSName& name, unsigned int id) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "activateDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "id", static_cast<int>(id) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::deactivateDomainKey(const DNSName& name, unsigned int id) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "deactivateDomainKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "id", static_cast<int>(id) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::doesDNSSEC() {
+ return d_dnssec;
+}
+
+bool RemoteBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, std::string* content) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "getTSIGKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ (*algorithm) = DNSName(stringFromJson(answer["result"], "algorithm"));
+ (*content) = stringFromJson(answer["result"], "content");
+
+ return true;
+}
+
+bool RemoteBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const std::string& content) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+
+ Json query = Json::object{
+ { "method", "setTSIGKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "algorithm", algorithm.toString() },
+ { "content", content }
+ }}
+ };
+
+ Json answer;
+ if (connector->send(query) == false || connector->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::deleteTSIGKey(const DNSName& name) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+ Json query = Json::object{
+ { "method", "deleteTSIGKey" },
+ { "parameters", Json::object {
+ { "name", name.toString() }
+ }}
+ };
+
+ Json answer;
+ if (connector->send(query) == false || connector->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::getTSIGKeys(std::vector<struct TSIGKey>& keys) {
+ // no point doing dnssec if it's not supported
+ if (d_dnssec == false) return false;
+ Json query = Json::object{
+ { "method", "getTSIGKeys" },
+ { "parameters", Json::object {
+ }}
+ };
+
+ Json answer;
+ if (connector->send(query) == false || connector->recv(answer) == false)
+ return false;
+
+ for(const auto& jsonKey: answer["result"].array_items()) {
+ struct TSIGKey key;
+ key.name = DNSName(stringFromJson(jsonKey, "name"));
+ key.algorithm = DNSName(stringFromJson(jsonKey, "algorithm"));
+ key.key = stringFromJson(jsonKey, "content");
+ keys.push_back(key);
+ }
+
+ return true;
+}
+
+void RemoteBackend::parseDomainInfo(const Json &obj, DomainInfo &di)
+{
+ di.id = intFromJson(obj, "id", -1);
+ di.zone = DNSName(stringFromJson(obj, "zone"));
+ for(const auto& master: obj["masters"].array_items())
+ di.masters.push_back(master.string_value());
+
+ di.notified_serial = static_cast<unsigned int>(doubleFromJson(obj, "notified_serial", -1));
+ di.serial = static_cast<unsigned int>(obj["serial"].number_value());
+ di.last_check = static_cast<time_t>(obj["last_check"].number_value());
+
+ string kind = "";
+ if (obj["kind"].is_string()) {
+ kind = stringFromJson(obj, "kind");
+ }
+ if (kind == "master") {
+ di.kind = DomainInfo::Master;
+ } else if (kind == "slave") {
+ di.kind = DomainInfo::Slave;
+ } else {
+ di.kind = DomainInfo::Native;
+ }
+ di.backend = this;
+}
+
+bool RemoteBackend::getDomainInfo(const DNSName& domain, DomainInfo &di) {
+ if (domain.empty()) return false;
+ Json query = Json::object{
+ { "method", "getDomainInfo" },
+ { "parameters", Json::object {
+ { "name", domain.toString() }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ this->parseDomainInfo(answer["result"], di);
+ return true;
+}
+
+void RemoteBackend::setNotified(uint32_t id, uint32_t serial) {
+ Json query = Json::object{
+ { "method", "setNotified" },
+ { "parameters", Json::object {
+ { "id", static_cast<double>(id) },
+ { "serial", static_cast<double>(serial) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false) {
+ L<<Logger::Error<<kBackendId<<" Failed to execute RPC for RemoteBackend::setNotified("<<id<<","<<serial<<")"<<endl;
+ }
+}
+
+bool RemoteBackend::isMaster(const DNSName& name, const string &ip)
+{
+ Json query = Json::object{
+ { "method", "isMaster" },
+ { "parameters", Json::object {
+ { "name", name.toString() },
+ { "ip", ip }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::superMasterBackend(const string &ip, const DNSName& domain, const vector<DNSResourceRecord>&nsset, string* nameserver, string *account, DNSBackend **ddb)
+{
+ Json::array rrset;
+
+ for(const auto& ns: nsset) {
+ rrset.push_back(Json::object{
+ { "qtype", ns.qtype.getName() },
+ { "qname", ns.qname.toString() },
+ { "qclass", QClass::IN },
+ { "content", ns.content },
+ { "ttl", static_cast<int>(ns.ttl) },
+ { "auth", ns.auth }
+ });
+ }
+
+ Json query = Json::object{
+ { "method", "superMasterBackend" },
+ { "parameters", Json::object {
+ { "ip", ip },
+ { "domain", domain.toString() },
+ { "nsset", rrset }
+ }}
+ };
+
+ *ddb = 0;
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ // we are the backend
+ *ddb = this;
+
+ // we allow simple true as well...
+ if (answer["result"].is_object()) {
+ *account = stringFromJson(answer["result"], "account");
+ *nameserver = stringFromJson(answer["result"], "nameserver");
+ }
+
+ return true;
+}
+
+bool RemoteBackend::createSlaveDomain(const string &ip, const DNSName& domain, const string& nameserver, const string &account) {
+ Json query = Json::object{
+ { "method", "createSlaveDomain" },
+ { "parameters", Json::object {
+ { "ip", ip },
+ { "domain", domain.toString() },
+ { "nameserver", nameserver },
+ { "account", account },
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+}
+
+bool RemoteBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qtype, const vector<DNSResourceRecord>& rrset) {
+ Json::array json_rrset;
+ for(const auto& rr: rrset) {
+ json_rrset.push_back(Json::object{
+ { "qtype", rr.qtype.getName() },
+ { "qname", rr.qname.toString() },
+ { "qclass", QClass::IN },
+ { "content", rr.content },
+ { "ttl", static_cast<int>(rr.ttl) },
+ { "auth", rr.auth }
+ });
+ }
+
+ Json query = Json::object{
+ { "method", "replaceRRSet" },
+ { "parameters", Json::object {
+ { "domain_id", static_cast<double>(domain_id) },
+ { "qname", qname.toString() },
+ { "qtype", qtype.getName() },
+ { "trxid", static_cast<double>(d_trxid) },
+ { "rrset", json_rrset }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ return true;
+}
+
+bool RemoteBackend::feedRecord(const DNSResourceRecord &rr, string *ordername) {
+ Json query = Json::object{
+ { "method", "feedRecord" },
+ { "parameters", Json::object{
+ { "rr", Json::object{
+ { "qtype", rr.qtype.getName() },
+ { "qname", rr.qname.toString() },
+ { "qclass", QClass::IN },
+ { "content", rr.content },
+ { "ttl", static_cast<int>(rr.ttl) },
+ { "auth", rr.auth },
+ { "ordername", (ordername==nullptr?Json():*ordername) }
+ }},
+ { "trxid", static_cast<double>(d_trxid) },
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true; // XXX FIXME this API should not return 'true' I think -ahu
+}
+
+bool RemoteBackend::feedEnts(int domain_id, map<DNSName,bool>& nonterm) {
+ Json::array nts;
+
+ for(const auto& t: nonterm)
+ nts.push_back(Json::object{
+ { "nonterm", t.first.toString() },
+ { "auth", t.second }
+ });
+
+ Json query = Json::object{
+ { "method", "feedEnts" },
+ { "parameters", Json::object{
+ { "domain_id", domain_id },
+ { "trxid", static_cast<double>(d_trxid) },
+ { "nonterm", nts }
+ }},
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+}
+
+bool RemoteBackend::feedEnts3(int domain_id, const DNSName& domain, map<DNSName,bool>& nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow) {
+ Json::array nts;
+
+ for(const auto& t: nonterm)
+ nts.push_back(Json::object{
+ { "nonterm", t.first.toString() },
+ { "auth", t.second }
+ });
+
+ Json query = Json::object{
+ { "method", "feedEnts3" },
+ { "parameters", Json::object{
+ { "domain_id", domain_id },
+ { "domain", domain.toString() },
+ { "times", ns3prc.d_iterations },
+ { "salt", ns3prc.d_salt },
+ { "narrow", narrow },
+ { "trxid", static_cast<double>(d_trxid) },
+ { "nonterm", nts }
+ }},
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+}
+
+bool RemoteBackend::startTransaction(const DNSName& domain, int domain_id) {
+ this->d_trxid = time((time_t*)NULL);
+
+ Json query = Json::object{
+ { "method", "startTransaction" },
+ { "parameters", Json::object{
+ { "domain", domain.toString() },
+ { "domain_id", domain_id },
+ { "trxid", static_cast<double>(d_trxid) }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false) {
+ d_trxid = -1;
+ return false;
+ }
+ return true;
+
+}
+bool RemoteBackend::commitTransaction() {
+ if (d_trxid == -1) return false;
+
+ Json query = Json::object{
+ { "method", "commitTransaction" },
+ { "parameters", Json::object{
+ { "trxid", static_cast<double>(d_trxid) }
+ }}
+ };
+
+ d_trxid = -1;
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+}
+
+bool RemoteBackend::abortTransaction() {
+ if (d_trxid == -1) return false;
+
+ Json query = Json::object{
+ { "method", "abortTransaction" },
+ { "parameters", Json::object{
+ { "trxid", static_cast<double>(d_trxid) }
+ }}
+ };
+
+ d_trxid = -1;
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+ return true;
+}
+
+bool RemoteBackend::calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial) {
+ Json query = Json::object{
+ { "method", "calculateSOASerial" },
+ { "parameters", Json::object{
+ { "domain", domain.toString() },
+ { "sd", Json::object{
+ { "qname", sd.qname.toString() },
+ { "nameserver", sd.nameserver.toString() },
+ { "hostmaster", sd.hostmaster.toString() },
+ { "ttl", static_cast<int>(sd.ttl) },
+ { "serial", static_cast<double>(sd.serial) },
+ { "refresh", static_cast<int>(sd.refresh) },
+ { "retry", static_cast<int>(sd.retry) },
+ { "expire", static_cast<int>(sd.expire) },
+ { "default_ttl", static_cast<int>(sd.default_ttl) },
+ { "domain_id", static_cast<int>(sd.domain_id) },
+ { "scopeMask", sd.scopeMask }
+ }}
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ serial = static_cast<unsigned int>(doubleFromJson(answer,"result"));
+ return true;
+}
+
+string RemoteBackend::directBackendCmd(const string& querystr) {
+ Json query = Json::object{
+ { "method", "directBackendCmd" },
+ { "parameters", Json::object{
+ { "query", querystr }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return "backend command failed";
+
+ return asString(answer["result"]);
+}
+
+bool RemoteBackend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
+{
+ Json query = Json::object{
+ { "method", "searchRecords" },
+ { "parameters", Json::object{
+ { "pattern", pattern },
+ { "maxResults", maxResults }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return false;
+
+ if (answer["result"].is_array() == false)
+ return false;
+
+ for(const auto& row: answer["result"].array_items()) {
+ DNSResourceRecord rr;
+ rr.qtype = stringFromJson(row, "qtype");
+ rr.qname = DNSName(stringFromJson(row, "qname"));
+ rr.qclass = QClass::IN;
+ rr.content = stringFromJson(row, "content");
+ rr.ttl = row["ttl"].int_value();
+ rr.domain_id = intFromJson(row, "domain_id", -1);
+ if (d_dnssec)
+ rr.auth = intFromJson(row, "auth", 1);
+ else
+ rr.auth = 1;
+ rr.scopeMask = row["scopeMask"].int_value();
+ result.push_back(rr);
+ }
+
+ return true;
+}
+
+bool RemoteBackend::searchComments(const string &pattern, int maxResults, vector<Comment>& result)
+{
+ // FIXME: Implement Comment API
+ return false;
+}
+
+void RemoteBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
+{
+ Json query = Json::object{
+ { "method", "getAllDomains" },
+ { "parameters", Json::object{
+ { "include_disabled", include_disabled }
+ }}
+ };
+
+ Json answer;
+ if (this->send(query) == false || this->recv(answer) == false)
+ return;
+
+ if (answer["result"].is_array() == false)
+ return;
+
+ for(const auto& row: answer["result"].array_items()) {
+ DomainInfo di;
+ this->parseDomainInfo(row, di);
+ domains->push_back(di);
+ }
+}
+
+DNSBackend *RemoteBackend::maker()
+{
+ try {
+ return new RemoteBackend();
+ }
+ catch(...) {
+ L<<Logger::Error<<kBackendId<<" Unable to instantiate a remotebackend!"<<endl;
+ return 0;
+ };
+}
+
+
+
+class RemoteBackendFactory : public BackendFactory
+{
+ public:
+ RemoteBackendFactory() : BackendFactory("remote") {}
+
+ void declareArguments(const std::string &suffix="")
+ {
+ declare(suffix,"dnssec","Enable dnssec support","no");
+ declare(suffix,"connection-string","Connection string","");
+ }
+
+ DNSBackend *make(const std::string &suffix="")
+ {
+ return new RemoteBackend(suffix);
+ }
+};
+
+class RemoteLoader
+{
+public:
+ RemoteLoader();
+};
+
+
+RemoteLoader::RemoteLoader() {
+ BackendMakers().report(new RemoteBackendFactory);
+ L << Logger::Info << kBackendId << " This is the remote backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+}
+
+static RemoteLoader remoteloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef REMOTEBACKEND_REMOTEBACKEND_HH
+
+#include <sys/types.h>
+#include <sys/wait.h>
+
+#include <string>
+#include "pdns/arguments.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/logger.hh"
+#include "pdns/namespaces.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/sstuff.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/json.hh"
+#include "pdns/lock.hh"
+#include "yahttp/yahttp.hpp"
+
+#ifdef REMOTEBACKEND_ZEROMQ
+#include <zmq.h>
+
+// If the available ZeroMQ library version is < 2.x, create macros for the zmq_msg_send/recv functions
+#ifndef HAVE_ZMQ_MSG_SEND
+#define zmq_msg_send(msg, socket, flags) zmq_send(socket, msg, flags)
+#define zmq_msg_recv(msg, socket, flags) zmq_recv(socket, msg, flags)
+#endif
+#endif
+
+using json11::Json;
+
+class Connector {
+ public:
+ virtual ~Connector() {};
+ bool send(Json &value);
+ bool recv(Json &value);
+ virtual int send_message(const Json &input) = 0;
+ virtual int recv_message(Json &output) = 0;
+ protected:
+ string asString(const Json& value) {
+ if (value.is_number()) return std::to_string(value.int_value());
+ if (value.is_bool()) return (value.bool_value()?"1":"0");
+ if (value.is_string()) return value.string_value();
+ throw JsonException("Json value not convertible to String");
+ };
+};
+
+// fwd declarations
+class UnixsocketConnector: public Connector {
+ public:
+ UnixsocketConnector(std::map<std::string,std::string> options);
+ virtual ~UnixsocketConnector();
+ virtual int send_message(const Json &input);
+ virtual int recv_message(Json &output);
+ private:
+ ssize_t read(std::string &data);
+ ssize_t write(const std::string &data);
+ void reconnect();
+ std::map<std::string,std::string> options;
+ int fd;
+ std::string path;
+ bool connected;
+ int timeout;
+};
+
+class HTTPConnector: public Connector {
+ public:
+
+ HTTPConnector(std::map<std::string,std::string> options);
+ ~HTTPConnector();
+
+ virtual int send_message(const Json &input);
+ virtual int recv_message(Json &output);
+ private:
+ std::string d_url;
+ std::string d_url_suffix;
+ std::string d_data;
+ int timeout;
+ bool d_post;
+ bool d_post_json;
+ void restful_requestbuilder(const std::string &method, const Json ¶meters, YaHTTP::Request& req);
+ void post_requestbuilder(const Json &input, YaHTTP::Request& req);
+ void addUrlComponent(const Json ¶meters, const string& element, std::stringstream& ss);
+ std::string buildMemberListArgs(std::string prefix, const Json& args);
+ Socket* d_socket;
+ ComboAddress d_addr;
+};
+
+#ifdef REMOTEBACKEND_ZEROMQ
+class ZeroMQConnector: public Connector {
+ public:
+ ZeroMQConnector(std::map<std::string,std::string> options);
+ virtual ~ZeroMQConnector();
+ virtual int send_message(const Json &input);
+ virtual int recv_message(Json &output);
+ private:
+ void connect();
+ std::string d_endpoint;
+ int d_timeout;
+ int d_timespent;
+ std::map<std::string,std::string> d_options;
+ void *d_ctx;
+ void *d_sock;
+};
+#endif
+
+class PipeConnector: public Connector {
+ public:
+
+ PipeConnector(std::map<std::string,std::string> options);
+ ~PipeConnector();
+
+ virtual int send_message(const Json &input);
+ virtual int recv_message(Json &output);
+
+ private:
+
+ void launch();
+ bool checkStatus();
+
+ std::string command;
+ std::map<std::string,std::string> options;
+
+ int d_fd1[2], d_fd2[2];
+ int d_pid;
+ int d_timeout;
+ FILE *d_fp;
+};
+
+class RemoteBackend : public DNSBackend
+{
+ public:
+ RemoteBackend(const std::string &suffix="");
+ ~RemoteBackend();
+
+ void lookup(const QType &qtype, const DNSName& qdomain, DNSPacket *pkt_p=0, int zoneId=-1);
+ bool get(DNSResourceRecord &rr);
+ bool list(const DNSName& target, int domain_id, bool include_disabled=false);
+
+ virtual bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ virtual bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys);
+ virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, std::string* content);
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, string& before, string& after);
+ virtual bool setDomainMetadata(const DNSName& name, const string& kind, const std::vector<std::basic_string<char> >& meta);
+ virtual bool removeDomainKey(const DNSName& name, unsigned int id);
+ virtual int addDomainKey(const DNSName& name, const KeyData& key);
+ virtual bool activateDomainKey(const DNSName& name, unsigned int id);
+ virtual bool deactivateDomainKey(const DNSName& name, unsigned int id);
+ virtual bool getDomainInfo(const DNSName& domain, DomainInfo& di);
+ virtual void setNotified(uint32_t id, uint32_t serial);
+ virtual bool doesDNSSEC();
+ virtual bool isMaster(const DNSName& name, const string &ip);
+ virtual bool superMasterBackend(const string &ip, const DNSName& domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **ddb);
+ virtual bool createSlaveDomain(const string &ip, const DNSName& domain, const string& nameserver, const string &account);
+ virtual bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset);
+ virtual bool feedRecord(const DNSResourceRecord &r, string *ordername);
+ virtual bool feedEnts(int domain_id, map<DNSName,bool>& nonterm);
+ virtual bool feedEnts3(int domain_id, const DNSName& domain, map<DNSName,bool>& nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow);
+ virtual bool startTransaction(const DNSName& domain, int domain_id);
+ virtual bool commitTransaction();
+ virtual bool abortTransaction();
+ virtual bool calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial);
+ virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
+ virtual bool deleteTSIGKey(const DNSName& name);
+ virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys);
+ virtual string directBackendCmd(const string& querystr);
+ virtual bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
+ virtual bool searchComments(const string &pattern, int maxResults, vector<Comment>& result);
+ virtual void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false);
+
+ static DNSBackend *maker();
+
+ private:
+ int build();
+ Connector *connector;
+ bool d_dnssec;
+ Json d_result;
+ int d_index;
+ int64_t d_trxid;
+ std::string d_connstr;
+
+ bool send(Json &value);
+ bool recv(Json &value);
+
+ string asString(const Json& value) {
+ if (value.is_number()) return std::to_string(value.int_value());
+ if (value.is_bool()) return (value.bool_value()?"1":"0");
+ if (value.is_string()) return value.string_value();
+ throw JsonException("Json value not convertible to String");
+ };
+
+ bool asBool(const Json& value) {
+ if (value.is_bool()) return value.bool_value();
+ try {
+ string val = asString(value);
+ if (val == "0") return false;
+ if (val == "1") return true;
+ } catch (JsonException) {};
+ throw JsonException("Json value not convertible to boolean");
+ };
+
+ void parseDomainInfo(const json11::Json &obj, DomainInfo &di);
+};
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="http:url=http://localhost:62434/dns";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="http:url=http://localhost:62434/dns/endpoint.json,post=1,post_json=1";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+DNSBackend::KeyData k1 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: qpe9fxlN4dBT38cLPWtqljZhcJjbqRprj9XsYmf2/uFu4kA5sHYrlQY7H9lpzGJPRfOAfxShBpKs1AVaVInfJQ==\nPublicExponent: AQAB\nPrivateExponent: Ad3YogzXvVDLsWuAfioY571QlolbdTbzVlhLEMLD6dSRx+xcZgw6c27ak2HAH00iSKTvqK3AyeaK8Eqy/oJ5QQ==\nPrime1: wo8LZrdU2y0xLGCeLhwziQDDtTMi18NEIwlx8tUPnhs=\nPrime2: 4HcuFqgo7NOiXFvN+V2PT+QaIt2+oi6D2m8/qtTDS78=\nExponent1: GUdCoPbi9JM7l1t6Ud1iKMPLqchaF5SMTs0UXAuous8=\nExponent2: nzgKqimX9f1corTAEw0pddrwKyEtcu8ZuhzFhZCsAxM=\nCoefficient: YGNxbulf5GTNiIu0oNKmAF0khNtx9layjOPEI0R4/RY="), 1, 257, true };
+
+DNSBackend::KeyData k2 = {std::string("Private-key-format: v1.2\nAlgorithm: 5 (RSASHA1)\nModulus: tY2TAMgL/whZdSbn2aci4wcMqohO24KQAaq5RlTRwQ33M8FYdW5fZ3DMdMsSLQUkjGnKJPKEdN3Qd4Z5b18f+w==\nPublicExponent: AQAB\nPrivateExponent: BB6xibPNPrBV0PUp3CQq0OdFpk9v9EZ2NiBFrA7osG5mGIZICqgOx/zlHiHKmX4OLmL28oU7jPKgogeuONXJQQ==\nPrime1: yjxe/iHQ4IBWpvCmuGqhxApWF+DY9LADIP7bM3Ejf3M=\nPrime2: 5dGWTyYEQRBVK74q1a64iXgaNuYm1pbClvvZ6ccCq1k=\nExponent1: TwM5RebmWeAqerzJFoIqw5IaQugJO8hM4KZR9A4/BTs=\nExponent2: bpV2HSmu3Fvuj7jWxbFoDIXlH0uJnrI2eg4/4hSnvSk=\nCoefficient: e2uDDWN2zXwYa2P6VQBWQ4mR1ZZjFEtO/+YqOJZun1Y="), 2, 256, true };
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnsrecords.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="pipe:command=unittest_pipe.rb";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ // load few record types to help out
+ SOARecordContent::report();
+ NSRecordContent::report();
+ ARecordContent::report();
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="http:url=http://localhost:62434/dns,post=1";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnsrecords.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="unix:path=/tmp/remotebackend.sock";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ // load few record types to help out
+ SOARecordContent::report();
+ NSRecordContent::report();
+ ARecordContent::report();
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/dnsrecords.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+StatBag S;
+PacketCache PC;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+};
+
+class RemoteLoader
+{
+ public:
+ RemoteLoader();
+};
+
+DNSBackend *be;
+
+#ifdef REMOTEBACKEND_ZEROMQ
+#include <boost/test/unit_test.hpp>
+
+struct RemotebackendSetup {
+ RemotebackendSetup() {
+ be = 0;
+ try {
+ // setup minimum arguments
+ ::arg().set("module-dir")="./.libs";
+ new RemoteLoader();
+ BackendMakers().launch("remote");
+ // then get us a instance of it
+ ::arg().set("remote-connection-string")="zeromq:endpoint=ipc:///tmp/remotebackend.0";
+ ::arg().set("remote-dnssec")="yes";
+ be = BackendMakers().all()[0];
+ // load few record types to help out
+ SOARecordContent::report();
+ NSRecordContent::report();
+ ARecordContent::report();
+ } catch (PDNSException &ex) {
+ BOOST_TEST_MESSAGE("Cannot start remotebackend: " << ex.reason );
+ };
+ }
+ ~RemotebackendSetup() { }
+};
+
+BOOST_GLOBAL_FIXTURE( RemotebackendSetup );
+
+#else
+
+#include <iostream>
+
+int main(void) {
+ std::cout << "No HTTP support in remotebackend - skipping test" << std::endl;
+ return 0;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "pdns/namespaces.hh"
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/json.hh"
+#include "pdns/statbag.hh"
+#include "pdns/packetcache.hh"
+
+#include "test-remotebackend-keys.hh"
+
+extern DNSBackend *be;
+
+BOOST_AUTO_TEST_SUITE(test_remotebackend_so)
+
+BOOST_AUTO_TEST_CASE(test_method_lookup) {
+ BOOST_TEST_MESSAGE("Testing lookup method");
+ DNSResourceRecord rr;
+ be->lookup(QType(QType::SOA), DNSName("unit.test."));
+ // then try to get()
+ BOOST_CHECK(be->get(rr)); // and this should be TRUE.
+ // then we check rr contains what we expect
+ BOOST_CHECK_EQUAL(rr.qname.toString(), "unit.test.");
+ BOOST_CHECK_MESSAGE(rr.qtype == QType::SOA, "returned qtype was not SOA");
+ BOOST_CHECK_EQUAL(rr.content, "ns.unit.test. hostmaster.unit.test. 1 2 3 4 5 6");
+ BOOST_CHECK_EQUAL(rr.ttl, 300);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_lookup_empty) {
+ BOOST_TEST_MESSAGE("Testing lookup method with empty result");
+ DNSResourceRecord rr;
+ be->lookup(QType(QType::SOA), DNSName("empty.unit.test."));
+ // then try to get()
+ BOOST_CHECK(!be->get(rr)); // and this should be FALSE
+}
+
+BOOST_AUTO_TEST_CASE(test_method_list) {
+ int record_count = 0;
+ DNSResourceRecord rr;
+
+ BOOST_TEST_MESSAGE("Testing list method");
+ be->list(DNSName("unit.test."), -1);
+ while(be->get(rr)) record_count++;
+
+ BOOST_CHECK_EQUAL(record_count, 5); // number of records our test domain has
+}
+
+BOOST_AUTO_TEST_CASE(test_method_doesDNSSEC) {
+ BOOST_TEST_MESSAGE("Testing doesDNSSEC method");
+ BOOST_CHECK(be->doesDNSSEC()); // should be true
+}
+
+BOOST_AUTO_TEST_CASE(test_method_setDomainMetadata) {
+ std::vector<std::string> meta;
+ meta.push_back("VALUE");
+ BOOST_TEST_MESSAGE("Testing setDomainMetadata method");
+ BOOST_CHECK(be->setDomainMetadata(DNSName("unit.test."),"TEST", meta));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getDomainMetadata) {
+ std::vector<std::string> meta;
+ BOOST_TEST_MESSAGE("Testing getDomainMetadata method");
+ be->getDomainMetadata(DNSName("unit.test."),"TEST", meta);
+ BOOST_CHECK_EQUAL(meta.size(), 1);
+ // in case we got more than one value, which would be unexpected
+ // but not fatal
+ if (meta.size() > 0)
+ BOOST_CHECK_EQUAL(meta[0], "VALUE");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getAllDomainMetadata) {
+ std::map<std::string, std::vector<std::string> > meta;
+ BOOST_TEST_MESSAGE("Testing getAllDomainMetadata method");
+ be->getAllDomainMetadata(DNSName("unit.test."), meta);
+ BOOST_CHECK_EQUAL(meta.size(), 1);
+ // in case we got more than one value, which would be unexpected
+ // but not fatal
+ if (meta.size() > 0)
+ BOOST_CHECK_EQUAL(meta["TEST"][0], "VALUE");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_addDomainKey) {
+ BOOST_TEST_MESSAGE("Testing addDomainKey method");
+ BOOST_CHECK_EQUAL(be->addDomainKey(DNSName("unit.test."),k1), 1);
+ BOOST_CHECK_EQUAL(be->addDomainKey(DNSName("unit.test."),k2), 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getDomainKeys) {
+ std::vector<DNSBackend::KeyData> keys;
+ BOOST_TEST_MESSAGE("Testing getDomainKeys method");
+ // we expect to get two keys
+ be->getDomainKeys(DNSName("unit.test."),0,keys);
+ BOOST_CHECK_EQUAL(keys.size(), 2);
+ // in case we got more than 2 keys, which would be unexpected
+ // but not fatal
+ if (keys.size() > 1) {
+ // check that we have two keys
+ for(DNSBackend::KeyData &kd : keys) {
+ BOOST_CHECK(kd.id > 0);
+ BOOST_CHECK(kd.flags == 256 || kd.flags == 257);
+ BOOST_CHECK(kd.active == true);
+ BOOST_CHECK(kd.content.size() > 500);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_method_deactivateDomainKey) {
+ BOOST_TEST_MESSAGE("Testing deactivateDomainKey method");
+ BOOST_CHECK(be->deactivateDomainKey(DNSName("unit.test."),1));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_activateDomainKey) {
+ BOOST_TEST_MESSAGE("Testing activateDomainKey method");
+ BOOST_CHECK(be->activateDomainKey(DNSName("unit.test."),1));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_removeDomainKey) {
+ BOOST_CHECK(be->removeDomainKey(DNSName("unit.test."),2));
+ BOOST_CHECK(be->removeDomainKey(DNSName("unit.test."),1));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getBeforeAndAfterNamesAbsolute) {
+ DNSName unhashed;
+ std::string before,after;
+ BOOST_TEST_MESSAGE("Testing getBeforeAndAfterNamesAbsolute method");
+
+ be->getBeforeAndAfterNamesAbsolute(-1, "middle.unit.test.", unhashed, before, after);
+ BOOST_CHECK_EQUAL(unhashed.toString(), "middle.");
+ BOOST_CHECK_EQUAL(before, "begin.");
+ BOOST_CHECK_EQUAL(after, "stop.");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_setTSIGKey) {
+ std::string algorithm, content;
+ BOOST_TEST_MESSAGE("Testing setTSIGKey method");
+ BOOST_CHECK_MESSAGE(be->setTSIGKey(DNSName("unit.test."),DNSName("hmac-md5."),"kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys="), "did not return true");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getTSIGKey) {
+ DNSName algorithm;
+ std::string content;
+ BOOST_TEST_MESSAGE("Testing getTSIGKey method");
+ be->getTSIGKey(DNSName("unit.test."),&algorithm,&content);
+ BOOST_CHECK_EQUAL(algorithm.toString(), "hmac-md5.");
+ BOOST_CHECK_EQUAL(content, "kp4/24gyYsEzbuTVJRUMoqGFmN3LYgVDzJ/3oRSP7ys=");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_deleteTSIGKey) {
+ std::string algorithm, content;
+ BOOST_TEST_MESSAGE("Testing deleteTSIGKey method");
+ BOOST_CHECK_MESSAGE(be->deleteTSIGKey(DNSName("unit.test.")), "did not return true");
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getTSIGKeys) {
+ std::vector<struct TSIGKey> keys;
+ BOOST_TEST_MESSAGE("Testing getTSIGKeys method");
+ be->getTSIGKeys(keys);
+ BOOST_CHECK(keys.size() > 0);
+ if (keys.size() > 0) {
+ BOOST_CHECK_EQUAL(keys[0].name.toString(), "test.");
+ BOOST_CHECK_EQUAL(keys[0].algorithm.toString(), "NULL.");
+ BOOST_CHECK_EQUAL(keys[0].key, "NULL");
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_method_setNotified) {
+ BOOST_TEST_MESSAGE("Testing setNotified method");
+ be->setNotified(1, 2);
+ BOOST_CHECK(true); // we check this on next step
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getDomainInfo) {
+ DomainInfo di;
+ BOOST_TEST_MESSAGE("Testing getDomainInfo method");
+ be->getDomainInfo(DNSName("unit.test."), di);
+ BOOST_CHECK_EQUAL(di.zone.toString(), "unit.test.");
+ BOOST_CHECK_EQUAL(di.serial, 2);
+ BOOST_CHECK_EQUAL(di.notified_serial, 2);
+ BOOST_CHECK_EQUAL(di.kind, DomainInfo::Native);
+ BOOST_CHECK_EQUAL(di.backend, be);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_getAllDomains) {
+ DomainInfo di;
+ BOOST_TEST_MESSAGE("Testing getAllDomains method");
+ vector<DomainInfo> result;
+
+ be->getAllDomains(&result, true);
+
+ di = result[0];
+ BOOST_CHECK_EQUAL(di.zone.toString(), "unit.test.");
+ BOOST_CHECK_EQUAL(di.serial, 2);
+ BOOST_CHECK_EQUAL(di.notified_serial, 2);
+ BOOST_CHECK_EQUAL(di.kind, DomainInfo::Native);
+ BOOST_CHECK_EQUAL(di.backend, be);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_isMaster) {
+ BOOST_TEST_MESSAGE("Testing isMaster method");
+ BOOST_CHECK(be->isMaster(DNSName("ns1.unit.test."), "10.0.0.1"));
+ BOOST_CHECK(!be->isMaster(DNSName("ns2.unit.test."), "10.0.0.2"));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_superMasterBackend) {
+ DNSResourceRecord rr;
+ std::vector<DNSResourceRecord> nsset;
+ DNSBackend *dbd;
+ BOOST_TEST_MESSAGE("Testing superMasterBackend method");
+
+ rr.qname = DNSName("example.com.");
+ rr.qtype = QType::NS;
+ rr.qclass = QClass::IN;
+ rr.ttl = 300;
+ rr.content = "ns1.example.com.";
+ nsset.push_back(rr);
+ rr.qname = DNSName("example.com.");
+ rr.qtype = QType::NS;
+ rr.qclass = QClass::IN;
+ rr.ttl = 300;
+ rr.content = "ns2.example.com.";
+ nsset.push_back(rr);
+
+ BOOST_CHECK(be->superMasterBackend("10.0.0.1", DNSName("example.com."), nsset, NULL, NULL, &dbd));
+
+ // let's see what we got
+ BOOST_CHECK_EQUAL(dbd, be);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_createSlaveDomain) {
+ BOOST_TEST_MESSAGE("Testing createSlaveDomain method");
+ BOOST_CHECK(be->createSlaveDomain("10.0.0.1", DNSName("pirate.unit.test."), "", ""));
+}
+
+BOOST_AUTO_TEST_CASE(test_method_feedRecord) {
+ DNSResourceRecord rr;
+ BOOST_TEST_MESSAGE("Testing feedRecord method");
+ be->startTransaction(DNSName("example.com."),2);
+ rr.qname = DNSName("example.com.");
+ rr.qtype = QType::SOA;
+ rr.qclass = QClass::IN;
+ rr.ttl = 300;
+ rr.content = "ns1.example.com. hostmaster.example.com. 2013013441 7200 3600 1209600 300";
+ BOOST_CHECK(be->feedRecord(rr, NULL));
+ rr.qname = DNSName("replace.example.com.");
+ rr.qtype = QType::A;
+ rr.qclass = QClass::IN;
+ rr.ttl = 300;
+ rr.content = "127.0.0.1";
+ BOOST_CHECK(be->feedRecord(rr, NULL));
+ be->commitTransaction();
+}
+
+BOOST_AUTO_TEST_CASE(test_method_replaceRRSet) {
+ be->startTransaction(DNSName("example.com."),2);
+ DNSResourceRecord rr;
+ std::vector<DNSResourceRecord> rrset;
+ BOOST_TEST_MESSAGE("Testing replaceRRSet method");
+ rr.qname = DNSName("replace.example.com.");
+ rr.qtype = QType::A;
+ rr.qclass = QClass::IN;
+ rr.ttl = 300;
+ rr.content = "1.1.1.1";
+ rrset.push_back(rr);
+ BOOST_CHECK(be->replaceRRSet(2, DNSName("replace.example.com."), QType(QType::A), rrset));
+ be->commitTransaction();
+}
+
+BOOST_AUTO_TEST_CASE(test_method_feedEnts) {
+ BOOST_TEST_MESSAGE("Testing feedEnts method");
+ be->startTransaction(DNSName("example.com."),2);
+ map<DNSName, bool> nonterm = boost::assign::map_list_of(DNSName("_udp"), true)(DNSName("_sip._udp"), true);
+ BOOST_CHECK(be->feedEnts(2, nonterm));
+ be->commitTransaction();
+}
+
+BOOST_AUTO_TEST_CASE(test_method_feedEnts3) {
+ BOOST_TEST_MESSAGE("Testing feedEnts3 method");
+ be->startTransaction(DNSName("example.com"),2);
+ NSEC3PARAMRecordContent ns3prc;
+ ns3prc.d_iterations=1;
+ ns3prc.d_salt="\u00aa\u00bb\u00cc\u00dd";
+ map<DNSName, bool> nonterm = boost::assign::map_list_of(DNSName("_udp"), true)(DNSName("_sip._udp"), true);
+ BOOST_CHECK(be->feedEnts3(2, DNSName("example.com."), nonterm, ns3prc, 0));
+ be->commitTransaction();
+}
+
+BOOST_AUTO_TEST_CASE(test_method_abortTransaction) {
+ BOOST_TEST_MESSAGE("Testing abortTransaction method");
+ be->startTransaction(DNSName("example.com."),2);
+ BOOST_CHECK(be->abortTransaction());
+}
+
+BOOST_AUTO_TEST_CASE(test_method_calculateSOASerial) {
+ SOAData sd;
+ time_t serial;
+
+ be->getSOA(DNSName("unit.test."),sd);
+ BOOST_CHECK(be->calculateSOASerial(DNSName("unit.test."),sd,serial));
+
+ BOOST_CHECK_EQUAL(serial, 2013060300);
+}
+
+BOOST_AUTO_TEST_CASE(test_method_directBackendCmd) {
+ BOOST_TEST_MESSAGE("Testing directBackendCmd method");
+ BOOST_CHECK_EQUAL(be->directBackendCmd("PING 1234"), "PING 1234");
+}
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#!/usr/bin/env bash
+new_api=0
+mode=$1
+
+# keep the original arguments for new test harness api
+orig="$*"
+
+# we could be ran with new API
+while [ "$1" != "" ]
+do
+ if [ "$1" == "--" ]; then
+ new_api=1
+ mode=$2
+ break
+ fi
+ shift
+done
+
+webrick_pid=""
+socat_pid=""
+zeromq_pid=""
+socat=$(which socat)
+
+function start_web() {
+ local service_logfile="${mode%\.test}_server.log"
+
+ ./unittest_${1}.rb >> ${service_logfile} 2>&1 &
+ webrick_pid=$!
+
+ local timeout=0
+ while [ ${timeout} -lt 20 ]; do
+ local res=$(curl http://localhost:62434/ping 2>/dev/null)
+ if [ "x$res" == "xpong" ]; then
+ # server is up and running
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${webrick_pid} 2>/dev/null; then
+ # if something is wrong with curl (i.e. curl isn't installed, localhost is firewalled ...)
+ # the status check will fail -- cleanup required!
+ echo >&2 "WARNING: Timeout (${timeout}s) reached: \"${1}\" test service process is running but status check failed"
+ kill -KILL ${webrick_pid} 2>/dev/null
+ fi
+
+ echo >&2 "ERROR: A timeout (${timeout}s) was reached while waiting for \"${1}\" test service to start!"
+ echo >&2 " See \"modules/remotebackend/${service_logfile}\" for more details."
+ exit 69
+}
+
+function stop_web() {
+ if [ -z "${webrick_pid}" ]; then
+ # should never happen - why was stop_web() called?
+ echo >&2 "ERROR: Unable to stop \"${1}\" test service: Did we ever start the service?"
+ exit 99
+ fi
+
+ if ! kill -0 ${webrick_pid} 2>/dev/null; then
+ # should never happen - did the test crashed the service?
+ echo >&2 "ERROR: Unable to stop \"${1}\" test service: service (${webrick_pid}) not running"
+ exit 69
+ fi
+
+ kill -TERM ${webrick_pid}
+ local timeout=0
+ while [ ${timeout} -lt 5 ]; do
+ if ! kill -0 ${webrick_pid} 2>/dev/null; then
+ # service was stopped
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${webrick_pid} 2>/dev/null; then
+ echo >&2 "WARNING: Timeout (${timeout}s) reached - killing \"${1}\" test service ..."
+ kill -KILL ${webrick_pid} 2>/dev/null
+ return $?
+ fi
+}
+
+function start_zeromq() {
+ if [ x"$REMOTEBACKEND_ZEROMQ" != "xyes" ]; then
+ echo "INFO: Skipping \"ZeroMQ\" test because PowerDNS was built without \"--enable-remotebackend-zeromq\"!"
+ exit 77
+ fi
+
+ local service_logfile="${mode%\.test}_server.log"
+
+ ./unittest_zeromq.rb >> ${service_logfile} 2>&1 &
+ zeromq_pid=$!
+
+ local timeout=0
+ while [ ${timeout} -lt 5 ]; do
+ if [ -S "/tmp/remotebackend.0" ]; then
+ # service is up and running
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${zeromq_pid} 2>/dev/null; then
+ # not sure when this can happen but we should cleanup any process we started
+ echo >&2 "WARNING: Timeout (${timeout}s) reached: \"ZeroMQ\" test service process is running but status check failed"
+ kill -KILL ${zeromq_pid} 2>/dev/null
+ fi
+
+ echo >&2 "ERROR: A timeout (${timeout}s) was reached while waiting for \"ZeroMQ\" test service to start!"
+ echo >&2 " See \"modules/remotebackend/${service_logfile}\" for more details."
+ exit 69
+}
+
+function stop_zeromq() {
+ if [ -z "${zeromq_pid}" ]; then
+ # should never happen - why was stop_zeromq() called?
+ echo >&2 "ERROR: Unable to stop \"ZeroMQ\" test service: Did we ever start the service?"
+ exit 99
+ fi
+
+ if ! kill -0 ${zeromq_pid} 2>/dev/null; then
+ # should never happen - did the test crashed the service?
+ echo >&2 "ERROR: Unable to stop \"ZeroMQ\" test service: service (${zeromq_pid}) not running"
+ exit 69
+ fi
+
+ kill -TERM ${zeromq_pid}
+ local timeout=0
+ while [ ${timeout} -lt 5 ]; do
+ if ! kill -0 ${zeromq_pid} 2>/dev/null; then
+ # service was stopped
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${zeromq_pid} 2>/dev/null; then
+ echo >&2 "WARNING: Timeout (${timeout}s) reached - killing \"ZeroMQ\" test service ..."
+ kill -KILL ${zeromq_pid} 2>/dev/null
+ return $?
+ fi
+}
+
+function start_unix() {
+ if [ -z "$socat" -o ! -x "$socat" ]; then
+ echo "INFO: Skipping \"UNIX socket\" test because \"socat\" executable wasn't found!"
+ exit 77
+ fi
+
+ $socat unix-listen:/tmp/remotebackend.sock exec:./unittest_pipe.rb &
+ socat_pid=$!
+
+ local timeout=0
+ while [ ${timeout} -lt 5 ]; do
+ if [ -S "/tmp/remotebackend.sock" ]; then
+ # service is up and running
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${socat_pid} 2>/dev/null; then
+ # not sure when this can happen but we should cleanup any process we started
+ echo >&2 "WARNING: Timeout (${timeout}s) reached: \"UNIX socket\" test service process is running but status check failed"
+ kill -KILL ${socat_pid} 2>/dev/null
+ fi
+
+ echo >&2 "ERROR: A timeout (${timeout}s) was reached while waiting for \"UNIX socket\" test service to start!"
+ exit 69
+}
+
+function stop_unix() {
+ if [ -z "${socat_pid}" ]; then
+ # should never happen - why was stop_unix() called?
+ echo >&2 "ERROR: Unable to stop \"UNIX socket\" test service: Did we ever start the service?"
+ exit 99
+ fi
+
+ if ! kill -0 ${socat_pid} 2>/dev/null; then
+ # might very well happen, since socat will stop after getting EOF
+ return 0
+ fi
+
+ kill -TERM ${socat_pid}
+ local timeout=0
+ while [ ${timeout} -lt 5 ]; do
+ if ! kill -0 ${socat_pid} 2>/dev/null; then
+ # service was stopped
+ return 0
+ fi
+
+ sleep 1
+ let timeout=timeout+1
+ done
+
+ if kill -0 ${socat_pid} 2>/dev/null; then
+ echo >&2 "WARNING: Timeout (${timeout}s) reached - killing \"UNIX socket\" test service ..."
+ kill -KILL ${socat_pid} 2>/dev/null
+ return $?
+ fi
+}
+
+function run_test() {
+ if [ $new_api -eq 0 ]; then
+ ./$mode
+ else
+ $orig
+ fi
+}
+
+mode=`basename "$mode"`
+
+case "$mode" in
+ remotebackend_pipe.test)
+ run_test
+ ;;
+ remotebackend_unix.test)
+ start_unix
+ run_test
+ stop_unix
+ ;;
+ remotebackend_http.test)
+ start_web "http"
+ run_test
+ stop_web "http"
+ ;;
+ remotebackend_post.test)
+ start_web "post"
+ run_test
+ stop_web "post"
+ ;;
+ remotebackend_json.test)
+ start_web "json"
+ run_test
+ stop_web "json"
+ ;;
+ remotebackend_zeromq.test)
+ start_zeromq
+ run_test
+ stop_zeromq
+ ;;
+ *)
+ echo "Usage: $0 remotebackend_(pipe|unix|http|post|json|zeromq).test"
+ exit 1
+ ;;
+esac
+
+exit $?
--- /dev/null
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+
+# define a simple $domain
+
+$ttl = 300
+$notified_serial = 1
+
+$domain = {
+ "unit.test." => {
+ "SOA" => ["ns.unit.test. hostmaster.unit.test. 1 2 3 4 5 6"],
+ "NS" => ["ns1.unit.test.", "ns2.unit.test."],
+ },
+ "ns1.unit.test." => {
+ "A" => ["10.0.0.1"]
+ },
+ "ns2.unit.test." => {
+ "A" => ["10.0.0.2"]
+ },
+ "empty.unit.test." => {}
+}
+
+$meta = {}
+
+$keys = {}
+
+$tsigkeys = { "test." => {:name => "test.", :algorithm => "NULL.", :content => "NULL"} }
+
+$masters = { :name => "ns1.unit.test.", :ip => "10.0.0.1" }
+
+class Handler
+ def initialize
+ end
+
+ def rr(qname, qtype, content, ttl, auth = 1, domain_id = -1)
+ {:qname => qname, :qtype => qtype, :content => content, :ttl => ttl.to_i, :auth => auth.to_i, :domain_id => domain_id.to_i}
+ end
+
+ def do_initialize(*args)
+ return true, "Test bench initialized"
+ end
+
+ def do_lookup(args)
+ ret = []
+ if $domain.has_key?(args["qname"])
+ if $domain[args["qname"]].has_key?(args["qtype"])
+ $domain[args["qname"]][args["qtype"]].each do |rd|
+ ret << rr(args["qname"], args["qtype"], rd, $ttl)
+ end
+ elsif args["qtype"] == 'ANY'
+ $domain[args["qname"]].each do |qt,qr|
+ qr.each do |rd|
+ ret << rr(args["qname"], qt, rd, $ttl)
+ end
+ end
+ end
+ end
+ [false] unless ret.size>0 and args["qname"] != "empty.unit.test"
+ [ret]
+ end
+
+ def do_list(args)
+ ret = []
+ if args["zonename"] == "unit.test."
+ $domain.each do |qname,rdata|
+ rdata.each do |rtype,rc|
+ rc.each do |rd|
+ ret << rr(qname,rtype,rd,$ttl)
+ end
+ end
+ end
+ end
+ [false] unless ret.size>0
+ [ret]
+ end
+
+ def do_getalldomainmetadata(args)
+ return [ $meta[args["name"]] ] if $meta.has_key?(args["name"])
+ return [false]
+ end
+
+ def do_getdomainmetadata(args)
+ return [ $meta[args["name"]][args["kind"]] ] if $meta.has_key?(args["name"]) and $meta[args["name"]].has_key?(args["kind"])
+ return [false]
+ end
+
+ def do_setdomainmetadata(args)
+ $meta[args["name"].to_s] = {} unless $meta.has_key? args["name"]
+ $meta[args["name"].to_s][args["kind"].to_s] = args["value"].to_a
+ [true]
+ end
+
+ def do_adddomainkey(args)
+ $keys[args["name"]] = [] unless $keys.has_key? args["name"]
+ id=$keys[args["name"]].size + 1
+ args["key"]["id"] = id
+ $keys[args["name"]] << args["key"]
+ [id]
+ end
+
+ def do_getdomainkeys(args)
+ if $keys.has_key? args["name"]
+ return [ $keys[args["name"]] ]
+ end
+ [false]
+ end
+
+ def do_activatedomainkey(args)
+ args["id"] = args["id"].to_i
+ if $keys.has_key? args["name"]
+ if $keys[args["name"]][args["id"]-1]
+ $keys[args["name"]][args["id"]-1]["active"] = true
+ return [true]
+ end
+ end
+ [false]
+ end
+
+ def do_deactivatedomainkey(args)
+ args["id"] = args["id"].to_i
+ if $keys.has_key? args["name"]
+ if $keys[args["name"]][args["id"]-1]
+ $keys[args["name"]][args["id"]-1]["active"] = false
+ return [true]
+ end
+ end
+ [false]
+ end
+
+ def do_removedomainkey(args)
+ args["id"] = args["id"].to_i
+ if $keys.has_key? args["name"]
+ if $keys[args["name"]][args["id"]-1]
+ $keys[args["name"]].delete_at args["id"]-1
+ return [true]
+ end
+ end
+ [false]
+ end
+
+ def do_getbeforeandafternamesabsolute(args)
+ return [ { :unhashed => "middle.", :before => "begin.", :after => "stop." } ] if args["qname"] == 'middle.unit.test.'
+ [false]
+ end
+
+ def do_gettsigkey(args)
+ if $tsigkeys.has_key? args["name"]
+ return [{:algorithm => $tsigkeys[args["name"]][:algorithm], :content => $tsigkeys[args["name"]][:content] }]
+ end
+ [false]
+ end
+
+ def do_setnotified(args)
+ if args["id"].to_i == 1
+ $notified_serial = args["serial"].to_i
+ return [true]
+ end
+ [false]
+ end
+
+ def do_getdomaininfo(args)
+ if args["name"] == "unit.test."
+ return [{
+ :id => 1,
+ :zone => "unit.test.",
+ :masters => ["10.0.0.1"],
+ :notified_serial => $notified_serial,
+ :serial => $notified_serial,
+ :last_check => Time.now.to_i,
+ :kind => 'native'
+ }]
+ end
+ [false]
+ end
+
+ def do_ismaster(args)
+ $masters[:name] == args["name"] && $masters[:ip] == args["ip"]
+ end
+
+ def do_supermasterbackend(args)
+ $domain[args["domain"]] = {
+ "NS" => args["nsset"]
+ }
+ [true]
+ end
+
+ def do_createslavedomain(args)
+ $domain[args["domain"]] = {
+ }
+ [true]
+ end
+
+ def do_feedrecord(args)
+ args.delete "trxid"
+ rr = args["rr"]
+ name = rr["qname"]
+ qtype = rr["qtype"]
+ $domain[name] = {} unless $domain.has_key? name
+ $domain[name][qtype] = [] unless $domain[name].has_key? qtype
+ $domain[name][qtype] << rr["content"]
+ [true]
+ end
+
+ def do_replacerrset(args)
+ $domain[args["qname"]].delete args["qtype"] if $domain.has_key?(args["qname"]) and $domain[args["qname"]].has_key?(args["qtype"])
+ args["rrset"] = args["rrset"].values if args["rrset"].is_a?(Hash)
+ args["rrset"].each do |rr|
+ self.do_feedrecord({"trxid" => args["trxid"], "rr" => rr})
+ end
+ [true]
+ end
+
+ def do_feedents(args)
+ [true]
+ end
+
+ def do_feedents3(args)
+ [true]
+ end
+
+ def do_settsigkey(args)
+ $tsigkeys[args["name"]] = { :name => args["name"], :algorithm => args["algorithm"], :content => args["content"] }
+ [true]
+ end
+
+ def do_deletetsigkey(args)
+ $tsigkeys.delete args["name"] if $tsigkeys.has_key? args["name"]
+ [true]
+ end
+
+ def do_gettsigkeys(*args)
+ return [$tsigkeys.values]
+ end
+
+ def do_starttransaction(args)
+ [true]
+ end
+
+ def do_committransaction(args)
+ [true]
+ end
+
+ def do_aborttransaction(args)
+ [true]
+ end
+
+ def do_calculatesoaserial(args)
+ return [2013060300] if args["sd"]["qname"] == "unit.test."
+ [false]
+ end
+
+ def do_directbackendcmd(args)
+ [args["query"]]
+ end
+
+ def do_getalldomains(args)
+ [do_getdomaininfo({'name'=>'unit.test.'})]
+ end
+end
+
--- /dev/null
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+require 'thread'
+require 'webrick'
+require './unittest'
+
+class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet
+ def initialize(server, dnsbackend)
+ @dnsbackend = dnsbackend
+ @semaphore = Mutex.new
+ @f = File.open("/tmp/remotebackend.txt.#{$$}","ab")
+ @f.set_encoding 'UTF-8'
+ end
+
+ def parse_arrays(params)
+ newparams = {}
+ params.each do |key,val|
+ if key=~/^(.*)\[(.*)\]\[(.*)\]/
+ newparams[$1] = {} unless newparams.has_key? $1
+ newparams[$1][$2] = {} unless newparams[$1].has_key? $2
+ newparams[$1][$2][$3] = val
+ params.delete key
+ elsif key=~/^(.*)\[(.*)\]/
+ if $2 == ""
+ newparams[$1] = [] unless newparams.has_key? $1
+ newparams[$1] << val
+ else
+ newparams[$1] = {} unless newparams.has_key? $1
+ newparams[$1][$2] = val
+ end
+ params.delete key
+ end
+ end
+ params.merge newparams
+ end
+
+ def parse_url(url)
+ url = url.split('/')
+ method = url.shift.downcase
+
+ # do some determining based on method names
+ args = case method
+ when "lookup"
+ {
+ "qname" => url.shift,
+ "qtype" => url.shift
+ }
+ when "list"
+ {
+ "zonename" => url.shift
+ }
+ when "getbeforeandafternamesabsolute", "getbeforeandafternames"
+ {
+ "id" => url.shift.to_i,
+ "qname" => url.shift
+ }
+ when "getdomainmetadata", "setdomainmetadata", "getdomainkeys"
+ {
+ "name" => url.shift,
+ "kind" => url.shift
+ }
+ when "removedomainkey", "activatedomainkey", "deactivatedomainkey"
+ {
+ "id" => url.shift.to_i,
+ "name" => url.shift
+ }
+ when "adddomainkey", "gettsigkey", "getdomaininfo", "settsigkey", "deletetsigkey", "getalldomainmetadata"
+ {
+ "name" => url.shift
+ }
+ when "setnotified", "feedents"
+ {
+ "id" => url.shift.to_i
+ }
+ when "ismaster"
+ {
+ "name" => url.shift,
+ "ip" => url.shift
+ }
+ when "supermasterbackend", "createslavedomain"
+ {
+ "ip" => url.shift,
+ "domain" => url.shift
+ }
+ when "feedents3"
+ {
+ "id" => url.shift.to_i,
+ "domain" => url.shift
+ }
+ when "starttransaction"
+ {
+ "id" => url.shift.to_i,
+ "domain" => url.shift,
+ "trxid" => url.shift.to_i
+ }
+ when "committransaction", "aborttransaction"
+ {
+ "trxid" => url.shift.to_i
+ }
+ when "replacerrset"
+ {
+ "id" => url.shift.to_i,
+ "qname" => url.shift,
+ "qtype" => url.shift
+ }
+ else
+ {}
+ end
+
+ [method, args]
+ end
+
+ def do_GET(req,res)
+ req.continue
+
+ tmp = req.path[/dns\/(.*)/,1]
+ return 400, "Bad request" if (tmp.nil?)
+
+ method, args = parse_url(tmp)
+
+ method = "do_#{method}"
+
+ # get more arguments
+ req.each do |k,v|
+ attr = k[/X-RemoteBackend-(.*)/,1]
+ if attr
+ args[attr] = v
+ end
+ end
+
+ args = args.merge req.query
+
+ if method == "do_adddomainkey"
+ args["key"] = {
+ "flags" => args.delete("flags").to_i,
+ "active" => args.delete("active").to_i,
+ "content" => args.delete("content")
+ }
+ end
+
+ args = parse_arrays args
+ begin
+ @f.puts "#{Time.now.to_f} [http]: #{({:method=>method,:parameters=>args}).to_json}"
+ rescue Encoding::UndefinedConversionError
+ # this fails with encoding error for feedEnts3
+ end
+
+ @semaphore.synchronize do
+ if @dnsbackend.respond_to?(method.to_sym)
+ result, log = @dnsbackend.send(method.to_sym, args)
+ body = {:result => result, :log => log}
+ res.status = 200
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = body.to_json
+ else
+ res.status = 404
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = ({:result => false, :log => ["Method not found"]}).to_json
+ end
+
+ @f.puts "#{Time.now.to_f} [http]: #{res.body}"
+ end
+ end
+
+ def do_DELETE(req,res)
+ do_GET(req,res)
+ end
+
+ def do_POST(req,res)
+ do_GET(req,res)
+ end
+
+ def do_PATCH(req,res)
+ do_GET(req,res)
+ end
+
+ def do_PUT(req,res)
+ do_GET(req,res)
+ end
+end
+
+server = WEBrick::HTTPServer.new(
+ :Port=>62434,
+ :BindAddress=>"localhost",
+# Logger: WEBrick::Log.new("remotebackend-server.log"),
+ :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ]
+)
+
+be = Handler.new
+server.mount "/dns", DNSBackendHandler, be
+server.mount_proc("/ping"){ |req,resp| resp.body = "pong" }
+
+trap('INT') { server.stop }
+trap('TERM') { server.stop }
+
+server.start
--- /dev/null
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+require 'thread'
+require 'webrick'
+require './unittest'
+
+class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet
+ def initialize(server, dnsbackend)
+ @dnsbackend = dnsbackend
+ @semaphore = Mutex.new
+ @f = File.open("/tmp/remotebackend.txt.#{$$}","a")
+ @f.sync
+ end
+
+ def do_POST(req,res)
+ req.continue
+
+ return 400, "Bad request" unless req.path == "/dns/endpoint.json"
+
+ tmp = JSON::parse(req.body)
+ method = tmp["method"].downcase
+ method = "do_#{method}"
+ args = tmp["parameters"]
+
+ @f.puts "#{Time.now.to_f} [http/json]: #{({:method=>method,:parameters=>args}).to_json}"
+
+ @semaphore.synchronize do
+ if @dnsbackend.respond_to?(method.to_sym)
+ result, log = @dnsbackend.send(method.to_sym, args)
+ body = {:result => result, :log => log}
+ res.status = 200
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = body.to_json
+ else
+ res.status = 404
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = ({:result => false, :log => ["Method not found"]}).to_json
+ end
+ @f.puts "#{Time.now.to_f} [http/json]: #{res.body}"
+ end
+ end
+end
+
+server = WEBrick::HTTPServer.new(
+ :Port=>62434,
+ :BindAddress=>"localhost",
+# Logger: WEBrick::Log.new("remotebackend-server.log"),
+ :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ]
+)
+
+be = Handler.new
+server.mount "/dns", DNSBackendHandler, be
+server.mount_proc("/ping"){ |req,resp| resp.body = "pong" }
+
+trap('INT') { server.stop }
+trap('TERM') { server.stop }
+
+server.start
--- /dev/null
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+require './unittest'
+
+h = Handler.new()
+f = File.open "/tmp/remotebackend.txt.#{$$}","a"
+f.sync
+
+STDOUT.sync = true
+begin
+ STDIN.each_line do |line|
+ f.puts "#{Time.now.to_f}: [pipe] #{line}"
+ # expect json
+ input = {}
+ line = line.strip
+ next if line.empty?
+ begin
+ input = JSON.parse(line)
+ method = "do_#{input["method"].downcase}"
+ args = input["parameters"] || []
+
+ if h.respond_to?(method.to_sym) == false
+ res = false
+ elsif args.size > 0
+ res, log = h.send(method,args)
+ else
+ res, log = h.send(method)
+ end
+ puts ({:result => res, :log => log}).to_json
+ f.puts "#{Time.now.to_f} [pipe]: #{({:result => res, :log => log}).to_json}"
+ rescue JSON::ParserError
+ puts ({:result => false, :log => "Cannot parse input #{line}"}).to_json
+ f.puts "#{Time.now.to_f} [pipe]: #{({:result => false, :log => "Cannot parse input #{line}"}).to_json}"
+ next
+ end
+ end
+rescue SystemExit, Interrupt
+end
--- /dev/null
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+require 'thread'
+require 'webrick'
+require './unittest'
+
+class DNSBackendHandler < WEBrick::HTTPServlet::AbstractServlet
+ def initialize(server, dnsbackend)
+ @dnsbackend = dnsbackend
+ @semaphore = Mutex.new
+ @f = File.open("/tmp/remotebackend.txt.#{$$}","a")
+ @f.sync
+ end
+
+ def do_POST(req,res)
+ req.continue
+
+ tmp = req.path[/dns\/(.*)/,1]
+ return 400, "Bad request" if (tmp.nil?)
+
+ url = tmp.split('/')
+ method = url.shift.downcase
+ method = "do_#{method}"
+ args = JSON::parse(req.query["parameters"])
+
+ @f.puts "#{Time.now.to_f} [http/post]: #{({:method=>method,:parameters=>args}).to_json}"
+
+ @semaphore.synchronize do
+ if @dnsbackend.respond_to?(method.to_sym)
+ result, log = @dnsbackend.send(method.to_sym, args)
+ body = {:result => result, :log => log}
+ res.status = 200
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = body.to_json
+ else
+ res.status = 404
+ res["Content-Type"] = "application/javascript; charset=utf-8"
+ res.body = ({:result => false, :log => ["Method not found"]}).to_json
+ end
+ @f.puts "#{Time.now.to_f} [http/post]: #{res.body}"
+ end
+ end
+end
+
+server = WEBrick::HTTPServer.new(
+ :Port=>62434,
+ :BindAddress=>"localhost",
+# Logger: WEBrick::Log.new("remotebackend-server.log"),
+ :AccessLog=>[ [ File.open("remotebackend-access.log", "w"), WEBrick::AccessLog::COMBINED_LOG_FORMAT ] ]
+)
+
+be = Handler.new
+server.mount "/dns", DNSBackendHandler, be
+server.mount_proc("/ping"){ |req,resp| resp.body = "pong" }
+
+trap('INT') { server.stop }
+trap('TERM') { server.stop }
+
+server.start
--- /dev/null
+#!/usr/bin/env ruby
+
+require 'rubygems'
+require 'bundler/setup'
+require 'json'
+require 'zero_mq'
+require './unittest'
+
+h = Handler.new()
+f = File.open "/tmp/remotebackend.txt.#{$$}","a"
+f.sync = true
+
+runcond=true
+
+trap('INT') { runcond = false }
+trap('TERM') { runcond = false }
+
+begin
+ context = ZeroMQ::Context.new
+ socket = context.socket ZMQ::REP
+ socket.bind("ipc:///tmp/remotebackend.0")
+
+ print "[#{Time.now.to_s}] ZeroMQ unit test responder running\n"
+
+ while(runcond) do
+ line = ""
+ rc = socket.recv_string line
+ # expect json
+ input = {}
+ line = line.strip
+
+ f.puts "#{Time.now.to_f}: [zmq] #{line}"
+ next if line.empty?
+ begin
+ input = JSON.parse(line)
+ method = "do_#{input["method"].downcase}"
+ args = input["parameters"] || []
+
+ if h.respond_to?(method.to_sym) == false
+ res = false
+ elsif args.size > 0
+ res, log = h.send(method,args)
+ else
+ res, log = h.send(method)
+ end
+ socket.send_string ({:result => res, :log => log}).to_json + "\n" , 0
+ f.puts "#{Time.now.to_f} [zmq]: #{({:result => res, :log => log}).to_json}"
+ rescue JSON::ParserError
+ socket.send_string ({:result => false, :log => "Cannot parse input #{line}"}).to_json + "\n";
+ f.puts "#{Time.now.to_f} [zmq]: #{({:result => false, :log => "Cannot parse input #{line}"}).to_json}"
+ next
+ end
+ end
+rescue SystemExit, Interrupt, Errno::EINTR
+end
+
+print "[#{Time.now.to_s}] ZeroMQ unit test responder ended\n"
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "remotebackend.hh"
+#ifndef UNIX_PATH_MAX
+#define UNIX_PATH_MAX 108
+#endif
+
+UnixsocketConnector::UnixsocketConnector(std::map<std::string,std::string> options) {
+ if (options.count("path") == 0) {
+ L<<Logger::Error<<"Cannot find 'path' option in connection string"<<endl;
+ throw PDNSException();
+ }
+ this->timeout = 2000;
+ if (options.find("timeout") != options.end()) {
+ this->timeout = std::stoi(options.find("timeout")->second);
+ }
+ this->path = options.find("path")->second;
+ this->options = options;
+ this->connected = false;
+ this->fd = -1;
+}
+
+UnixsocketConnector::~UnixsocketConnector() {
+ if (this->connected) {
+ try {
+ L<<Logger::Info<<"closing socket connection"<<endl;
+ }
+ catch (...) {
+ }
+ close(fd);
+ }
+}
+
+int UnixsocketConnector::send_message(const Json& input) {
+ auto data = input.dump() + "\n";
+ int rv = this->write(data);
+ if (rv == -1)
+ return -1;
+ return rv;
+}
+
+int UnixsocketConnector::recv_message(Json& output) {
+ int rv,nread;
+ std::string s_output,err;
+
+ struct timeval t0,t;
+
+ nread = 0;
+ gettimeofday(&t0, NULL);
+ memcpy(&t,&t0,sizeof(t0));
+ s_output = "";
+
+ while((t.tv_sec - t0.tv_sec)*1000 + (t.tv_usec - t0.tv_usec)/1000 < this->timeout) {
+ int avail = waitForData(this->fd, 0, this->timeout * 500); // use half the timeout as poll timeout
+ if (avail < 0) // poll error
+ return -1;
+ if (avail == 0) { // timeout
+ gettimeofday(&t, NULL);
+ continue;
+ }
+
+ std::string temp;
+ temp.clear();
+
+ rv = this->read(temp);
+ if (rv == -1)
+ return -1;
+
+ if (rv>0) {
+ nread += rv;
+ s_output.append(temp);
+ // see if it can be parsed
+ output = Json::parse(s_output, err);
+ if (output != nullptr) return s_output.size();
+ }
+ gettimeofday(&t, NULL);
+ }
+
+ close(fd);
+ connected = false; // we need to reconnect
+ return -1;
+}
+
+ssize_t UnixsocketConnector::read(std::string &data) {
+ ssize_t nread;
+ char buf[1500] = {0};
+
+ reconnect();
+ if (!connected) return -1;
+ nread = ::read(this->fd, buf, sizeof buf);
+
+ // just try again later...
+ if (nread==-1 && errno == EAGAIN) return 0;
+
+ if (nread==-1 || nread==0) {
+ connected = false;
+ close(fd);
+ return -1;
+ }
+
+ data.append(buf, nread);
+ return nread;
+}
+
+ssize_t UnixsocketConnector::write(const std::string &data) {
+ ssize_t nwrite, nbuf;
+ size_t pos;
+ char buf[1500];
+
+ reconnect();
+ if (!connected) return -1;
+ pos = 0;
+ nwrite = 0;
+ while(pos < data.size()) {
+ nbuf = data.copy(buf, sizeof buf, pos); // copy data and write
+ nwrite = ::write(fd, buf, nbuf);
+ pos = pos + sizeof(buf);
+ if (nwrite < 1) {
+ connected = false;
+ close(fd);
+ return -1;
+ }
+ }
+ return nwrite;
+}
+
+void UnixsocketConnector::reconnect() {
+ struct sockaddr_un sock;
+ int rv;
+
+ if (connected) return; // no point reconnecting if connected...
+ connected = true;
+
+ L<<Logger::Info<<"Reconnecting to backend" << std::endl;
+ fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (fd < 0) {
+ connected = false;
+ L<<Logger::Error<<"Cannot create socket: " << strerror(errno) << std::endl;;
+ return;
+ }
+
+ if (makeUNsockaddr(path, &sock)) {
+ L<<Logger::Error<<"Unable to create UNIX domain socket: Path '"<<path<<"' is not a valid UNIX socket path."<<std::endl;
+ return;
+ }
+
+ rv = connect(fd, reinterpret_cast<struct sockaddr*>(&sock), sizeof sock);
+
+ if (rv != 0 && errno != EISCONN && errno != 0) {
+ L<<Logger::Error<<"Cannot connect to socket: " << strerror(errno) << std::endl;
+ close(fd);
+ connected = false;
+ return;
+ }
+ // send initialize
+
+ Json::array parameters;
+ Json msg = Json(Json::object{
+ { "method", "initialize" },
+ { "parameters", Json(options) },
+ });
+
+ this->send(msg);
+ msg = nullptr;
+ if (this->recv(msg) == false) {
+ L<<Logger::Warning << "Failed to initialize backend" << std::endl;
+ close(fd);
+ this->connected = false;
+ }
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "remotebackend.hh"
+#ifdef REMOTEBACKEND_ZEROMQ
+
+ZeroMQConnector::ZeroMQConnector(std::map<std::string,std::string> options) {
+ int opt=0;
+
+ // lookup timeout, target and stuff
+ if (options.count("endpoint") == 0) {
+ L<<Logger::Error<<"Cannot find 'endpoint' option in connection string"<<endl;
+ throw PDNSException("Cannot find 'endpoint' option in connection string");
+ }
+ this->d_endpoint = options.find("endpoint")->second;
+ this->d_options = options;
+ this->d_timeout=2000;
+
+ if (options.find("timeout") != options.end()) {
+ this->d_timeout = std::stoi(options.find("timeout")->second);
+ }
+
+ d_ctx = zmq_init(2);
+ d_sock = zmq_socket(this->d_ctx, ZMQ_REQ);
+ zmq_setsockopt(d_sock, ZMQ_LINGER, &opt, sizeof(opt));
+
+ if(zmq_connect(this->d_sock, this->d_endpoint.c_str()) < 0)
+ {
+ L<<Logger::Error<<"zmq_connect() failed"<< zmq_strerror(errno)<<std::endl;;
+ throw PDNSException("Cannot find 'endpoint' option in connection string");
+ }
+
+ Json::array parameters;
+ Json msg = Json(Json::object{
+ { "method", "initialize" },
+ { "parameters", Json(options) },
+ });
+
+ this->send(msg);
+ msg = nullptr;
+ if (this->recv(msg)==false) {
+ L<<Logger::Error<<"Failed to initialize zeromq"<<std::endl;
+ throw PDNSException("Failed to initialize zeromq");
+ }
+};
+
+ZeroMQConnector::~ZeroMQConnector() {
+ zmq_close(this->d_sock);
+ zmq_term(this->d_ctx);
+};
+
+int ZeroMQConnector::send_message(const Json& input) {
+ auto line = input.dump();
+ zmq_msg_t message;
+
+ zmq_msg_init_size(&message, line.size()+1);
+ line.copy(reinterpret_cast<char*>(zmq_msg_data(&message)), line.size());
+ ((char *)zmq_msg_data(&message))[line.size()] = '\0';
+
+ try {
+ zmq_pollitem_t item;
+ item.socket = d_sock;
+ item.events = ZMQ_POLLOUT;
+ // poll until it's sent or timeout is spent. try to leave
+ // leave few cycles for read. just in case.
+ for(d_timespent = 0; d_timespent < d_timeout-5; d_timespent++) {
+ if (zmq_poll(&item, 1, 1)>0) {
+ if(zmq_msg_send(&message, this->d_sock, 0) == -1) {
+ // message was not sent
+ L<<Logger::Error<<"Cannot send to " << this->d_endpoint << ": " << zmq_strerror(errno)<<std::endl;
+ } else
+ return line.size();
+ }
+ }
+ } catch (std::exception &ex) {
+ L<<Logger::Error<<"Cannot send to " << this->d_endpoint << ": " << ex.what()<<std::endl;
+ throw PDNSException(ex.what());
+ }
+
+ return 0;
+}
+
+int ZeroMQConnector::recv_message(Json& output) {
+ int rv = 0;
+ // try to receive message
+ zmq_pollitem_t item;
+ zmq_msg_t message;
+
+ item.socket = d_sock;
+ item.events = ZMQ_POLLIN;
+
+ try {
+ // do zmq::poll few times
+ // d_timespent should always be initialized by send_message, recv should never
+ // be called without send first.
+ for(; d_timespent < d_timeout; d_timespent++) {
+ if (zmq_poll(&item, 1, 1)>0) {
+ // we have an event
+ if ((item.revents & ZMQ_POLLIN) == ZMQ_POLLIN) {
+ string data;
+ size_t msg_size;
+ zmq_msg_init(&message);
+ // read something
+ if(zmq_msg_recv(&message, this->d_sock, ZMQ_NOBLOCK)>0) {
+ string err;
+ msg_size = zmq_msg_size(&message);
+ data.assign(reinterpret_cast<const char*>(zmq_msg_data(&message)), msg_size);
+ zmq_msg_close(&message);
+ output = Json::parse(data, err);
+ if (output != nullptr)
+ rv = msg_size;
+ else
+ L<<Logger::Error<<"Cannot parse JSON reply from " << this->d_endpoint << ": " << err << endl;
+ break;
+ } else if (errno == EAGAIN) { continue; // try again }
+ } else {
+ break;
+ }
+ }
+ }
+ }
+ } catch (std::exception &ex) {
+ L<<Logger::Error<<"Cannot receive from " << this->d_endpoint << ": " << ex.what()<<std::endl;
+ throw PDNSException(ex.what());
+ }
+
+ return rv;
+}
+
+#endif
--- /dev/null
+AM_CPPFLAGS += $(CDB_CFLAGS)
+
+pkglib_LTLIBRARIES = libtinydnsbackend.la
+
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+
+libtinydnsbackend_la_SOURCES = \
+ cdb.cc cdb.hh \
+ tinydnsbackend.cc tinydnsbackend.hh
+
+libtinydnsbackend_la_LDFLAGS = -module -avoid-version
+libtinydnsbackend_la_LIBADD = $(CDB_LIBS)
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+subdir = modules/tinydnsbackend
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(top_srcdir)/build-aux/depcomp
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+am__installdirs = "$(DESTDIR)$(pkglibdir)"
+LTLIBRARIES = $(pkglib_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libtinydnsbackend_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am_libtinydnsbackend_la_OBJECTS = cdb.lo tinydnsbackend.lo
+libtinydnsbackend_la_OBJECTS = $(am_libtinydnsbackend_la_OBJECTS)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+libtinydnsbackend_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(libtinydnsbackend_la_LDFLAGS) \
+ $(LDFLAGS) -o $@
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+SOURCES = $(libtinydnsbackend_la_SOURCES)
+DIST_SOURCES = $(libtinydnsbackend_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ $(CDB_CFLAGS)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+pkglib_LTLIBRARIES = libtinydnsbackend.la
+EXTRA_DIST = OBJECTFILES OBJECTLIBS
+libtinydnsbackend_la_SOURCES = \
+ cdb.cc cdb.hh \
+ tinydnsbackend.cc tinydnsbackend.hh
+
+libtinydnsbackend_la_LDFLAGS = -module -avoid-version
+libtinydnsbackend_la_LIBADD = $(CDB_LIBS)
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .cc .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign modules/tinydnsbackend/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign modules/tinydnsbackend/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+
+install-pkglibLTLIBRARIES: $(pkglib_LTLIBRARIES)
+ @$(NORMAL_INSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ list2=; for p in $$list; do \
+ if test -f $$p; then \
+ list2="$$list2 $$p"; \
+ else :; fi; \
+ done; \
+ test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkglibdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkglibdir)" || exit 1; \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pkglibdir)'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pkglibdir)"; \
+ }
+
+uninstall-pkglibLTLIBRARIES:
+ @$(NORMAL_UNINSTALL)
+ @list='$(pkglib_LTLIBRARIES)'; test -n "$(pkglibdir)" || list=; \
+ for p in $$list; do \
+ $(am__strip_dir) \
+ echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pkglibdir)/$$f'"; \
+ $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pkglibdir)/$$f"; \
+ done
+
+clean-pkglibLTLIBRARIES:
+ -test -z "$(pkglib_LTLIBRARIES)" || rm -f $(pkglib_LTLIBRARIES)
+ @list='$(pkglib_LTLIBRARIES)'; \
+ locs=`for p in $$list; do echo $$p; done | \
+ sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \
+ sort -u`; \
+ test -z "$$locs" || { \
+ echo rm -f $${locs}; \
+ rm -f $${locs}; \
+ }
+
+libtinydnsbackend.la: $(libtinydnsbackend_la_OBJECTS) $(libtinydnsbackend_la_DEPENDENCIES) $(EXTRA_libtinydnsbackend_la_DEPENDENCIES)
+ $(AM_V_CXXLD)$(libtinydnsbackend_la_LINK) -rpath $(pkglibdir) $(libtinydnsbackend_la_OBJECTS) $(libtinydnsbackend_la_LIBADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/cdb.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tinydnsbackend.Plo@am__quote@
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+ for dir in "$(DESTDIR)$(pkglibdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+
+clean-generic:
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+clean: clean-am
+
+clean-am: clean-generic clean-libtool clean-pkglibLTLIBRARIES \
+ mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am:
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-pkglibLTLIBRARIES
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-pkglibLTLIBRARIES
+
+.MAKE: install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-am clean clean-generic \
+ clean-libtool clean-pkglibLTLIBRARIES cscopelist-am ctags \
+ ctags-am distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-data \
+ install-data-am install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-pkglibLTLIBRARIES install-ps install-ps-am \
+ install-strip installcheck installcheck-am installdirs \
+ maintainer-clean maintainer-clean-generic mostlyclean \
+ mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+ pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \
+ uninstall-pkglibLTLIBRARIES
+
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+tinydnsbackend.lo cdb.lo
\ No newline at end of file
--- /dev/null
+$(CDB_LIBS)
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "cdb.hh"
+#include <cdb.h>
+#include "pdns/misc.hh"
+#include "pdns/iputils.hh"
+#include <utility>
+
+
+CDB::CDB(const string &cdbfile)
+{
+ d_fd = open(cdbfile.c_str(), O_RDONLY);
+ if (d_fd < 0)
+ {
+ L<<Logger::Error<<"Failed to open cdb database file '"<<cdbfile<<"'. Error: "<<stringerror()<<endl;
+ throw new PDNSException("Failed to open cdb database file '"+cdbfile+"'. Error: " + stringerror());
+ }
+
+ memset(&d_cdbf,0,sizeof(struct cdb_find));
+ int cdbinit = cdb_init(&d_cdb, d_fd);
+ if (cdbinit < 0)
+ {
+ L<<Logger::Error<<"Failed to initialize cdb structure. ErrorNr: '"<<cdbinit<<endl;
+ throw new PDNSException("Failed to initialize cdb structure.");
+ }
+
+ d_key = NULL;
+ d_seqPtr = 0;
+ d_searchType = SearchKey;
+}
+
+CDB::~CDB() {
+ cdb_free(&d_cdb);
+ close(d_fd);
+}
+
+int CDB::searchKey(const string &key) {
+ d_searchType = SearchKey;
+
+ // A 'bug' in tinycdb (the lib used for reading the CDB files) means we have to copy the key because the cdb_find struct
+ // keeps a pointer to it.
+ d_key = strdup(key.c_str());
+ return cdb_findinit(&d_cdbf, &d_cdb, d_key, key.size());
+}
+
+bool CDB::searchSuffix(const string &key) {
+ d_searchType = SearchSuffix;
+
+ //See CDB::searchKey()
+ d_key = strdup(key.c_str());
+
+ // We are ok with a search on things, but we do want to know if a record with that key exists.........
+ bool hasDomain = (cdb_find(&d_cdb, key.c_str(), key.size()) == 1);
+ if (hasDomain) {
+ cdb_seqinit(&d_seqPtr, &d_cdb);
+ }
+
+ return hasDomain;
+}
+
+void CDB::searchAll() {
+ d_searchType = SearchAll;
+ cdb_seqinit(&d_seqPtr, &d_cdb);
+}
+
+bool CDB::moveToNext() {
+ int hasNext = 0;
+ if (d_searchType == SearchKey) {
+ hasNext = cdb_findnext(&d_cdbf);
+ } else {
+ hasNext = cdb_seqnext(&d_seqPtr, &d_cdb);
+ }
+ return (hasNext > 0);
+}
+
+bool CDB::readNext(pair<string, string> &value) {
+ while (moveToNext()) {
+ unsigned int pos;
+ unsigned int len;
+
+ pos = cdb_keypos(&d_cdb);
+ len = cdb_keylen(&d_cdb);
+
+ char *key = (char *)malloc(len);
+ cdb_read(&d_cdb, key, len, pos);
+
+ if (d_searchType == SearchSuffix) {
+ char *p = strstr(key, d_key);
+ if (p == NULL) {
+ free(key);
+ continue;
+ }
+ }
+ string skey(key, len);
+ free(key);
+
+ pos = cdb_datapos(&d_cdb);
+ len = cdb_datalen(&d_cdb);
+ char *val = (char *)malloc(len);
+ cdb_read(&d_cdb, val, len, pos);
+ string sval(val, len);
+ free(val);
+
+ value = make_pair(skey, sval);
+ return true;
+ }
+ // We're done searching, so we can clean up d_key
+ if (d_searchType != SearchAll) {
+ free(d_key);
+ }
+ return false;
+}
+
+vector<string> CDB::findall(string &key)
+{
+ vector<string> ret;
+ struct cdb_find cdbf;
+
+ cdb_findinit(&cdbf, &d_cdb, key.c_str(), key.size());
+ int x=0;
+ while(cdb_findnext(&cdbf) > 0) {
+ x++;
+ unsigned int vpos = cdb_datapos(&d_cdb);
+ unsigned int vlen = cdb_datalen(&d_cdb);
+ char *val = (char *)malloc(vlen);
+ cdb_read(&d_cdb, val, vlen, vpos);
+ string sval(val, vlen);
+ ret.push_back(sval);
+ free(val);
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef CDB_HH
+#define CDB_HH
+
+#include "pdns/logger.hh"
+#include <cdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+// This class is responsible for the reading of a CDB file.
+// The constructor opens the CDB file, the destructor closes it, so make sure you call that.
+class CDB
+{
+public:
+ CDB(const string &cdbfile);
+ ~CDB();
+
+ int searchKey(const string &key);
+ bool searchSuffix(const string &key);
+ void searchAll();
+ bool readNext(pair<string, string> &value);
+ vector<string> findall(string &key);
+
+private:
+ int d_fd;
+ bool moveToNext();
+ struct cdb d_cdb;
+ struct cdb_find d_cdbf;
+ char *d_key;
+ unsigned d_seqPtr;
+ enum SearchType { SearchSuffix, SearchKey, SearchAll } d_searchType;
+};
+
+#endif // CDB_HH
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "tinydnsbackend.hh"
+#include "pdns/lock.hh"
+#include <cdb.h>
+#include "pdns/misc.hh"
+#include "pdns/iputils.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/dnsrecords.hh"
+#include <utility>
+
+
+static string backendname="[TinyDNSBackend] ";
+uint32_t TinyDNSBackend::s_lastId;
+pthread_mutex_t TinyDNSBackend::s_domainInfoLock=PTHREAD_MUTEX_INITIALIZER;
+TinyDNSBackend::TDI_suffix_t TinyDNSBackend::s_domainInfo;
+
+vector<string> TinyDNSBackend::getLocations()
+{
+ vector<string> ret;
+
+ if (! d_dnspacket) {
+ return ret;
+ }
+
+ //TODO: We do not have IPv6 support.
+ Netmask remote = d_dnspacket->getRealRemote();
+ if (remote.getBits() != 32) {
+ return ret;
+ }
+
+ unsigned long addr = remote.getNetwork().sin4.sin_addr.s_addr;
+
+ char key[6];
+ key[0] = '\000';
+ key[1] = '\045';
+ key[2] = (addr )&0xff;
+ key[3] = (addr >> 8)&0xff;
+ key[4] = (addr >> 16)&0xff;
+ key[5] = (addr >> 24)&0xff;
+
+ for (int i=4;i>=0;i--) {
+ string searchkey(key, i+2);
+ CDB *reader = new CDB(getArg("dbfile"));
+ ret = reader->findall(searchkey);
+ delete reader;
+
+ //Biggest item wins, so when we find something, we can jump out.
+ if (ret.size() > 0) {
+ break;
+ }
+ }
+
+ return ret;
+}
+
+TinyDNSBackend::TinyDNSBackend(const string &suffix)
+{
+ setArgPrefix("tinydns"+suffix);
+ d_suffix = suffix;
+ d_locations = mustDo("locations");
+ d_ignorebogus = mustDo("ignore-bogus-records");
+ d_taiepoch = 4611686018427387904ULL + getArgAsNum("tai-adjust");
+ d_dnspacket = NULL;
+ d_cdbReader = NULL;
+ d_isAxfr = false;
+ d_isWildcardQuery = false;
+}
+
+void TinyDNSBackend::getUpdatedMasters(vector<DomainInfo>* retDomains) {
+ Lock l(&s_domainInfoLock); //TODO: We could actually lock less if we do it per suffix.
+
+ if (! s_domainInfo.count(d_suffix)) {
+ TDI_t tmp;
+ s_domainInfo.insert( make_pair(d_suffix,tmp) );
+ }
+
+ TDI_t *domains = &s_domainInfo[d_suffix];
+
+ vector<DomainInfo> allDomains;
+ getAllDomains(&allDomains);
+ if (domains->size() == 0 && !mustDo("notify-on-startup")) {
+ for (vector<DomainInfo>::iterator di=allDomains.begin(); di!=allDomains.end(); ++di) {
+ di->notified_serial = 0;
+ }
+ }
+
+ for(vector<DomainInfo>::iterator di=allDomains.begin(); di!=allDomains.end(); ++di) {
+ TDIByZone_t& zone_index = domains->get<tag_zone>();
+ TDIByZone_t::iterator itByZone = zone_index.find(di->zone);
+ if (itByZone == zone_index.end()) {
+ s_lastId++;
+
+ TinyDomainInfo tmp;
+ tmp.zone = di->zone;
+ tmp.id = s_lastId;
+ tmp.notified_serial = di->serial;
+ domains->insert(tmp);
+
+ di->id = s_lastId;
+ if (di->notified_serial > 0) {
+ retDomains->push_back(*di);
+ }
+ } else {
+ if (itByZone->notified_serial < di->serial) {
+ di->id = itByZone->id;
+ retDomains->push_back(*di);
+ }
+ }
+ }
+}
+
+void TinyDNSBackend::setNotified(uint32_t id, uint32_t serial) {
+ Lock l(&s_domainInfoLock);
+ if (!s_domainInfo.count(d_suffix)) {
+ throw new PDNSException("Can't get list of domains to set the serial.");
+ }
+ TDI_t *domains = &s_domainInfo[d_suffix];
+ TDIById_t& domain_index = domains->get<tag_domainid>();
+ TDIById_t::iterator itById = domain_index.find(id);
+ if (itById == domain_index.end()) {
+ L<<Logger::Error<<backendname<<"Received updated serial("<<serial<<"), but domain ID ("<<id<<") is not known in this backend."<<endl;
+ } else {
+ DLOG(L<<Logger::Debug<<backendname<<"Setting serial for "<<itById->zone<<" to "<<serial<<endl);
+ domain_index.modify(itById, TDI_SerialModifier(serial));
+ }
+ s_domainInfo[d_suffix] = *domains;
+}
+
+void TinyDNSBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled) {
+ d_isAxfr=true;
+ d_dnspacket = NULL;
+
+ d_cdbReader=std::unique_ptr<CDB>(new CDB(getArg("dbfile")));
+ d_cdbReader->searchAll();
+ DNSResourceRecord rr;
+
+ while (get(rr)) {
+ if (rr.qtype.getCode() == QType::SOA) {
+ SOAData sd;
+ fillSOAData(rr.content, sd);
+
+ DomainInfo di;
+ di.id = -1; //TODO: Check if this is ok.
+ di.backend=this;
+ di.zone = rr.qname;
+ di.serial = sd.serial;
+ di.notified_serial = sd.serial;
+ di.kind = DomainInfo::Master;
+ di.last_check = time(0);
+ domains->push_back(di);
+ }
+ }
+}
+
+bool TinyDNSBackend::list(const DNSName &target, int domain_id, bool include_disabled) {
+ d_isAxfr=true;
+ string key = target.toDNSString(); // FIXME400 bug: no lowercase here? or promise that from core?
+ d_cdbReader=std::unique_ptr<CDB>(new CDB(getArg("dbfile")));
+ return d_cdbReader->searchSuffix(key);
+}
+
+void TinyDNSBackend::lookup(const QType &qtype, const DNSName &qdomain, DNSPacket *pkt_p, int zoneId) {
+ d_isAxfr = false;
+ string queryDomain = toLowerCanonic(qdomain.toString());
+
+ string key=simpleCompress(queryDomain);
+
+ DLOG(L<<Logger::Debug<<backendname<<"[lookup] query for qtype ["<<qtype.getName()<<"] qdomain ["<<qdomain<<"]"<<endl);
+ DLOG(L<<Logger::Debug<<"[lookup] key ["<<makeHexDump(key)<<"]"<<endl);
+
+ d_isWildcardQuery = false;
+ if (key[0] == '\001' && key[1] == '\052') {
+ d_isWildcardQuery = true;
+ key.erase(0,2);
+ }
+
+ d_qtype=qtype;
+
+ d_cdbReader=std::unique_ptr<CDB>(new CDB(getArg("dbfile")));
+ d_cdbReader->searchKey(key);
+ d_dnspacket = pkt_p;
+}
+
+
+bool TinyDNSBackend::get(DNSResourceRecord &rr)
+{
+ pair<string, string> record;
+
+ while (d_cdbReader->readNext(record)) {
+ string val = record.second;
+ string key = record.first;
+
+ //DLOG(L<<Logger::Debug<<"[GET] Key: "<<makeHexDump(key)<<endl);
+ //DLOG(L<<Logger::Debug<<"[GET] Val: "<<makeHexDump(val)<<endl);
+ if (key[0] == '\000' && key[1] == '\045') { // skip locations
+ continue;
+ }
+
+ if (!d_isAxfr) {
+ // If we have a wildcard query, but the record we got is not a wildcard, we skip.
+ if (d_isWildcardQuery && val[2] != '\052' && val[2] != '\053') {
+ continue;
+ }
+
+ // If it is NOT a wildcard query, but we do find a wildcard record, we skip it.
+ if (!d_isWildcardQuery && (val[2] == '\052' || val[2] == '\053')) {
+ continue;
+ }
+ }
+
+
+ vector<uint8_t> bytes;
+ const char *sval = val.c_str();
+ unsigned int len = val.size();
+ bytes.resize(len);
+ copy(sval, sval+len, bytes.begin());
+ PacketReader pr(bytes);
+ rr.qtype = QType(pr.get16BitInt());
+
+ if(d_isAxfr || d_qtype.getCode() == QType::ANY || rr.qtype == d_qtype) {
+ char locwild = pr.get8BitInt();
+ if(locwild != '\075' && (locwild == '\076' || locwild == '\053')) {
+ if (d_isAxfr && d_locations) { // We skip records with a location in AXFR, unless we disable locations.
+ continue;
+ }
+ char recloc[2];
+ recloc[0] = pr.get8BitInt();
+ recloc[1] = pr.get8BitInt();
+
+ if (d_locations) {
+ bool foundLocation = false;
+ vector<string> locations = getLocations();
+ while(locations.size() > 0) {
+ string locId = locations.back();
+ locations.pop_back();
+
+ if (recloc[0] == locId[0] && recloc[1] == locId[1]) {
+ foundLocation = true;
+ break;
+ }
+ }
+ if (!foundLocation) {
+ continue;
+ }
+ }
+ }
+
+ if (d_isAxfr && (val[2] == '\052' || val[2] == '\053' )) { // Keys are not stored with wildcard character, with AXFR we need to add that.
+ key.insert(0, 1, '\052');
+ key.insert(0, 1, '\001');
+ }
+ // rr.qname.clear();
+ rr.qname=DNSName(key.c_str(), key.size(), 0, false);
+ rr.domain_id=-1;
+ // 11:13.21 <@ahu> IT IS ALWAYS AUTH --- well not really because we are just a backend :-)
+ // We could actually do NSEC3-NARROW DNSSEC according to Habbie, if we do, we need to change something ehre.
+ rr.auth = true;
+
+ rr.ttl = pr.get32BitInt();
+ uint64_t timestamp = pr.get32BitInt();
+ timestamp <<= 32;
+ timestamp += pr.get32BitInt();
+ if(timestamp) {
+ uint64_t now = d_taiepoch + time(NULL);
+ if (rr.ttl == 0) {
+ if (timestamp < now) {
+ continue;
+ }
+ rr.ttl = timestamp - now;
+ } else if (now <= timestamp) {
+ continue;
+ }
+ }
+ try {
+ DNSRecord dr;
+ dr.d_class = 1;
+ dr.d_type = rr.qtype.getCode();
+ dr.d_clen = val.size()-pr.d_pos;
+
+ DNSRecordContent *drc = DNSRecordContent::mastermake(dr, pr);
+ rr.content = drc->getZoneRepresentation();
+ DLOG(cerr<<"CONTENT: "<<rr.content<<endl);
+ delete drc;
+ }
+ catch (...) {
+ if (d_ignorebogus) {
+ L<<Logger::Error<<backendname<<"Failed to parse record content for "<<rr.qname<<" with type "<<rr.qtype.getName()<<". Ignoring!"<<endl;
+ continue;
+ } else
+ throw;
+ }
+// DLOG(L<<Logger::Debug<<backendname<<"Returning ["<<rr.content<<"] for ["<<rr.qname<<"] of RecordType ["<<rr.qtype.getName()<<"]"<<endl;);
+ return true;
+ }
+ } // end of while
+ DLOG(L<<Logger::Debug<<backendname<<"No more records to return."<<endl);
+
+ d_cdbReader = nullptr;
+ return false;
+}
+
+// boilerplate
+class TinyDNSFactory: public BackendFactory
+{
+public:
+ TinyDNSFactory() : BackendFactory("tinydns") {}
+
+ void declareArguments(const string &suffix="") {
+ declare(suffix, "notify-on-startup", "Tell the TinyDNSBackend to notify all the slave nameservers on startup. Default is no.", "no");
+ declare(suffix, "dbfile", "Location of the cdb data file", "data.cdb");
+ declare(suffix, "tai-adjust", "This adjusts the TAI value if timestamps are used. These seconds will be added to the start point (1970) and will allow you to adjust for leap seconds. The default is 11.", "11");
+ declare(suffix, "locations", "Enable or Disable location support in the backend. Changing the value to 'no' will make the backend ignore the locations. This then returns all records!", "yes");
+ declare(suffix, "ignore-bogus-records", "The data.cdb file might have some incorrect record data, this causes PowerDNS to fail, where tinydns would send out truncated data. This option makes powerdns ignore that data!", "no");
+ }
+
+ DNSBackend *make(const string &suffix="") {
+ return new TinyDNSBackend(suffix);
+ }
+};
+
+// boilerplate
+class TinyDNSLoader
+{
+public:
+ TinyDNSLoader() {
+ BackendMakers().report(new TinyDNSFactory);
+ L << Logger::Info << "[tinydnsbackend] This is the tinydns backend version " VERSION
+#ifndef REPRODUCIBLE
+ << " (" __DATE__ " " __TIME__ ")"
+#endif
+ << " reporting" << endl;
+ }
+};
+
+static TinyDNSLoader tinydnsloader;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef TINYDNSBACKEND_HH
+#define TINYDNSBACKEND_HH
+
+#include "pdns/dnsbackend.hh"
+#include "pdns/logger.hh"
+#include "pdns/iputils.hh"
+#include "pdns/dnspacket.hh"
+#include <cdb.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "cdb.hh"
+#include "pdns/lock.hh"
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/multi_index/member.hpp>
+
+using namespace ::boost;
+using namespace ::boost::multi_index;
+
+struct TinyDomainInfo {
+ uint32_t id;
+ uint32_t notified_serial;
+ DNSName zone;
+
+ bool operator<(const TinyDomainInfo& tdi) const
+ {
+ return zone < tdi.zone;
+ }
+};
+
+struct TDI_SerialModifier {
+ TDI_SerialModifier (const int newSerial) : d_newSerial(newSerial) {}
+
+ void operator()(TinyDomainInfo& tdi)
+ {
+ tdi.notified_serial = d_newSerial;
+ }
+
+ private:
+ int d_newSerial;
+};
+
+
+class TinyDNSBackend : public DNSBackend
+{
+public:
+ // Methods for simple operation
+ TinyDNSBackend(const string &suffix);
+ void lookup(const QType &qtype, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1);
+ bool list(const DNSName &target, int domain_id, bool include_disabled=false);
+ bool get(DNSResourceRecord &rr);
+ void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false);
+
+ //Master mode operation
+ void getUpdatedMasters(vector<DomainInfo>* domains);
+ void setNotified(uint32_t id, uint32_t serial);
+private:
+ vector<string> getLocations();
+
+ //TypeDefs
+ struct tag_zone{};
+ struct tag_domainid{};
+ typedef multi_index_container<
+ TinyDomainInfo,
+ indexed_by<
+ hashed_unique<tag<tag_zone>, member<TinyDomainInfo, DNSName, &TinyDomainInfo::zone> >,
+ hashed_unique<tag<tag_domainid>, member<TinyDomainInfo, uint32_t, &TinyDomainInfo::id> >
+ >
+ > TDI_t;
+ typedef map<string, TDI_t> TDI_suffix_t;
+ typedef TDI_t::index<tag_zone>::type TDIByZone_t;
+ typedef TDI_t::index<tag_domainid>::type TDIById_t;
+
+ //data member variables
+ uint64_t d_taiepoch;
+ QType d_qtype;
+ std::unique_ptr<CDB> d_cdbReader;
+ DNSPacket *d_dnspacket; // used for location and edns-client support.
+ bool d_isWildcardQuery; // Indicate if the query received was a wildcard query.
+ bool d_isAxfr; // Indicate if we received a list() and not a lookup().
+ bool d_locations;
+ bool d_ignorebogus;
+ string d_suffix;
+
+ // Statics
+ static pthread_mutex_t s_domainInfoLock;
+ static TDI_suffix_t s_domainInfo;
+ static uint32_t s_lastId; // used to give a domain an id.
+};
+
+#endif // TINYDNSBACKEND_HH
--- /dev/null
+JSON11_LIBS = $(top_builddir)/ext/json11/libjson11.la
+
+AM_CPPFLAGS += \
+ -I$(top_srcdir)/ext/json11 \
+ $(YAHTTP_CFLAGS) \
+ $(LIBEDIT_CFLAGS) \
+ $(LIBCRYPTO_INCLUDES) \
+ $(SYSTEMD_CFLAGS)
+
+AM_CXXFLAGS = \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DPKGLIBDIR=\"$(pkglibdir)\" \
+ -DLOCALSTATEDIR=\"$(socketdir)\"
+
+AM_LDFLAGS = \
+ $(PROGRAM_LDFLAGS) \
+ $(THREADFLAGS)
+
+AM_LFLAGS = -i
+AM_YFLAGS = -d --verbose --debug
+
+if BOTAN110
+AM_CPPFLAGS += $(BOTAN110_CFLAGS)
+endif
+
+if PKCS11
+AM_CPPFLAGS += $(P11KIT1_CFLAGS)
+endif
+
+if SQLITE3
+AM_CPPFLAGS += $(SQLITE3_CFLAGS)
+endif
+
+if LUA
+AM_CPPFLAGS +=$(LUA_CFLAGS)
+endif
+
+if GSS_TSIG
+AM_CPPFLAGS +=$(GSS_CFLAGS)
+endif
+
+EXTRA_DIST = \
+ dnslabeltext.rl \
+ dnslabeltext.cc \
+ dnsmessage.proto \
+ effective_tld_names.dat \
+ mtasker.cc \
+ inflighter.cc \
+ bind-dnssec.schema.sqlite3.sql \
+ bindparser.h \
+ named.conf.parsertest \
+ delaypipe.hh delaypipe.cc \
+ pdns.service.in
+
+BUILT_SOURCES = \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindparser.h
+
+CLEANFILES = \
+ *.gcda \
+ *.gcno \
+ *.gcov \
+ backends/gsql/gsqlbackend.gcda \
+ backends/gsql/gsqlbackend.gcno \
+ backends/gsql/gsqlbackend.gcov \
+ dnsmessage.pb.cc dnsmessage.pb.h \
+ pdns.conf-dist
+
+noinst_SCRIPTS = pdns.init
+sysconf_DATA = pdns.conf-dist
+
+sbin_PROGRAMS = pdns_server
+bin_PROGRAMS = \
+ pdns_control \
+ pdnsutil \
+ zone2sql \
+ zone2json
+
+if TOOLS
+bin_PROGRAMS += \
+ dnsgram \
+ dnsreplay \
+ dnsscan \
+ dnsscope \
+ dnswasher \
+ dumresp \
+ pdns_notify \
+ nproxy \
+ nsec3dig \
+ saxfr \
+ stubquery \
+ ixplore \
+ sdig
+
+if HAVE_RECVMMSG
+bin_PROGRAMS += calidns
+endif
+
+if HAVE_BOOST_GE_148
+bin_PROGRAMS += \
+ dnsbulktest \
+ dnstcpbench
+endif
+
+endif
+
+EXTRA_PROGRAMS = \
+ calidns \
+ comfun \
+ dnsbulktest \
+ dnsdemog \
+ dnsgram \
+ dnsreplay \
+ dnsscan \
+ dnsscope \
+ dnstcpbench \
+ dnswasher \
+ dumresp \
+ kvresp \
+ ixplore \
+ pdns_notify \
+ nproxy \
+ nsec3dig \
+ saxfr \
+ stubquery \
+ sdig \
+ speedtest \
+ testrunner \
+ toysdig \
+ tsig-tests \
+ zone2ldap
+
+pdns_server_SOURCES = \
+ arguments.cc arguments.hh \
+ auth-carbon.cc \
+ backends/gsql/gsqlbackend.cc backends/gsql/gsqlbackend.hh \
+ backends/gsql/ssql.hh \
+ base32.cc base32.hh \
+ base64.cc base64.hh \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.cc \
+ cachecleaner.hh \
+ comment.hh \
+ common_startup.cc common_startup.hh \
+ communicator.cc communicator.hh \
+ dbdnsseckeeper.cc \
+ distributor.hh \
+ dns.cc dns.hh \
+ dns_random.cc dns_random.hh \
+ dnsbackend.cc dnsbackend.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnspacket.cc dnspacket.hh \
+ dnsparser.cc \
+ dnsproxy.cc dnsproxy.hh \
+ dnsrecords.cc dnsrecords.hh \
+ dnssecinfra.cc dnssecinfra.hh \
+ dnsseckeeper.hh \
+ dnssecsigner.cc \
+ dnswriter.cc \
+ dynhandler.cc dynhandler.hh \
+ dynlistener.cc dynlistener.hh \
+ dynmessenger.hh \
+ ednssubnet.cc ednssubnet.hh \
+ gss_context.cc gss_context.hh \
+ iputils.cc iputils.hh \
+ ixfr.cc ixfr.hh \
+ json.cc json.hh \
+ lock.hh \
+ logger.cc logger.hh \
+ lua-auth.cc lua-auth.hh \
+ lua-pdns.cc lua-pdns.hh lua-iputils.cc \
+ mastercommunicator.cc \
+ md5.hh \
+ misc.cc misc.hh \
+ nameserver.cc nameserver.hh \
+ namespaces.hh \
+ nsecrecords.cc \
+ opensslsigners.cc opensslsigners.hh \
+ packetcache.cc packetcache.hh \
+ packethandler.cc packethandler.hh \
+ pdnsexception.hh \
+ qtype.cc qtype.hh \
+ randomhelper.cc \
+ rcpgenerator.cc \
+ receiver.cc \
+ resolver.cc resolver.hh \
+ responsestats.cc responsestats.hh responsestats-auth.cc \
+ rfc2136handler.cc \
+ secpoll-auth.cc secpoll-auth.hh \
+ serialtweaker.cc \
+ sha.hh \
+ signingpipe.cc signingpipe.hh \
+ sillyrecords.cc \
+ slavecommunicator.cc \
+ statbag.cc statbag.hh \
+ stubresolver.cc stubresolver.hh \
+ tcpreceiver.cc tcpreceiver.hh \
+ tsigverifier.cc tsigverifier.hh \
+ tkey.cc \
+ ueberbackend.cc ueberbackend.hh \
+ unix_semaphore.cc \
+ unix_utility.cc \
+ utility.hh \
+ version.cc version.hh \
+ webserver.cc webserver.hh \
+ ws-api.cc ws-api.hh \
+ ws-auth.cc ws-auth.hh \
+ zoneparser-tng.cc
+
+pdns_server_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(DYNLINKFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+pdns_server_LDADD = \
+ @moduleobjects@ \
+ @modulelibs@ \
+ $(LIBDL) \
+ $(YAHTTP_LIBS) \
+ $(JSON11_LIBS) \
+ $(LIBCRYPTO_LIBS) \
+ $(SYSTEMD_LIBS)
+
+if BOTAN110
+pdns_server_SOURCES += botan110signers.cc
+pdns_server_LDADD += $(BOTAN110_LIBS)
+endif
+
+if LIBSODIUM
+pdns_server_SOURCES += sodiumsigners.cc
+pdns_server_LDADD += $(LIBSODIUM_LIBS)
+endif
+
+if LIBDECAF
+pdns_server_SOURCES += decafsigners.cc
+pdns_server_LDADD += $(LIBDECAF_LIBS)
+endif
+
+if SQLITE3
+pdns_server_SOURCES += ssqlite3.cc ssqlite3.hh
+pdns_server_LDADD += $(SQLITE3_LIBS)
+endif
+
+if ORACLE
+pdns_server_LDADD += $(ORACLE_LIBS)
+endif
+
+if PKCS11
+pdns_server_SOURCES += pkcs11signers.cc pkcs11signers.hh
+pdns_server_LDADD += $(P11KIT1_LIBS)
+endif
+
+if LUA
+pdns_server_LDADD += $(LUA_LIBS)
+endif
+
+if GSS_TSIG
+pdns_server_LDADD += $(GSS_LIBS)
+endif
+
+pdnsutil_SOURCES = \
+ arguments.cc \
+ backends/gsql/gsqlbackend.cc backends/gsql/gsqlbackend.hh \
+ backends/gsql/ssql.hh \
+ base32.cc \
+ base64.cc base64.hh \
+ bindlexer.l \
+ bindparser.yy \
+ cachecleaner.hh \
+ dbdnsseckeeper.cc \
+ dnsbackend.cc \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnspacket.cc \
+ dnsparser.cc dnsparser.hh \
+ dns_random.cc \
+ dnsrecords.cc \
+ dnssecinfra.cc dnssecinfra.hh \
+ dnssecsigner.cc \
+ dnswriter.cc dnswriter.hh \
+ dynlistener.cc \
+ ednssubnet.cc \
+ gss_context.cc gss_context.hh \
+ iputils.cc iputils.hh \
+ json.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ opensslsigners.cc opensslsigners.hh \
+ packetcache.cc \
+ pdnsutil.cc \
+ qtype.cc \
+ randomhelper.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ serialtweaker.cc \
+ signingpipe.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ ueberbackend.cc \
+ unix_utility.cc \
+ zoneparser-tng.cc
+
+pdnsutil_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(DYNLINKFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+pdnsutil_LDADD = \
+ @moduleobjects@ \
+ @modulelibs@ \
+ $(YAHTTP_LIBS) \
+ $(JSON11_LIBS) \
+ $(LIBDL) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(LIBCRYPTO_LIBS)
+
+if BOTAN110
+pdnsutil_SOURCES += botan110signers.cc
+pdnsutil_LDADD += $(BOTAN110_LIBS)
+endif
+
+if LIBSODIUM
+pdnsutil_SOURCES += sodiumsigners.cc
+pdnsutil_LDADD += $(LIBSODIUM_LIBS)
+endif
+
+if LIBDECAF
+pdnsutil_SOURCES += decafsigners.cc
+pdnsutil_LDADD += $(LIBDECAF_LIBS)
+endif
+
+if SQLITE3
+pdnsutil_SOURCES += ssqlite3.cc ssqlite3.hh
+pdnsutil_LDADD += $(SQLITE3_LIBS)
+endif
+
+if ORACLE
+pdnsutil_LDADD += $(ORACLE_LIBS)
+endif
+
+if PKCS11
+pdnsutil_SOURCES += pkcs11signers.cc pkcs11signers.hh
+pdnsutil_LDADD += $(P11KIT1_LIBS)
+endif
+
+if GSS_TSIG
+pdnsutil_LDADD += $(GSS_LIBS)
+endif
+
+zone2sql_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dns.cc \
+ dns_random.cc \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ json.cc json.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2sql.cc \
+ zoneparser-tng.cc
+
+zone2sql_LDADD = $(LIBCRYPTO_LIBS) $(JSON11_LIBS)
+zone2sql_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+zone2json_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2json.cc \
+ zoneparser-tng.cc
+
+zone2json_LDADD = $(LIBCRYPTO_LIBS) $(JSON11_LIBS)
+zone2json_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+# pkglib_LTLIBRARIES = iputils.la
+# iputils_la_SOURCES = lua-iputils.cc
+# iputils_la_LDFLAGS= -module -avoid-version
+
+if LDAP
+bin_PROGRAMS += zone2ldap
+endif
+
+zone2ldap_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dns_random.cc \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2ldap.cc \
+ zoneparser-tng.cc
+
+zone2ldap_LDADD = $(LIBCRYPTO_LIBS)
+zone2ldap_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+sdig_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ ednssubnet.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sdig.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+sdig_LDADD = $(LIBCRYPTO_LIBS)
+sdig_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+calidns_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ calidns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ iputils.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+calidns_LDADD = $(LIBCRYPTO_LIBS)
+calidns_LDFLAGS = $(AM_LDFLAGS) $(THREADFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+dumresp_SOURCES = \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dumresp.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ statbag.cc \
+ unix_utility.cc \
+ qtype.cc
+
+kvresp_SOURCES = \
+ dnslabeltext.cc dnsname.cc dnsname.hh \
+ kvresp.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ statbag.cc \
+ unix_utility.cc \
+ qtype.cc
+
+stubquery_SOURCES = \
+ arguments.cc arguments.hh \
+ base32.cc \
+ base64.cc \
+ dns_random.cc \
+ dnslabeltext.cc \
+ dnsname.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ stubresolver.cc stubresolver.hh \
+ stubquery.cc \
+ unix_utility.cc
+
+stubquery_LDADD = $(LIBCRYPTO_LIBS)
+stubquery_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+saxfr_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dns_random.cc dns_random.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh \
+ gss_context.cc gss_context.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ saxfr.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+saxfr_LDADD = $(LIBCRYPTO_LIBS)
+saxfr_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+if PKCS11
+saxfr_SOURCES += pkcs11signers.cc pkcs11signers.hh
+saxfr_LDADD += $(P11KIT1_LIBS)
+endif
+
+if GSS_TSIG
+saxfr_LDADD += $(GSS_LIBS)
+endif
+
+
+ixplore_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dns_random.cc dns_random.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh \
+ gss_context.cc gss_context.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ resolver.cc \
+ ixfr.cc ixfr.hh \
+ ixplore.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ tsigverifier.cc tsigverifier.hh \
+ unix_utility.cc zoneparser-tng.cc
+
+ixplore_LDADD = $(LIBCRYPTO_LIBS)
+ixplore_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+if PKCS11
+ixplore_SOURCES += pkcs11signers.cc pkcs11signers.hh
+ixplore_LDADD += $(P11KIT1_LIBS)
+endif
+
+if GSS_TSIG
+ixplore_LDADD += $(GSS_LIBS)
+endif
+
+
+dnstcpbench_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnstcpbench.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+dnstcpbench_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnstcpbench_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+nsec3dig_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh \
+ gss_context.cc gss_context.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsec3dig.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+nsec3dig_LDADD = $(LIBCRYPTO_LIBS)
+nsec3dig_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+if PKCS11
+nsec3dig_SOURCES += pkcs11signers.cc pkcs11signers.hh
+nsec3dig_LDADD += $(P11KIT1_LIBS)
+endif
+
+if GSS_TSIG
+nsec3dig_LDADD += $(GSS_LIBS)
+endif
+
+toysdig_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dns_random.cc \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh \
+ ednssubnet.cc ednssubnet.hh \
+ filterpo.hh \
+ gss_context.cc gss_context.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ opensslsigners.cc opensslsigners.hh \
+ qtype.cc \
+ randomhelper.cc \
+ root-dnssec.hh \
+ rcpgenerator.cc rcpgenerator.hh \
+ rec-lua-conf.hh \
+ recursor_cache.hh \
+ sholder.hh \
+ sillyrecords.cc \
+ sortlist.hh \
+ sstuff.hh \
+ statbag.cc \
+ toysdig.cc \
+ unix_utility.cc \
+ validate.cc validate.hh
+
+
+toysdig_LDFLAGS = $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+toysdig_LDADD = $(LIBCRYPTO_LIBS)
+
+if GSS_TSIG
+toysdig_LDADD += $(GSS_LIBS)
+endif
+
+if BOTAN110
+toysdig_SOURCES += botan110signers.cc
+toysdig_LDADD += $(BOTAN110_LIBS)
+endif
+
+if PKCS11
+toysdig_SOURCES += pkcs11signers.cc pkcs11signers.hh
+toysdig_LDADD += $(P11KIT1_LIBS)
+endif
+
+tsig_tests_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dns_random.cc dns_random.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh \
+ gss_context.cc gss_context.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ randomhelper.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ resolver.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ tsig-tests.cc \
+ tsigverifier.cc tsigverifier.hh \
+ unix_utility.cc
+
+tsig_tests_LDADD = $(LIBCRYPTO_LIBS)
+tsig_tests_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+
+if PKCS11
+tsig_tests_SOURCES += pkcs11signers.cc pkcs11signers.hh
+tsig_tests_LDADD += $(P11KIT1_LIBS)
+endif
+
+if GSS_TSIG
+tsig_tests_LDADD += $(GSS_LIBS)
+endif
+
+speedtest_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ speedtest.cc \
+ statbag.cc \
+ unix_utility.cc
+
+speedtest_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+speedtest_LDADD = $(LIBCRYPTO_LIBS) \
+ $(RT_LIBS)
+
+dnswasher_SOURCES = \
+ dnslabeltext.cc \
+ dnsname.hh dnsname.cc \
+ dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnswasher.cc \
+ dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ qtype.cc \
+ statbag.cc \
+ unix_utility.cc
+
+
+dnsbulktest_SOURCES = \
+ base32.cc \
+ base64.cc \
+ dnsbulktest.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+dnsbulktest_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsbulktest_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+comfun_SOURCES = \
+ base32.cc \
+ base64.cc \
+ comfun.cc \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zoneparser-tng.cc zoneparser-tng.hh
+
+comfun_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+comfun_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+
+dnsscan_SOURCES = \
+ anadns.hh \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsscan.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsscan_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsscan_LDADD = $(LIBCRYPTO_LIBS)
+
+dnsreplay_SOURCES = \
+ anadns.hh \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsreplay.cc \
+ dnswriter.cc dnswriter.hh \
+ ednssubnet.cc ednssubnet.hh \
+ ednsoptions.cc ednsoptions.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsreplay_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsreplay_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+nproxy_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ mplexer.hh \
+ nproxy.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ selectmplexer.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+nproxy_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+nproxy_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+pdns_notify_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ notify.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ selectmplexer.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+pdns_notify_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+pdns_notify_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+dnsscope_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsscope.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ statnode.cc statnode.hh \
+ unix_utility.cc \
+ utility.hh
+
+dnsscope_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsscope_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+dnsgram_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnsgram.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsgram_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsgram_LDADD = \
+ $(LIBCRYPTO_LIBS)
+
+dnsdemog_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnsdemog.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsdemog_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsdemog_LDADD = \
+ $(LIBCRYPTO_LIBS)
+
+if HAVE_PROTOBUF
+if HAVE_PROTOC
+bin_PROGRAMS += dnspcap2protobuf
+
+dnsmessage.pb.cc: dnsmessage.proto
+ $(AM_V_GEN)$(PROTOC) --cpp_out=./ $<
+
+BUILT_SOURCES += dnsmessage.pb.cc
+dnspcap2protobuf.$(OBJEXT): dnsmessage.pb.cc
+
+dnspcap2protobuf_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnspcap2protobuf.cc \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ gettime.cc gettime.hh \
+ iputils.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ protobuf.cc protobuf.hh \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+nodist_dnspcap2protobuf_SOURCES=dnsmessage.pb.cc dnsmessage.pb.h
+
+dnspcap2protobuf_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnspcap2protobuf_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(PROTOBUF_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+endif
+endif
+
+pdns.conf-dist: pdns_server
+ $(AM_V_GEN)./pdns_server --no-config --config 2>/dev/null > $@
+
+testrunner_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bindlexer.l \
+ bindparser.yy \
+ dbdnsseckeeper.cc \
+ dns.cc \
+ dns_random.cc \
+ dnsbackend.cc \
+ dnslabeltext.cc \
+ dnsname.cc \
+ dnsname.hh \
+ dnspacket.cc \
+ dnsparser.hh dnsparser.cc \
+ dnsrecords.cc \
+ dnssecinfra.cc \
+ dnssecsigner.cc \
+ dnswriter.cc \
+ ednsoptions.cc ednsoptions.hh \
+ ednssubnet.cc \
+ gettime.cc gettime.hh \
+ gss_context.cc gss_context.hh \
+ iputils.cc \
+ logger.cc \
+ misc.cc \
+ nameserver.cc \
+ nsecrecords.cc \
+ packetcache.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ recpacketcache.cc recpacketcache.hh \
+ rec-protobuf.hh \
+ responsestats.cc \
+ responsestats-auth.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ test-arguments_cc.cc \
+ test-base32_cc.cc \
+ test-base64_cc.cc \
+ test-bindparser_cc.cc \
+ test-delaypipe_hh.cc \
+ test-distributor_hh.cc \
+ test-dns_random_hh.cc \
+ test-dnsname_cc.cc \
+ test-dnsparser_hh.cc \
+ test-dnsrecords_cc.cc \
+ test-iputils_hh.cc \
+ test-md5_hh.cc \
+ test-misc_hh.cc \
+ test-nameserver_cc.cc \
+ test-nmtree.cc \
+ test-packetcache_cc.cc \
+ test-rcpgenerator_cc.cc \
+ test-recpacketcache_cc.cc \
+ test-signers.cc \
+ test-sha_hh.cc \
+ test-statbag_cc.cc \
+ test-zoneparser_tng_cc.cc \
+ testrunner.cc \
+ ueberbackend.cc \
+ unix_utility.cc \
+ zoneparser-tng.cc zoneparser-tng.hh
+
+testrunner_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS)
+
+testrunner_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
+ $(RT_LIBS) \
+ $(LIBDL)
+
+if HAVE_PROTOBUF
+if HAVE_PROTOC
+nodist_testrunner_SOURCES = \
+ dnsmessage.pb.cc dnsmessage.pb.h
+
+testrunner_LDADD += \
+ $(PROTOBUF_LIBS)
+
+recpacketcache.$(OBJEXT): dnsmessage.pb.cc
+endif
+endif
+
+if PKCS11
+testrunner_SOURCES += pkcs11signers.cc pkcs11signers.hh
+testrunner_LDADD += $(P11KIT1_LIBS)
+endif
+
+if LIBSODIUM
+testrunner_SOURCES += sodiumsigners.cc
+testrunner_LDADD += $(LIBSODIUM_LIBS)
+endif
+
+if LIBDECAF
+testrunner_SOURCES += decafsigners.cc
+testrunner_LDADD += $(LIBDECAF_LIBS)
+endif
+
+pdns_control_SOURCES = \
+ arguments.cc \
+ dynloader.cc \
+ dynmessenger.cc \
+ logger.cc \
+ misc.cc \
+ qtype.cc \
+ statbag.cc \
+ unix_utility.cc \
+ dnsname.cc \
+ dnslabeltext.cc
+
+if UNIT_TESTS
+
+if HAVE_BOOST_GE_148
+TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)'
+TESTS=testrunner
+else
+check-local:
+ @echo "Unit tests disabled, boost is too old"
+endif
+
+else
+check-local:
+ @echo "Unit tests are not enabled"
+ @echo "Run ./configure --enable-unit-tests"
+endif
+
+dnslabeltext.cc: dnslabeltext.rl
+ $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc
+
+bind-dnssec.schema.sqlite3.sql.h: bind-dnssec.schema.sqlite3.sql
+ ( echo 'static char sqlCreate[] __attribute__((unused))=' ; sed 's/$$/"/g' $< | sed 's/^/"/g' ; echo ';' ) > $@
+
+# for bindparser.h/hh
+.hh.h:
+ cp $< $@
+
+bindlexer.$(OBJEXT): bindparser.h
+
+curl_verbose = $(curl_verbose_$(V))
+curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY))
+curl_verbose_0 = @echo " CURL " $@;
+$(srcdir)/effective_tld_names.dat:
+ $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi
+
+pubsuffix.cc: $(srcdir)/effective_tld_names.dat
+ $(AM_V_GEN)./mkpubsuffixcc
+
+pdns_recursor rec_control:
+ @echo "Please build the recursor from the recursordist/ dir"
+ @exit 1
+
+dnsdist:
+ @echo "Please build dnsdist from the dnsdistdist/ dir"
+ @exit 1
+
+if HAVE_SYSTEMD
+pdns.service: pdns.service.in
+ $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' < $< > $@
+
+pdns@.service: pdns.service
+ $(AM_V_GEN)sed -e 's!/pdns_server!& --config-name=%i!' \
+ -e 's!Authoritative Server!& %i!' \
+ < $< > $@
+
+systemdsystemunitdir = $(SYSTEMD_DIR)
+
+systemdsystemunit_DATA = \
+ pdns.service \
+ pdns@.service
+endif
--- /dev/null
+# Makefile.in generated by automake 1.14.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994-2013 Free Software Foundation, Inc.
+
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+@SET_MAKE@
+
+
+
+VPATH = @srcdir@
+am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)'
+am__make_running_with_option = \
+ case $${target_option-} in \
+ ?) ;; \
+ *) echo "am__make_running_with_option: internal error: invalid" \
+ "target option '$${target_option-}' specified" >&2; \
+ exit 1;; \
+ esac; \
+ has_opt=no; \
+ sane_makeflags=$$MAKEFLAGS; \
+ if $(am__is_gnu_make); then \
+ sane_makeflags=$$MFLAGS; \
+ else \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ bs=\\; \
+ sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \
+ | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \
+ esac; \
+ fi; \
+ skip_next=no; \
+ strip_trailopt () \
+ { \
+ flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \
+ }; \
+ for flg in $$sane_makeflags; do \
+ test $$skip_next = yes && { skip_next=no; continue; }; \
+ case $$flg in \
+ *=*|--*) continue;; \
+ -*I) strip_trailopt 'I'; skip_next=yes;; \
+ -*I?*) strip_trailopt 'I';; \
+ -*O) strip_trailopt 'O'; skip_next=yes;; \
+ -*O?*) strip_trailopt 'O';; \
+ -*l) strip_trailopt 'l'; skip_next=yes;; \
+ -*l?*) strip_trailopt 'l';; \
+ -[dEDm]) skip_next=yes;; \
+ -[JT]) skip_next=yes;; \
+ esac; \
+ case $$flg in \
+ *$$target_option*) has_opt=yes; break;; \
+ esac; \
+ done; \
+ test $$has_opt = yes
+am__make_dryrun = (target_option=n; $(am__make_running_with_option))
+am__make_keepgoing = (target_option=k; $(am__make_running_with_option))
+pkgdatadir = $(datadir)/@PACKAGE@
+pkgincludedir = $(includedir)/@PACKAGE@
+pkglibdir = $(libdir)/@PACKAGE@
+pkglibexecdir = $(libexecdir)/@PACKAGE@
+am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd
+install_sh_DATA = $(install_sh) -c -m 644
+install_sh_PROGRAM = $(install_sh) -c
+install_sh_SCRIPT = $(install_sh) -c
+INSTALL_HEADER = $(INSTALL_DATA)
+transform = $(program_transform_name)
+NORMAL_INSTALL = :
+PRE_INSTALL = :
+POST_INSTALL = :
+NORMAL_UNINSTALL = :
+PRE_UNINSTALL = :
+POST_UNINSTALL = :
+build_triplet = @build@
+host_triplet = @host@
+@BOTAN110_TRUE@am__append_1 = $(BOTAN110_CFLAGS)
+@PKCS11_TRUE@am__append_2 = $(P11KIT1_CFLAGS)
+@SQLITE3_TRUE@am__append_3 = $(SQLITE3_CFLAGS)
+@LUA_TRUE@am__append_4 = $(LUA_CFLAGS)
+@GSS_TSIG_TRUE@am__append_5 = $(GSS_CFLAGS)
+sbin_PROGRAMS = pdns_server$(EXEEXT)
+bin_PROGRAMS = pdns_control$(EXEEXT) pdnsutil$(EXEEXT) \
+ zone2sql$(EXEEXT) zone2json$(EXEEXT) $(am__EXEEXT_1) \
+ $(am__EXEEXT_2) $(am__EXEEXT_3) $(am__EXEEXT_4) \
+ $(am__EXEEXT_5)
+@TOOLS_TRUE@am__append_6 = \
+@TOOLS_TRUE@ dnsgram \
+@TOOLS_TRUE@ dnsreplay \
+@TOOLS_TRUE@ dnsscan \
+@TOOLS_TRUE@ dnsscope \
+@TOOLS_TRUE@ dnswasher \
+@TOOLS_TRUE@ dumresp \
+@TOOLS_TRUE@ pdns_notify \
+@TOOLS_TRUE@ nproxy \
+@TOOLS_TRUE@ nsec3dig \
+@TOOLS_TRUE@ saxfr \
+@TOOLS_TRUE@ stubquery \
+@TOOLS_TRUE@ ixplore \
+@TOOLS_TRUE@ sdig
+
+@HAVE_RECVMMSG_TRUE@@TOOLS_TRUE@am__append_7 = calidns
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@am__append_8 = \
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@ dnsbulktest \
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@ dnstcpbench
+
+EXTRA_PROGRAMS = calidns$(EXEEXT) comfun$(EXEEXT) dnsbulktest$(EXEEXT) \
+ dnsdemog$(EXEEXT) dnsgram$(EXEEXT) dnsreplay$(EXEEXT) \
+ dnsscan$(EXEEXT) dnsscope$(EXEEXT) dnstcpbench$(EXEEXT) \
+ dnswasher$(EXEEXT) dumresp$(EXEEXT) kvresp$(EXEEXT) \
+ ixplore$(EXEEXT) pdns_notify$(EXEEXT) nproxy$(EXEEXT) \
+ nsec3dig$(EXEEXT) saxfr$(EXEEXT) stubquery$(EXEEXT) \
+ sdig$(EXEEXT) speedtest$(EXEEXT) testrunner$(EXEEXT) \
+ toysdig$(EXEEXT) tsig-tests$(EXEEXT) zone2ldap$(EXEEXT)
+@BOTAN110_TRUE@am__append_9 = botan110signers.cc
+@BOTAN110_TRUE@am__append_10 = $(BOTAN110_LIBS)
+@LIBSODIUM_TRUE@am__append_11 = sodiumsigners.cc
+@LIBSODIUM_TRUE@am__append_12 = $(LIBSODIUM_LIBS)
+@LIBDECAF_TRUE@am__append_13 = decafsigners.cc
+@LIBDECAF_TRUE@am__append_14 = $(LIBDECAF_LIBS)
+@SQLITE3_TRUE@am__append_15 = ssqlite3.cc ssqlite3.hh
+@SQLITE3_TRUE@am__append_16 = $(SQLITE3_LIBS)
+@ORACLE_TRUE@am__append_17 = $(ORACLE_LIBS)
+@PKCS11_TRUE@am__append_18 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_19 = $(P11KIT1_LIBS)
+@LUA_TRUE@am__append_20 = $(LUA_LIBS)
+@GSS_TSIG_TRUE@am__append_21 = $(GSS_LIBS)
+@BOTAN110_TRUE@am__append_22 = botan110signers.cc
+@BOTAN110_TRUE@am__append_23 = $(BOTAN110_LIBS)
+@LIBSODIUM_TRUE@am__append_24 = sodiumsigners.cc
+@LIBSODIUM_TRUE@am__append_25 = $(LIBSODIUM_LIBS)
+@LIBDECAF_TRUE@am__append_26 = decafsigners.cc
+@LIBDECAF_TRUE@am__append_27 = $(LIBDECAF_LIBS)
+@SQLITE3_TRUE@am__append_28 = ssqlite3.cc ssqlite3.hh
+@SQLITE3_TRUE@am__append_29 = $(SQLITE3_LIBS)
+@ORACLE_TRUE@am__append_30 = $(ORACLE_LIBS)
+@PKCS11_TRUE@am__append_31 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_32 = $(P11KIT1_LIBS)
+@GSS_TSIG_TRUE@am__append_33 = $(GSS_LIBS)
+
+# pkglib_LTLIBRARIES = iputils.la
+# iputils_la_SOURCES = lua-iputils.cc
+# iputils_la_LDFLAGS= -module -avoid-version
+@LDAP_TRUE@am__append_34 = zone2ldap
+@PKCS11_TRUE@am__append_35 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_36 = $(P11KIT1_LIBS)
+@GSS_TSIG_TRUE@am__append_37 = $(GSS_LIBS)
+@PKCS11_TRUE@am__append_38 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_39 = $(P11KIT1_LIBS)
+@GSS_TSIG_TRUE@am__append_40 = $(GSS_LIBS)
+@PKCS11_TRUE@am__append_41 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_42 = $(P11KIT1_LIBS)
+@GSS_TSIG_TRUE@am__append_43 = $(GSS_LIBS)
+@GSS_TSIG_TRUE@am__append_44 = $(GSS_LIBS)
+@BOTAN110_TRUE@am__append_45 = botan110signers.cc
+@BOTAN110_TRUE@am__append_46 = $(BOTAN110_LIBS)
+@PKCS11_TRUE@am__append_47 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_48 = $(P11KIT1_LIBS)
+@PKCS11_TRUE@am__append_49 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_50 = $(P11KIT1_LIBS)
+@GSS_TSIG_TRUE@am__append_51 = $(GSS_LIBS)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_52 = dnspcap2protobuf
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_53 = dnsmessage.pb.cc
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__append_54 = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(PROTOBUF_LIBS)
+
+@PKCS11_TRUE@am__append_55 = pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__append_56 = $(P11KIT1_LIBS)
+@LIBSODIUM_TRUE@am__append_57 = sodiumsigners.cc
+@LIBSODIUM_TRUE@am__append_58 = $(LIBSODIUM_LIBS)
+@LIBDECAF_TRUE@am__append_59 = decafsigners.cc
+@LIBDECAF_TRUE@am__append_60 = $(LIBDECAF_LIBS)
+@HAVE_BOOST_GE_148_TRUE@@UNIT_TESTS_TRUE@TESTS = testrunner$(EXEEXT)
+subdir = pdns
+DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \
+ $(srcdir)/pdns.init.in bindlexer.c bindparser.hh bindparser.cc \
+ $(top_srcdir)/build-aux/depcomp $(top_srcdir)/build-aux/ylwrap \
+ $(top_srcdir)/build-aux/test-driver
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = \
+ $(top_srcdir)/m4/ax_arg_default_enable_disable.m4 \
+ $(top_srcdir)/m4/ax_check_link_flag.m4 \
+ $(top_srcdir)/m4/ax_cxx_compile_stdcxx_11.m4 \
+ $(top_srcdir)/m4/boost.m4 $(top_srcdir)/m4/libtool.m4 \
+ $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
+ $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
+ $(top_srcdir)/m4/pdns_check_bison.m4 \
+ $(top_srcdir)/m4/pdns_check_cdb.m4 \
+ $(top_srcdir)/m4/pdns_check_clock_gettime.m4 \
+ $(top_srcdir)/m4/pdns_check_curl_program.m4 \
+ $(top_srcdir)/m4/pdns_check_flex.m4 \
+ $(top_srcdir)/m4/pdns_check_ldap.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto.m4 \
+ $(top_srcdir)/m4/pdns_check_libcrypto_ecdsa.m4 \
+ $(top_srcdir)/m4/pdns_check_libdecaf.m4 \
+ $(top_srcdir)/m4/pdns_check_libsodium.m4 \
+ $(top_srcdir)/m4/pdns_check_lua_hpp.m4 \
+ $(top_srcdir)/m4/pdns_check_network_libs.m4 \
+ $(top_srcdir)/m4/pdns_check_opendbx.m4 \
+ $(top_srcdir)/m4/pdns_check_os.m4 \
+ $(top_srcdir)/m4/pdns_check_pandoc.m4 \
+ $(top_srcdir)/m4/pdns_check_ragel.m4 \
+ $(top_srcdir)/m4/pdns_check_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_d_fortify_source.m4 \
+ $(top_srcdir)/m4/pdns_enable_botan.m4 \
+ $(top_srcdir)/m4/pdns_enable_coverage.m4 \
+ $(top_srcdir)/m4/pdns_enable_gss_tsig.m4 \
+ $(top_srcdir)/m4/pdns_enable_malloc_trace.m4 \
+ $(top_srcdir)/m4/pdns_enable_p11kit.m4 \
+ $(top_srcdir)/m4/pdns_enable_remotebackend_zeromq.m4 \
+ $(top_srcdir)/m4/pdns_enable_reproducible.m4 \
+ $(top_srcdir)/m4/pdns_enable_sanitizers.m4 \
+ $(top_srcdir)/m4/pdns_enable_unit_tests.m4 \
+ $(top_srcdir)/m4/pdns_enable_verbose_logging.m4 \
+ $(top_srcdir)/m4/pdns_from_git.m4 \
+ $(top_srcdir)/m4/pdns_param_ssp_buffer_size.m4 \
+ $(top_srcdir)/m4/pdns_pie.m4 $(top_srcdir)/m4/pdns_relro.m4 \
+ $(top_srcdir)/m4/pdns_stack_protector.m4 \
+ $(top_srcdir)/m4/pdns_with_geo.m4 \
+ $(top_srcdir)/m4/pdns_with_lua.m4 \
+ $(top_srcdir)/m4/pdns_with_luajit.m4 \
+ $(top_srcdir)/m4/pdns_with_mysql.m4 \
+ $(top_srcdir)/m4/pdns_with_oracle.m4 \
+ $(top_srcdir)/m4/pdns_with_postgresql.m4 \
+ $(top_srcdir)/m4/pdns_with_protobuf.m4 \
+ $(top_srcdir)/m4/pdns_with_sqlite3.m4 \
+ $(top_srcdir)/m4/pdns_with_unixodbc.m4 \
+ $(top_srcdir)/m4/systemd.m4 $(top_srcdir)/m4/tm-gmtoff.m4 \
+ $(top_srcdir)/m4/warnings.m4 $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(install_sh) -d
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = pdns.init
+CONFIG_CLEAN_VPATH_FILES =
+@TOOLS_TRUE@am__EXEEXT_1 = dnsgram$(EXEEXT) dnsreplay$(EXEEXT) \
+@TOOLS_TRUE@ dnsscan$(EXEEXT) dnsscope$(EXEEXT) \
+@TOOLS_TRUE@ dnswasher$(EXEEXT) dumresp$(EXEEXT) \
+@TOOLS_TRUE@ pdns_notify$(EXEEXT) nproxy$(EXEEXT) \
+@TOOLS_TRUE@ nsec3dig$(EXEEXT) saxfr$(EXEEXT) \
+@TOOLS_TRUE@ stubquery$(EXEEXT) ixplore$(EXEEXT) sdig$(EXEEXT)
+@HAVE_RECVMMSG_TRUE@@TOOLS_TRUE@am__EXEEXT_2 = calidns$(EXEEXT)
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@am__EXEEXT_3 = \
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@ dnsbulktest$(EXEEXT) \
+@HAVE_BOOST_GE_148_TRUE@@TOOLS_TRUE@ dnstcpbench$(EXEEXT)
+@LDAP_TRUE@am__EXEEXT_4 = zone2ldap$(EXEEXT)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__EXEEXT_5 = dnspcap2protobuf$(EXEEXT)
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" \
+ "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(systemdsystemunitdir)"
+PROGRAMS = $(bin_PROGRAMS) $(sbin_PROGRAMS)
+am_calidns_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ calidns.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) \
+ iputils.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+calidns_OBJECTS = $(am_calidns_OBJECTS)
+am__DEPENDENCIES_1 =
+calidns_DEPENDENCIES = $(am__DEPENDENCIES_1)
+AM_V_lt = $(am__v_lt_@AM_V@)
+am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
+am__v_lt_0 = --silent
+am__v_lt_1 =
+calidns_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(calidns_LDFLAGS) $(LDFLAGS) -o $@
+am_comfun_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) comfun.$(OBJEXT) \
+ dns.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT)
+comfun_OBJECTS = $(am_comfun_OBJECTS)
+comfun_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+comfun_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(comfun_LDFLAGS) $(LDFLAGS) -o $@
+am_dnsbulktest_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnsbulktest.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT)
+dnsbulktest_OBJECTS = $(am_dnsbulktest_OBJECTS)
+dnsbulktest_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+dnsbulktest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsbulktest_LDFLAGS) $(LDFLAGS) -o $@
+am_dnsdemog_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnsdemog.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnspcap.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnswriter.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+dnsdemog_OBJECTS = $(am_dnsdemog_OBJECTS)
+dnsdemog_DEPENDENCIES = $(am__DEPENDENCIES_1)
+dnsdemog_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsdemog_LDFLAGS) $(LDFLAGS) -o $@
+am_dnsgram_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnsgram.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnspcap.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnswriter.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+dnsgram_OBJECTS = $(am_dnsgram_OBJECTS)
+dnsgram_DEPENDENCIES = $(am__DEPENDENCIES_1)
+dnsgram_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsgram_LDFLAGS) $(LDFLAGS) -o $@
+am__dnspcap2protobuf_SOURCES_DIST = base32.cc base64.cc base64.hh \
+ dnslabeltext.cc dnsname.cc dnsname.hh dnsparser.cc \
+ dnsparser.hh dnspcap.cc dnspcap.hh dnspcap2protobuf.cc \
+ dnsrecords.cc dnswriter.cc dnswriter.hh gettime.cc gettime.hh \
+ iputils.cc logger.cc misc.cc nsecrecords.cc protobuf.cc \
+ protobuf.hh qtype.cc rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc statbag.cc unix_utility.cc utility.hh
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am_dnspcap2protobuf_OBJECTS = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ base32.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ base64.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnslabeltext.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsname.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsparser.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnspcap.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnspcap2protobuf.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsrecords.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnswriter.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ gettime.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ iputils.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ logger.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ misc.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ nsecrecords.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ protobuf.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ qtype.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ rcpgenerator.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ sillyrecords.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ statbag.$(OBJEXT) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ unix_utility.$(OBJEXT)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_dnspcap2protobuf_OBJECTS = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsmessage.pb.$(OBJEXT)
+dnspcap2protobuf_OBJECTS = $(am_dnspcap2protobuf_OBJECTS) \
+ $(nodist_dnspcap2protobuf_OBJECTS)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnspcap2protobuf_DEPENDENCIES = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(am__DEPENDENCIES_1) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(am__DEPENDENCIES_1)
+dnspcap2protobuf_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX \
+ $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CXXLD) \
+ $(AM_CXXFLAGS) $(CXXFLAGS) $(dnspcap2protobuf_LDFLAGS) \
+ $(LDFLAGS) -o $@
+am_dnsreplay_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnspcap.$(OBJEXT) dnsrecords.$(OBJEXT) dnsreplay.$(OBJEXT) \
+ dnswriter.$(OBJEXT) ednssubnet.$(OBJEXT) ednsoptions.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT)
+dnsreplay_OBJECTS = $(am_dnsreplay_OBJECTS)
+dnsreplay_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+dnsreplay_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsreplay_LDFLAGS) $(LDFLAGS) -o $@
+am_dnsscan_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnspcap.$(OBJEXT) dnsrecords.$(OBJEXT) dnsscan.$(OBJEXT) \
+ dnswriter.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+dnsscan_OBJECTS = $(am_dnsscan_OBJECTS)
+dnsscan_DEPENDENCIES = $(am__DEPENDENCIES_1)
+dnsscan_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsscan_LDFLAGS) $(LDFLAGS) -o $@
+am_dnsscope_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) dns.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnsparser.$(OBJEXT) dnspcap.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnsscope.$(OBJEXT) dnswriter.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) statnode.$(OBJEXT) unix_utility.$(OBJEXT)
+dnsscope_OBJECTS = $(am_dnsscope_OBJECTS)
+dnsscope_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+dnsscope_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnsscope_LDFLAGS) $(LDFLAGS) -o $@
+am_dnstcpbench_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnstcpbench.$(OBJEXT) dnswriter.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT)
+dnstcpbench_OBJECTS = $(am_dnstcpbench_OBJECTS)
+dnstcpbench_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+dnstcpbench_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(dnstcpbench_LDFLAGS) $(LDFLAGS) -o $@
+am_dnswasher_OBJECTS = dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnspcap.$(OBJEXT) dnswasher.$(OBJEXT) logger.$(OBJEXT) \
+ misc.$(OBJEXT) qtype.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+dnswasher_OBJECTS = $(am_dnswasher_OBJECTS)
+dnswasher_LDADD = $(LDADD)
+am_dumresp_OBJECTS = dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dumresp.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) qtype.$(OBJEXT)
+dumresp_OBJECTS = $(am_dumresp_OBJECTS)
+dumresp_LDADD = $(LDADD)
+am__ixplore_SOURCES_DIST = arguments.cc base32.cc base64.cc base64.hh \
+ dns.cc dns_random.cc dns_random.hh dnslabeltext.cc dnsname.cc \
+ dnsname.hh dnsparser.cc dnsparser.hh dnsrecords.cc \
+ dnssecinfra.cc dnswriter.cc dnswriter.hh gss_context.cc \
+ gss_context.hh logger.cc misc.cc misc.hh nsecrecords.cc \
+ qtype.cc rcpgenerator.cc rcpgenerator.hh resolver.cc ixfr.cc \
+ ixfr.hh ixplore.cc sillyrecords.cc sstuff.hh statbag.cc \
+ tsigverifier.cc tsigverifier.hh unix_utility.cc \
+ zoneparser-tng.cc pkcs11signers.cc pkcs11signers.hh
+@PKCS11_TRUE@am__objects_1 = pkcs11signers.$(OBJEXT)
+am_ixplore_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \
+ gss_context.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ resolver.$(OBJEXT) ixfr.$(OBJEXT) ixplore.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ tsigverifier.$(OBJEXT) unix_utility.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT) $(am__objects_1)
+ixplore_OBJECTS = $(am_ixplore_OBJECTS)
+@PKCS11_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+@GSS_TSIG_TRUE@am__DEPENDENCIES_3 = $(am__DEPENDENCIES_1)
+ixplore_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3)
+ixplore_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(ixplore_LDFLAGS) $(LDFLAGS) -o $@
+am_kvresp_OBJECTS = dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ kvresp.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) qtype.$(OBJEXT)
+kvresp_OBJECTS = $(am_kvresp_OBJECTS)
+kvresp_LDADD = $(LDADD)
+am_nproxy_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) logger.$(OBJEXT) \
+ misc.$(OBJEXT) nproxy.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) selectmplexer.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+nproxy_OBJECTS = $(am_nproxy_OBJECTS)
+nproxy_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+nproxy_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(nproxy_LDFLAGS) $(LDFLAGS) -o $@
+am__nsec3dig_SOURCES_DIST = base32.cc base64.cc base64.hh dnsname.cc \
+ dnsname.hh dnslabeltext.cc dnsparser.cc dnsparser.hh \
+ dnsrecords.cc dnssecinfra.cc dnswriter.cc dnswriter.hh \
+ gss_context.cc gss_context.hh logger.cc misc.cc misc.hh \
+ nsec3dig.cc nsecrecords.cc qtype.cc rcpgenerator.cc \
+ rcpgenerator.hh sillyrecords.cc sstuff.hh statbag.cc \
+ unix_utility.cc pkcs11signers.cc pkcs11signers.hh
+am_nsec3dig_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \
+ gss_context.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsec3dig.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) $(am__objects_1)
+nsec3dig_OBJECTS = $(am_nsec3dig_OBJECTS)
+nsec3dig_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3)
+nsec3dig_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(nsec3dig_LDFLAGS) $(LDFLAGS) -o $@
+am_pdns_control_OBJECTS = arguments.$(OBJEXT) dynloader.$(OBJEXT) \
+ dynmessenger.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ qtype.$(OBJEXT) statbag.$(OBJEXT) unix_utility.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnslabeltext.$(OBJEXT)
+pdns_control_OBJECTS = $(am_pdns_control_OBJECTS)
+pdns_control_LDADD = $(LDADD)
+am_pdns_notify_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) dns.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnswriter.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ notify.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) selectmplexer.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+pdns_notify_OBJECTS = $(am_pdns_notify_OBJECTS)
+pdns_notify_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+pdns_notify_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(pdns_notify_LDFLAGS) $(LDFLAGS) -o $@
+am__pdns_server_SOURCES_DIST = arguments.cc arguments.hh \
+ auth-carbon.cc backends/gsql/gsqlbackend.cc \
+ backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh base32.cc \
+ base32.hh base64.cc base64.hh bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l bindparser.cc cachecleaner.hh comment.hh \
+ common_startup.cc common_startup.hh communicator.cc \
+ communicator.hh dbdnsseckeeper.cc distributor.hh dns.cc dns.hh \
+ dns_random.cc dns_random.hh dnsbackend.cc dnsbackend.hh \
+ dnslabeltext.cc dnsname.cc dnsname.hh dnspacket.cc \
+ dnspacket.hh dnsparser.cc dnsproxy.cc dnsproxy.hh \
+ dnsrecords.cc dnsrecords.hh dnssecinfra.cc dnssecinfra.hh \
+ dnsseckeeper.hh dnssecsigner.cc dnswriter.cc dynhandler.cc \
+ dynhandler.hh dynlistener.cc dynlistener.hh dynmessenger.hh \
+ ednssubnet.cc ednssubnet.hh gss_context.cc gss_context.hh \
+ iputils.cc iputils.hh ixfr.cc ixfr.hh json.cc json.hh lock.hh \
+ logger.cc logger.hh lua-auth.cc lua-auth.hh lua-pdns.cc \
+ lua-pdns.hh lua-iputils.cc mastercommunicator.cc md5.hh \
+ misc.cc misc.hh nameserver.cc nameserver.hh namespaces.hh \
+ nsecrecords.cc opensslsigners.cc opensslsigners.hh \
+ packetcache.cc packetcache.hh packethandler.cc \
+ packethandler.hh pdnsexception.hh qtype.cc qtype.hh \
+ randomhelper.cc rcpgenerator.cc receiver.cc resolver.cc \
+ resolver.hh responsestats.cc responsestats.hh \
+ responsestats-auth.cc rfc2136handler.cc secpoll-auth.cc \
+ secpoll-auth.hh serialtweaker.cc sha.hh signingpipe.cc \
+ signingpipe.hh sillyrecords.cc slavecommunicator.cc statbag.cc \
+ statbag.hh stubresolver.cc stubresolver.hh tcpreceiver.cc \
+ tcpreceiver.hh tsigverifier.cc tsigverifier.hh tkey.cc \
+ ueberbackend.cc ueberbackend.hh unix_semaphore.cc \
+ unix_utility.cc utility.hh version.cc version.hh webserver.cc \
+ webserver.hh ws-api.cc ws-api.hh ws-auth.cc ws-auth.hh \
+ zoneparser-tng.cc botan110signers.cc sodiumsigners.cc \
+ decafsigners.cc ssqlite3.cc ssqlite3.hh pkcs11signers.cc \
+ pkcs11signers.hh
+am__dirstamp = $(am__leading_dot)dirstamp
+@BOTAN110_TRUE@am__objects_2 = botan110signers.$(OBJEXT)
+@LIBSODIUM_TRUE@am__objects_3 = sodiumsigners.$(OBJEXT)
+@LIBDECAF_TRUE@am__objects_4 = decafsigners.$(OBJEXT)
+@SQLITE3_TRUE@am__objects_5 = ssqlite3.$(OBJEXT)
+am_pdns_server_OBJECTS = arguments.$(OBJEXT) auth-carbon.$(OBJEXT) \
+ backends/gsql/gsqlbackend.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ common_startup.$(OBJEXT) communicator.$(OBJEXT) \
+ dbdnsseckeeper.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \
+ dnsbackend.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnspacket.$(OBJEXT) dnsparser.$(OBJEXT) dnsproxy.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) \
+ dnssecsigner.$(OBJEXT) dnswriter.$(OBJEXT) \
+ dynhandler.$(OBJEXT) dynlistener.$(OBJEXT) \
+ ednssubnet.$(OBJEXT) gss_context.$(OBJEXT) iputils.$(OBJEXT) \
+ ixfr.$(OBJEXT) json.$(OBJEXT) logger.$(OBJEXT) \
+ lua-auth.$(OBJEXT) lua-pdns.$(OBJEXT) lua-iputils.$(OBJEXT) \
+ mastercommunicator.$(OBJEXT) misc.$(OBJEXT) \
+ nameserver.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ opensslsigners.$(OBJEXT) packetcache.$(OBJEXT) \
+ packethandler.$(OBJEXT) qtype.$(OBJEXT) randomhelper.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) receiver.$(OBJEXT) resolver.$(OBJEXT) \
+ responsestats.$(OBJEXT) responsestats-auth.$(OBJEXT) \
+ rfc2136handler.$(OBJEXT) secpoll-auth.$(OBJEXT) \
+ serialtweaker.$(OBJEXT) signingpipe.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) slavecommunicator.$(OBJEXT) \
+ statbag.$(OBJEXT) stubresolver.$(OBJEXT) tcpreceiver.$(OBJEXT) \
+ tsigverifier.$(OBJEXT) tkey.$(OBJEXT) ueberbackend.$(OBJEXT) \
+ unix_semaphore.$(OBJEXT) unix_utility.$(OBJEXT) \
+ version.$(OBJEXT) webserver.$(OBJEXT) ws-api.$(OBJEXT) \
+ ws-auth.$(OBJEXT) zoneparser-tng.$(OBJEXT) $(am__objects_2) \
+ $(am__objects_3) $(am__objects_4) $(am__objects_5) \
+ $(am__objects_1)
+pdns_server_OBJECTS = $(am_pdns_server_OBJECTS)
+@BOTAN110_TRUE@am__DEPENDENCIES_4 = $(am__DEPENDENCIES_1)
+@LIBSODIUM_TRUE@am__DEPENDENCIES_5 = $(am__DEPENDENCIES_1)
+@LIBDECAF_TRUE@am__DEPENDENCIES_6 = $(am__DEPENDENCIES_1)
+@SQLITE3_TRUE@am__DEPENDENCIES_7 = $(am__DEPENDENCIES_1)
+@ORACLE_TRUE@am__DEPENDENCIES_8 = $(am__DEPENDENCIES_1)
+@LUA_TRUE@am__DEPENDENCIES_9 = $(am__DEPENDENCIES_1)
+pdns_server_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(JSON11_LIBS) $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_5) \
+ $(am__DEPENDENCIES_6) $(am__DEPENDENCIES_7) \
+ $(am__DEPENDENCIES_8) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_9) $(am__DEPENDENCIES_3)
+pdns_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(pdns_server_LDFLAGS) $(LDFLAGS) -o $@
+am__pdnsutil_SOURCES_DIST = arguments.cc backends/gsql/gsqlbackend.cc \
+ backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh base32.cc \
+ base64.cc base64.hh bindlexer.l bindparser.yy cachecleaner.hh \
+ dbdnsseckeeper.cc dnsbackend.cc dns.cc dnslabeltext.cc \
+ dnsname.cc dnsname.hh dnspacket.cc dnsparser.cc dnsparser.hh \
+ dns_random.cc dnsrecords.cc dnssecinfra.cc dnssecinfra.hh \
+ dnssecsigner.cc dnswriter.cc dnswriter.hh dynlistener.cc \
+ ednssubnet.cc gss_context.cc gss_context.hh iputils.cc \
+ iputils.hh json.cc logger.cc misc.cc misc.hh nsecrecords.cc \
+ opensslsigners.cc opensslsigners.hh packetcache.cc pdnsutil.cc \
+ qtype.cc randomhelper.cc rcpgenerator.cc rcpgenerator.hh \
+ serialtweaker.cc signingpipe.cc sillyrecords.cc sstuff.hh \
+ statbag.cc ueberbackend.cc unix_utility.cc zoneparser-tng.cc \
+ botan110signers.cc sodiumsigners.cc decafsigners.cc \
+ ssqlite3.cc ssqlite3.hh pkcs11signers.cc pkcs11signers.hh
+am_pdnsutil_OBJECTS = arguments.$(OBJEXT) \
+ backends/gsql/gsqlbackend.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ dbdnsseckeeper.$(OBJEXT) dnsbackend.$(OBJEXT) dns.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnspacket.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dns_random.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnssecinfra.$(OBJEXT) dnssecsigner.$(OBJEXT) \
+ dnswriter.$(OBJEXT) dynlistener.$(OBJEXT) ednssubnet.$(OBJEXT) \
+ gss_context.$(OBJEXT) iputils.$(OBJEXT) json.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ opensslsigners.$(OBJEXT) packetcache.$(OBJEXT) \
+ pdnsutil.$(OBJEXT) qtype.$(OBJEXT) randomhelper.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) serialtweaker.$(OBJEXT) \
+ signingpipe.$(OBJEXT) sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ ueberbackend.$(OBJEXT) unix_utility.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT) $(am__objects_2) $(am__objects_3) \
+ $(am__objects_4) $(am__objects_5) $(am__objects_1)
+pdnsutil_OBJECTS = $(am_pdnsutil_OBJECTS)
+pdnsutil_DEPENDENCIES = $(am__DEPENDENCIES_1) $(JSON11_LIBS) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_4) \
+ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6) \
+ $(am__DEPENDENCIES_7) $(am__DEPENDENCIES_8) \
+ $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_3)
+pdnsutil_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(pdnsutil_LDFLAGS) $(LDFLAGS) -o $@
+am__saxfr_SOURCES_DIST = base32.cc base64.cc base64.hh dns_random.cc \
+ dns_random.hh dnslabeltext.cc dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh dnsrecords.cc dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh gss_context.cc gss_context.hh \
+ logger.cc misc.cc misc.hh nsecrecords.cc qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh saxfr.cc sillyrecords.cc \
+ sstuff.hh statbag.cc unix_utility.cc pkcs11signers.cc \
+ pkcs11signers.hh
+am_saxfr_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dns_random.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) \
+ dnswriter.$(OBJEXT) gss_context.$(OBJEXT) logger.$(OBJEXT) \
+ misc.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) saxfr.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) $(am__objects_1)
+saxfr_OBJECTS = $(am_saxfr_OBJECTS)
+saxfr_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3)
+saxfr_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(saxfr_LDFLAGS) $(LDFLAGS) -o $@
+am_sdig_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) dns.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) ednssubnet.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sdig.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+sdig_OBJECTS = $(am_sdig_OBJECTS)
+sdig_DEPENDENCIES = $(am__DEPENDENCIES_1)
+sdig_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(sdig_LDFLAGS) $(LDFLAGS) -o $@
+am_speedtest_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) logger.$(OBJEXT) \
+ misc.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ speedtest.$(OBJEXT) statbag.$(OBJEXT) unix_utility.$(OBJEXT)
+speedtest_OBJECTS = $(am_speedtest_OBJECTS)
+speedtest_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
+speedtest_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(speedtest_LDFLAGS) $(LDFLAGS) -o $@
+am_stubquery_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) dns_random.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsname.$(OBJEXT) dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnswriter.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ stubresolver.$(OBJEXT) stubquery.$(OBJEXT) \
+ unix_utility.$(OBJEXT)
+stubquery_OBJECTS = $(am_stubquery_OBJECTS)
+stubquery_DEPENDENCIES = $(am__DEPENDENCIES_1)
+stubquery_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(stubquery_LDFLAGS) $(LDFLAGS) -o $@
+am__testrunner_SOURCES_DIST = arguments.cc base32.cc base64.cc \
+ bindlexer.l bindparser.yy dbdnsseckeeper.cc dns.cc \
+ dns_random.cc dnsbackend.cc dnslabeltext.cc dnsname.cc \
+ dnsname.hh dnspacket.cc dnsparser.hh dnsparser.cc \
+ dnsrecords.cc dnssecinfra.cc dnssecsigner.cc dnswriter.cc \
+ ednsoptions.cc ednsoptions.hh ednssubnet.cc gettime.cc \
+ gettime.hh gss_context.cc gss_context.hh iputils.cc logger.cc \
+ misc.cc nameserver.cc nsecrecords.cc packetcache.cc qtype.cc \
+ rcpgenerator.cc recpacketcache.cc recpacketcache.hh \
+ rec-protobuf.hh responsestats.cc responsestats-auth.cc \
+ sillyrecords.cc statbag.cc test-arguments_cc.cc \
+ test-base32_cc.cc test-base64_cc.cc test-bindparser_cc.cc \
+ test-delaypipe_hh.cc test-distributor_hh.cc \
+ test-dns_random_hh.cc test-dnsname_cc.cc test-dnsparser_hh.cc \
+ test-dnsrecords_cc.cc test-iputils_hh.cc test-md5_hh.cc \
+ test-misc_hh.cc test-nameserver_cc.cc test-nmtree.cc \
+ test-packetcache_cc.cc test-rcpgenerator_cc.cc \
+ test-recpacketcache_cc.cc test-signers.cc test-sha_hh.cc \
+ test-statbag_cc.cc test-zoneparser_tng_cc.cc testrunner.cc \
+ ueberbackend.cc unix_utility.cc zoneparser-tng.cc \
+ zoneparser-tng.hh pkcs11signers.cc pkcs11signers.hh \
+ sodiumsigners.cc decafsigners.cc
+am_testrunner_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ dbdnsseckeeper.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \
+ dnsbackend.$(OBJEXT) dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnspacket.$(OBJEXT) dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) \
+ dnssecinfra.$(OBJEXT) dnssecsigner.$(OBJEXT) \
+ dnswriter.$(OBJEXT) ednsoptions.$(OBJEXT) ednssubnet.$(OBJEXT) \
+ gettime.$(OBJEXT) gss_context.$(OBJEXT) iputils.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nameserver.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) packetcache.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) recpacketcache.$(OBJEXT) \
+ responsestats.$(OBJEXT) responsestats-auth.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) \
+ test-arguments_cc.$(OBJEXT) test-base32_cc.$(OBJEXT) \
+ test-base64_cc.$(OBJEXT) test-bindparser_cc.$(OBJEXT) \
+ test-delaypipe_hh.$(OBJEXT) test-distributor_hh.$(OBJEXT) \
+ test-dns_random_hh.$(OBJEXT) test-dnsname_cc.$(OBJEXT) \
+ test-dnsparser_hh.$(OBJEXT) test-dnsrecords_cc.$(OBJEXT) \
+ test-iputils_hh.$(OBJEXT) test-md5_hh.$(OBJEXT) \
+ test-misc_hh.$(OBJEXT) test-nameserver_cc.$(OBJEXT) \
+ test-nmtree.$(OBJEXT) test-packetcache_cc.$(OBJEXT) \
+ test-rcpgenerator_cc.$(OBJEXT) \
+ test-recpacketcache_cc.$(OBJEXT) test-signers.$(OBJEXT) \
+ test-sha_hh.$(OBJEXT) test-statbag_cc.$(OBJEXT) \
+ test-zoneparser_tng_cc.$(OBJEXT) testrunner.$(OBJEXT) \
+ ueberbackend.$(OBJEXT) unix_utility.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT) $(am__objects_1) $(am__objects_3) \
+ $(am__objects_4)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_testrunner_OBJECTS = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsmessage.pb.$(OBJEXT)
+testrunner_OBJECTS = $(am_testrunner_OBJECTS) \
+ $(nodist_testrunner_OBJECTS)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@am__DEPENDENCIES_10 = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(am__DEPENDENCIES_1)
+testrunner_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_10) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_5) $(am__DEPENDENCIES_6)
+testrunner_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(testrunner_LDFLAGS) $(LDFLAGS) -o $@
+am__toysdig_SOURCES_DIST = base32.cc base64.cc base64.hh dns_random.cc \
+ dnsname.cc dnsname.hh dnslabeltext.cc dnsparser.cc \
+ dnsparser.hh dnsrecords.cc dnssecinfra.cc dnswriter.cc \
+ dnswriter.hh ednssubnet.cc ednssubnet.hh filterpo.hh \
+ gss_context.cc gss_context.hh logger.cc misc.cc misc.hh \
+ nsecrecords.cc opensslsigners.cc opensslsigners.hh qtype.cc \
+ randomhelper.cc root-dnssec.hh rcpgenerator.cc rcpgenerator.hh \
+ rec-lua-conf.hh recursor_cache.hh sholder.hh sillyrecords.cc \
+ sortlist.hh sstuff.hh statbag.cc toysdig.cc unix_utility.cc \
+ validate.cc validate.hh botan110signers.cc pkcs11signers.cc \
+ pkcs11signers.hh
+am_toysdig_OBJECTS = base32.$(OBJEXT) base64.$(OBJEXT) \
+ dns_random.$(OBJEXT) dnsname.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) \
+ dnswriter.$(OBJEXT) ednssubnet.$(OBJEXT) gss_context.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ opensslsigners.$(OBJEXT) qtype.$(OBJEXT) \
+ randomhelper.$(OBJEXT) rcpgenerator.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) toysdig.$(OBJEXT) \
+ unix_utility.$(OBJEXT) validate.$(OBJEXT) $(am__objects_2) \
+ $(am__objects_1)
+toysdig_OBJECTS = $(am_toysdig_OBJECTS)
+toysdig_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_3) \
+ $(am__DEPENDENCIES_4) $(am__DEPENDENCIES_2)
+toysdig_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(toysdig_LDFLAGS) $(LDFLAGS) -o $@
+am__tsig_tests_SOURCES_DIST = arguments.cc base32.cc base64.cc \
+ base64.hh dns.cc dns_random.cc dns_random.hh dnslabeltext.cc \
+ dnsname.cc dnsname.hh dnsparser.cc dnsparser.hh dnsrecords.cc \
+ dnssecinfra.cc dnswriter.cc dnswriter.hh gss_context.cc \
+ gss_context.hh logger.cc misc.cc misc.hh nsecrecords.cc \
+ qtype.cc randomhelper.cc rcpgenerator.cc rcpgenerator.hh \
+ resolver.cc sillyrecords.cc sstuff.hh statbag.cc tsig-tests.cc \
+ tsigverifier.cc tsigverifier.hh unix_utility.cc \
+ pkcs11signers.cc pkcs11signers.hh
+am_tsig_tests_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) dns.$(OBJEXT) dns_random.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnssecinfra.$(OBJEXT) dnswriter.$(OBJEXT) \
+ gss_context.$(OBJEXT) logger.$(OBJEXT) misc.$(OBJEXT) \
+ nsecrecords.$(OBJEXT) qtype.$(OBJEXT) randomhelper.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) resolver.$(OBJEXT) \
+ sillyrecords.$(OBJEXT) statbag.$(OBJEXT) tsig-tests.$(OBJEXT) \
+ tsigverifier.$(OBJEXT) unix_utility.$(OBJEXT) $(am__objects_1)
+tsig_tests_OBJECTS = $(am_tsig_tests_OBJECTS)
+tsig_tests_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_2) \
+ $(am__DEPENDENCIES_3)
+tsig_tests_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(tsig_tests_LDFLAGS) $(LDFLAGS) -o $@
+am_zone2json_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsname.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) logger.$(OBJEXT) \
+ misc.$(OBJEXT) nsecrecords.$(OBJEXT) qtype.$(OBJEXT) \
+ rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) zone2json.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT)
+zone2json_OBJECTS = $(am_zone2json_OBJECTS)
+zone2json_DEPENDENCIES = $(am__DEPENDENCIES_1) $(JSON11_LIBS)
+zone2json_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(zone2json_LDFLAGS) $(LDFLAGS) -o $@
+am_zone2ldap_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ dns_random.$(OBJEXT) dnsname.$(OBJEXT) dnslabeltext.$(OBJEXT) \
+ dnsparser.$(OBJEXT) dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) zone2ldap.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT)
+zone2ldap_OBJECTS = $(am_zone2ldap_OBJECTS)
+zone2ldap_DEPENDENCIES = $(am__DEPENDENCIES_1)
+zone2ldap_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(zone2ldap_LDFLAGS) $(LDFLAGS) -o $@
+am_zone2sql_OBJECTS = arguments.$(OBJEXT) base32.$(OBJEXT) \
+ base64.$(OBJEXT) bindlexer.$(OBJEXT) bindparser.$(OBJEXT) \
+ dns.$(OBJEXT) dns_random.$(OBJEXT) dnsname.$(OBJEXT) \
+ dnslabeltext.$(OBJEXT) dnsparser.$(OBJEXT) \
+ dnsrecords.$(OBJEXT) dnswriter.$(OBJEXT) json.$(OBJEXT) \
+ logger.$(OBJEXT) misc.$(OBJEXT) nsecrecords.$(OBJEXT) \
+ qtype.$(OBJEXT) rcpgenerator.$(OBJEXT) sillyrecords.$(OBJEXT) \
+ statbag.$(OBJEXT) unix_utility.$(OBJEXT) zone2sql.$(OBJEXT) \
+ zoneparser-tng.$(OBJEXT)
+zone2sql_OBJECTS = $(am_zone2sql_OBJECTS)
+zone2sql_DEPENDENCIES = $(am__DEPENDENCIES_1) $(JSON11_LIBS)
+zone2sql_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(zone2sql_LDFLAGS) $(LDFLAGS) -o $@
+SCRIPTS = $(noinst_SCRIPTS)
+AM_V_P = $(am__v_P_@AM_V@)
+am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
+am__v_P_0 = false
+am__v_P_1 = :
+AM_V_GEN = $(am__v_GEN_@AM_V@)
+am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
+am__v_GEN_0 = @echo " GEN " $@;
+am__v_GEN_1 =
+AM_V_at = $(am__v_at_@AM_V@)
+am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
+am__v_at_0 = @
+am__v_at_1 =
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/build-aux/depcomp
+am__depfiles_maybe = depfiles
+am__mv = mv -f
+COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \
+ $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS)
+LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CFLAGS) $(CFLAGS)
+AM_V_CC = $(am__v_CC_@AM_V@)
+am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@)
+am__v_CC_0 = @echo " CC " $@;
+am__v_CC_1 =
+CCLD = $(CC)
+LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
+ $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CCLD = $(am__v_CCLD_@AM_V@)
+am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
+am__v_CCLD_0 = @echo " CCLD " $@;
+am__v_CCLD_1 =
+CXXCOMPILE = $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) \
+ $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS)
+LTCXXCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) \
+ $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \
+ $(AM_CXXFLAGS) $(CXXFLAGS)
+AM_V_CXX = $(am__v_CXX_@AM_V@)
+am__v_CXX_ = $(am__v_CXX_@AM_DEFAULT_V@)
+am__v_CXX_0 = @echo " CXX " $@;
+am__v_CXX_1 =
+CXXLD = $(CXX)
+CXXLINK = $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CXXLD) $(AM_CXXFLAGS) \
+ $(CXXFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
+AM_V_CXXLD = $(am__v_CXXLD_@AM_V@)
+am__v_CXXLD_ = $(am__v_CXXLD_@AM_DEFAULT_V@)
+am__v_CXXLD_0 = @echo " CXXLD " $@;
+am__v_CXXLD_1 =
+LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
+LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
+AM_V_LEX = $(am__v_LEX_@AM_V@)
+am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
+am__v_LEX_0 = @echo " LEX " $@;
+am__v_LEX_1 =
+YLWRAP = $(top_srcdir)/build-aux/ylwrap
+am__yacc_c2h = sed -e s/cc$$/hh/ -e s/cpp$$/hpp/ -e s/cxx$$/hxx/ \
+ -e s/c++$$/h++/ -e s/c$$/h/
+YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
+LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
+AM_V_YACC = $(am__v_YACC_@AM_V@)
+am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
+am__v_YACC_0 = @echo " YACC " $@;
+am__v_YACC_1 =
+SOURCES = $(calidns_SOURCES) $(comfun_SOURCES) $(dnsbulktest_SOURCES) \
+ $(dnsdemog_SOURCES) $(dnsgram_SOURCES) \
+ $(dnspcap2protobuf_SOURCES) $(nodist_dnspcap2protobuf_SOURCES) \
+ $(dnsreplay_SOURCES) $(dnsscan_SOURCES) $(dnsscope_SOURCES) \
+ $(dnstcpbench_SOURCES) $(dnswasher_SOURCES) $(dumresp_SOURCES) \
+ $(ixplore_SOURCES) $(kvresp_SOURCES) $(nproxy_SOURCES) \
+ $(nsec3dig_SOURCES) $(pdns_control_SOURCES) \
+ $(pdns_notify_SOURCES) $(pdns_server_SOURCES) \
+ $(pdnsutil_SOURCES) $(saxfr_SOURCES) $(sdig_SOURCES) \
+ $(speedtest_SOURCES) $(stubquery_SOURCES) \
+ $(testrunner_SOURCES) $(nodist_testrunner_SOURCES) \
+ $(toysdig_SOURCES) $(tsig_tests_SOURCES) $(zone2json_SOURCES) \
+ $(zone2ldap_SOURCES) $(zone2sql_SOURCES)
+DIST_SOURCES = $(calidns_SOURCES) $(comfun_SOURCES) \
+ $(dnsbulktest_SOURCES) $(dnsdemog_SOURCES) $(dnsgram_SOURCES) \
+ $(am__dnspcap2protobuf_SOURCES_DIST) $(dnsreplay_SOURCES) \
+ $(dnsscan_SOURCES) $(dnsscope_SOURCES) $(dnstcpbench_SOURCES) \
+ $(dnswasher_SOURCES) $(dumresp_SOURCES) \
+ $(am__ixplore_SOURCES_DIST) $(kvresp_SOURCES) \
+ $(nproxy_SOURCES) $(am__nsec3dig_SOURCES_DIST) \
+ $(pdns_control_SOURCES) $(pdns_notify_SOURCES) \
+ $(am__pdns_server_SOURCES_DIST) $(am__pdnsutil_SOURCES_DIST) \
+ $(am__saxfr_SOURCES_DIST) $(sdig_SOURCES) $(speedtest_SOURCES) \
+ $(stubquery_SOURCES) $(am__testrunner_SOURCES_DIST) \
+ $(am__toysdig_SOURCES_DIST) $(am__tsig_tests_SOURCES_DIST) \
+ $(zone2json_SOURCES) $(zone2ldap_SOURCES) $(zone2sql_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
+am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
+am__vpath_adj = case $$p in \
+ $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
+ *) f=$$p;; \
+ esac;
+am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`;
+am__install_max = 40
+am__nobase_strip_setup = \
+ srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'`
+am__nobase_strip = \
+ for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||"
+am__nobase_list = $(am__nobase_strip_setup); \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \
+ $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \
+ if (++n[$$2] == $(am__install_max)) \
+ { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \
+ END { for (dir in files) print dir, files[dir] }'
+am__base_list = \
+ sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \
+ sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g'
+am__uninstall_files_from_dir = { \
+ test -z "$$files" \
+ || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \
+ || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
+ $(am__cd) "$$dir" && rm -f $$files; }; \
+ }
+DATA = $(sysconf_DATA) $(systemdsystemunit_DATA)
+am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP)
+# Read a list of newline-separated strings from the standard input,
+# and print each of them once, without duplicates. Input order is
+# *not* preserved.
+am__uniquify_input = $(AWK) '\
+ BEGIN { nonempty = 0; } \
+ { items[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in items) print i; }; } \
+'
+# Make sure the list of sources is unique. This is necessary because,
+# e.g., the same source file might be shared among _SOURCES variables
+# for different programs/libraries.
+am__define_uniq_tagged_files = \
+ list='$(am__tagged_files)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | $(am__uniquify_input)`
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors_dummy = \
+ mgn= red= grn= lgn= blu= brg= std=; \
+ am__color_tests=no
+am__tty_colors = { \
+ $(am__tty_colors_dummy); \
+ if test "X$(AM_COLOR_TESTS)" = Xno; then \
+ am__color_tests=no; \
+ elif test "X$(AM_COLOR_TESTS)" = Xalways; then \
+ am__color_tests=yes; \
+ elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \
+ am__color_tests=yes; \
+ fi; \
+ if test $$am__color_tests = yes; then \
+ red='\e[0;31m'; \
+ grn='\e[0;32m'; \
+ lgn='\e[1;32m'; \
+ blu='\e[1;34m'; \
+ mgn='\e[0;35m'; \
+ brg='\e[1m'; \
+ std='\e[m'; \
+ fi; \
+}
+am__recheck_rx = ^[ ]*:recheck:[ ]*
+am__global_test_result_rx = ^[ ]*:global-test-result:[ ]*
+am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]*
+# A command that, given a newline-separated list of test names on the
+# standard input, print the name of the tests that are to be re-run
+# upon "make recheck".
+am__list_recheck_tests = $(AWK) '{ \
+ recheck = 1; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ { \
+ if ((getline line2 < ($$0 ".log")) < 0) \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \
+ { \
+ recheck = 0; \
+ break; \
+ } \
+ else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \
+ { \
+ break; \
+ } \
+ }; \
+ if (recheck) \
+ print $$0; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# A command that, given a newline-separated list of test names on the
+# standard input, create the global log from their .trs and .log files.
+am__create_global_log = $(AWK) ' \
+function fatal(msg) \
+{ \
+ print "fatal: making $@: " msg | "cat >&2"; \
+ exit 1; \
+} \
+function rst_section(header) \
+{ \
+ print header; \
+ len = length(header); \
+ for (i = 1; i <= len; i = i + 1) \
+ printf "="; \
+ printf "\n\n"; \
+} \
+{ \
+ copy_in_global_log = 1; \
+ global_test_result = "RUN"; \
+ while ((rc = (getline line < ($$0 ".trs"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".trs"); \
+ if (line ~ /$(am__global_test_result_rx)/) \
+ { \
+ sub("$(am__global_test_result_rx)", "", line); \
+ sub("[ ]*$$", "", line); \
+ global_test_result = line; \
+ } \
+ else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \
+ copy_in_global_log = 0; \
+ }; \
+ if (copy_in_global_log) \
+ { \
+ rst_section(global_test_result ": " $$0); \
+ while ((rc = (getline line < ($$0 ".log"))) != 0) \
+ { \
+ if (rc < 0) \
+ fatal("failed to read from " $$0 ".log"); \
+ print line; \
+ }; \
+ printf "\n"; \
+ }; \
+ close ($$0 ".trs"); \
+ close ($$0 ".log"); \
+}'
+# Restructured Text title.
+am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; }
+# Solaris 10 'make', and several other traditional 'make' implementations,
+# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it
+# by disabling -e (using the XSI extension "set +e") if it's set.
+am__sh_e_setup = case $$- in *e*) set +e;; esac
+# Default flags passed to test drivers.
+am__common_driver_flags = \
+ --color-tests "$$am__color_tests" \
+ --enable-hard-errors "$$am__enable_hard_errors" \
+ --expect-failure "$$am__expect_failure"
+# To be inserted before the command running the test. Creates the
+# directory for the log if needed. Stores in $dir the directory
+# containing $f, in $tst the test, in $log the log. Executes the
+# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and
+# passes TESTS_ENVIRONMENT. Set up options for the wrapper that
+# will run the test scripts (or their associated LOG_COMPILER, if
+# thy have one).
+am__check_pre = \
+$(am__sh_e_setup); \
+$(am__vpath_adj_setup) $(am__vpath_adj) \
+$(am__tty_colors); \
+srcdir=$(srcdir); export srcdir; \
+case "$@" in \
+ */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \
+ *) am__odir=.;; \
+esac; \
+test "x$$am__odir" = x"." || test -d "$$am__odir" \
+ || $(MKDIR_P) "$$am__odir" || exit $$?; \
+if test -f "./$$f"; then dir=./; \
+elif test -f "$$f"; then dir=; \
+else dir="$(srcdir)/"; fi; \
+tst=$$dir$$f; log='$@'; \
+if test -n '$(DISABLE_HARD_ERRORS)'; then \
+ am__enable_hard_errors=no; \
+else \
+ am__enable_hard_errors=yes; \
+fi; \
+case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \
+ am__expect_failure=yes;; \
+ *) \
+ am__expect_failure=no;; \
+esac; \
+$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT)
+# A shell command to get the names of the tests scripts with any registered
+# extension removed (i.e., equivalently, the names of the test logs, with
+# the '.log' extension removed). The result is saved in the shell variable
+# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly,
+# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)",
+# since that might cause problem with VPATH rewrites for suffix-less tests.
+# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'.
+am__set_TESTS_bases = \
+ bases='$(TEST_LOGS)'; \
+ bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \
+ bases=`echo $$bases`
+RECHECK_LOGS = $(TEST_LOGS)
+AM_RECURSIVE_TARGETS = check recheck
+TEST_SUITE_LOG = test-suite.log
+TEST_EXTENSIONS = @EXEEXT@ .test
+LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS)
+am__set_b = \
+ case '$@' in \
+ */*) \
+ case '$*' in \
+ */*) b='$*';; \
+ *) b=`echo '$@' | sed 's/\.log$$//'`; \
+ esac;; \
+ *) \
+ b='$*';; \
+ esac
+am__test_logs1 = $(TESTS:=.log)
+am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log)
+TEST_LOGS = $(am__test_logs2:.test.log=.log)
+TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/build-aux/test-driver
+TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \
+ $(TEST_LOG_FLAGS)
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+AMTAR = @AMTAR@
+AM_CPPFLAGS = @AM_CPPFLAGS@ -I$(top_srcdir)/ext/json11 \
+ $(YAHTTP_CFLAGS) $(LIBEDIT_CFLAGS) $(LIBCRYPTO_INCLUDES) \
+ $(SYSTEMD_CFLAGS) $(am__append_1) $(am__append_2) \
+ $(am__append_3) $(am__append_4) $(am__append_5)
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+BOOST_CPPFLAGS = @BOOST_CPPFLAGS@
+BOOST_LDPATH = @BOOST_LDPATH@
+BOOST_PROGRAM_OPTIONS_LDFLAGS = @BOOST_PROGRAM_OPTIONS_LDFLAGS@
+BOOST_PROGRAM_OPTIONS_LDPATH = @BOOST_PROGRAM_OPTIONS_LDPATH@
+BOOST_PROGRAM_OPTIONS_LIBS = @BOOST_PROGRAM_OPTIONS_LIBS@
+BOOST_ROOT = @BOOST_ROOT@
+BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS = @BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS@
+BOOST_UNIT_TEST_FRAMEWORK_LDPATH = @BOOST_UNIT_TEST_FRAMEWORK_LDPATH@
+BOOST_UNIT_TEST_FRAMEWORK_LIBS = @BOOST_UNIT_TEST_FRAMEWORK_LIBS@
+BOTAN110_CFLAGS = @BOTAN110_CFLAGS@
+BOTAN110_LIBS = @BOTAN110_LIBS@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CDB_CFLAGS = @CDB_CFLAGS@
+CDB_LIBS = @CDB_LIBS@
+CFLAGS = @CFLAGS@
+CPPFLAGS = @CPPFLAGS@
+CURL = @CURL@
+CXX = @CXX@
+CXXCPP = @CXXCPP@
+CXXDEPMODE = @CXXDEPMODE@
+CXXFLAGS = @CXXFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+DYNLINKFLAGS = @DYNLINKFLAGS@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GEOIP_CFLAGS = @GEOIP_CFLAGS@
+GEOIP_LIBS = @GEOIP_LIBS@
+GREP = @GREP@
+GSS_CFLAGS = @GSS_CFLAGS@
+GSS_LIBS = @GSS_LIBS@
+GSS_TSIG = @GSS_TSIG@
+HAVE_CXX11 = @HAVE_CXX11@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+LD = @LD@
+LDAP_LIBS = @LDAP_LIBS@
+LDFLAGS = @LDFLAGS@
+LEX = @LEX@
+LEXLIB = @LEXLIB@
+LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
+LIBCRYPTO_INCLUDES = @LIBCRYPTO_INCLUDES@
+LIBCRYPTO_LDFLAGS = @LIBCRYPTO_LDFLAGS@
+LIBCRYPTO_LIBS = @LIBCRYPTO_LIBS@
+LIBDECAF_LIBS = @LIBDECAF_LIBS@
+LIBDL = @LIBDL@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBSODIUM_CFLAGS = @LIBSODIUM_CFLAGS@
+LIBSODIUM_LIBS = @LIBSODIUM_LIBS@
+LIBTOOL = @LIBTOOL@
+LIBZMQ_CFLAGS = @LIBZMQ_CFLAGS@
+LIBZMQ_LIBS = @LIBZMQ_LIBS@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+LUA_CFLAGS = @LUA_CFLAGS@
+LUA_LIBS = @LUA_LIBS@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MKDIR_P = @MKDIR_P@
+MYSQL_CFLAGS = @MYSQL_CFLAGS@
+MYSQL_LIBS = @MYSQL_LIBS@
+MYSQL_config = @MYSQL_config@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OPENDBX_CFLAGS = @OPENDBX_CFLAGS@
+OPENDBX_LIBS = @OPENDBX_LIBS@
+ORACLE_CFLAGS = @ORACLE_CFLAGS@
+ORACLE_LIBS = @ORACLE_LIBS@
+OTOOL = @OTOOL@
+OTOOL64 = @OTOOL64@
+P11KIT1_CFLAGS = @P11KIT1_CFLAGS@
+P11KIT1_LIBS = @P11KIT1_LIBS@
+PACKAGE = @PACKAGE@
+PACKAGEVERSION = @PACKAGEVERSION@
+PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@
+PACKAGE_NAME = @PACKAGE_NAME@
+PACKAGE_STRING = @PACKAGE_STRING@
+PACKAGE_TARNAME = @PACKAGE_TARNAME@
+PACKAGE_URL = @PACKAGE_URL@
+PACKAGE_VERSION = @PACKAGE_VERSION@
+PANDOC = @PANDOC@
+PATH_SEPARATOR = @PATH_SEPARATOR@
+PGSQL_inc = @PGSQL_inc@
+PGSQL_lib = @PGSQL_lib@
+PGSQL_pg_config = @PGSQL_pg_config@
+PIE_CFLAGS = @PIE_CFLAGS@
+PIE_LDFLAGS = @PIE_LDFLAGS@
+PKG_CONFIG = @PKG_CONFIG@
+PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
+PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
+PROGRAM_LDFLAGS = @PROGRAM_LDFLAGS@
+PROTOBUF_CFLAGS = @PROTOBUF_CFLAGS@
+PROTOBUF_LIBS = @PROTOBUF_LIBS@
+PROTOC = @PROTOC@
+RAGEL = @RAGEL@
+RANLIB = @RANLIB@
+RELRO_LDFLAGS = @RELRO_LDFLAGS@
+REMOTEBACKEND_ZEROMQ = @REMOTEBACKEND_ZEROMQ@
+RT_LIBS = @RT_LIBS@
+SANITIZER_FLAGS = @SANITIZER_FLAGS@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SQLITE3_CFLAGS = @SQLITE3_CFLAGS@
+SQLITE3_LIBS = @SQLITE3_LIBS@
+STRIP = @STRIP@
+SYSTEMD_CFLAGS = @SYSTEMD_CFLAGS@
+SYSTEMD_DIR = @SYSTEMD_DIR@
+SYSTEMD_LIBS = @SYSTEMD_LIBS@
+SYSTEMD_MODULES_LOAD = @SYSTEMD_MODULES_LOAD@
+THREADFLAGS = @THREADFLAGS@
+UNIXODBC_CFLAGS = @UNIXODBC_CFLAGS@
+UNIXODBC_LIBS = @UNIXODBC_LIBS@
+UNIXODBC_config = @UNIXODBC_config@
+VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
+YACC = @YACC@
+YAHTTP_CFLAGS = @YAHTTP_CFLAGS@
+YAHTTP_LIBS = @YAHTTP_LIBS@
+YAML_CFLAGS = @YAML_CFLAGS@
+YAML_LIBS = @YAML_LIBS@
+YFLAGS = @YFLAGS@
+abs_builddir = @abs_builddir@
+abs_srcdir = @abs_srcdir@
+abs_top_builddir = @abs_top_builddir@
+abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
+ac_ct_CC = @ac_ct_CC@
+ac_ct_CXX = @ac_ct_CXX@
+ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
+am__include = @am__include@
+am__leading_dot = @am__leading_dot@
+am__quote = @am__quote@
+am__tar = @am__tar@
+am__untar = @am__untar@
+bindir = @bindir@
+build = @build@
+build_alias = @build_alias@
+build_cpu = @build_cpu@
+build_os = @build_os@
+build_vendor = @build_vendor@
+builddir = @builddir@
+datadir = @datadir@
+datarootdir = @datarootdir@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+host = @host@
+host_alias = @host_alias@
+host_cpu = @host_cpu@
+host_os = @host_os@
+host_vendor = @host_vendor@
+htmldir = @htmldir@
+includedir = @includedir@
+infodir = @infodir@
+install_sh = @install_sh@
+libdir = @libdir@
+libexecdir = @libexecdir@
+localedir = @localedir@
+localstatedir = @localstatedir@
+mandir = @mandir@
+mkdir_p = @mkdir_p@
+moduledirs = @moduledirs@
+modulelibs = @modulelibs@
+moduleobjects = @moduleobjects@
+oldincludedir = @oldincludedir@
+pdfdir = @pdfdir@
+pdns_configure_args = @pdns_configure_args@
+prefix = @prefix@
+program_transform_name = @program_transform_name@
+psdir = @psdir@
+sbindir = @sbindir@
+sharedstatedir = @sharedstatedir@
+socketdir = @socketdir@
+srcdir = @srcdir@
+sysconfdir = @sysconfdir@
+systemd = @systemd@
+target_alias = @target_alias@
+top_build_prefix = @top_build_prefix@
+top_builddir = @top_builddir@
+top_srcdir = @top_srcdir@
+JSON11_LIBS = $(top_builddir)/ext/json11/libjson11.la
+AM_CXXFLAGS = \
+ -DSYSCONFDIR=\"$(sysconfdir)\" \
+ -DPKGLIBDIR=\"$(pkglibdir)\" \
+ -DLOCALSTATEDIR=\"$(socketdir)\"
+
+AM_LDFLAGS = \
+ $(PROGRAM_LDFLAGS) \
+ $(THREADFLAGS)
+
+AM_LFLAGS = -i
+AM_YFLAGS = -d --verbose --debug
+EXTRA_DIST = \
+ dnslabeltext.rl \
+ dnslabeltext.cc \
+ dnsmessage.proto \
+ effective_tld_names.dat \
+ mtasker.cc \
+ inflighter.cc \
+ bind-dnssec.schema.sqlite3.sql \
+ bindparser.h \
+ named.conf.parsertest \
+ delaypipe.hh delaypipe.cc \
+ pdns.service.in
+
+BUILT_SOURCES = bind-dnssec.schema.sqlite3.sql.h bindparser.h \
+ $(am__append_53)
+CLEANFILES = \
+ *.gcda \
+ *.gcno \
+ *.gcov \
+ backends/gsql/gsqlbackend.gcda \
+ backends/gsql/gsqlbackend.gcno \
+ backends/gsql/gsqlbackend.gcov \
+ dnsmessage.pb.cc dnsmessage.pb.h \
+ pdns.conf-dist
+
+noinst_SCRIPTS = pdns.init
+sysconf_DATA = pdns.conf-dist
+pdns_server_SOURCES = arguments.cc arguments.hh auth-carbon.cc \
+ backends/gsql/gsqlbackend.cc backends/gsql/gsqlbackend.hh \
+ backends/gsql/ssql.hh base32.cc base32.hh base64.cc base64.hh \
+ bind-dnssec.schema.sqlite3.sql.h bindlexer.l bindparser.cc \
+ cachecleaner.hh comment.hh common_startup.cc common_startup.hh \
+ communicator.cc communicator.hh dbdnsseckeeper.cc \
+ distributor.hh dns.cc dns.hh dns_random.cc dns_random.hh \
+ dnsbackend.cc dnsbackend.hh dnslabeltext.cc dnsname.cc \
+ dnsname.hh dnspacket.cc dnspacket.hh dnsparser.cc dnsproxy.cc \
+ dnsproxy.hh dnsrecords.cc dnsrecords.hh dnssecinfra.cc \
+ dnssecinfra.hh dnsseckeeper.hh dnssecsigner.cc dnswriter.cc \
+ dynhandler.cc dynhandler.hh dynlistener.cc dynlistener.hh \
+ dynmessenger.hh ednssubnet.cc ednssubnet.hh gss_context.cc \
+ gss_context.hh iputils.cc iputils.hh ixfr.cc ixfr.hh json.cc \
+ json.hh lock.hh logger.cc logger.hh lua-auth.cc lua-auth.hh \
+ lua-pdns.cc lua-pdns.hh lua-iputils.cc mastercommunicator.cc \
+ md5.hh misc.cc misc.hh nameserver.cc nameserver.hh \
+ namespaces.hh nsecrecords.cc opensslsigners.cc \
+ opensslsigners.hh packetcache.cc packetcache.hh \
+ packethandler.cc packethandler.hh pdnsexception.hh qtype.cc \
+ qtype.hh randomhelper.cc rcpgenerator.cc receiver.cc \
+ resolver.cc resolver.hh responsestats.cc responsestats.hh \
+ responsestats-auth.cc rfc2136handler.cc secpoll-auth.cc \
+ secpoll-auth.hh serialtweaker.cc sha.hh signingpipe.cc \
+ signingpipe.hh sillyrecords.cc slavecommunicator.cc statbag.cc \
+ statbag.hh stubresolver.cc stubresolver.hh tcpreceiver.cc \
+ tcpreceiver.hh tsigverifier.cc tsigverifier.hh tkey.cc \
+ ueberbackend.cc ueberbackend.hh unix_semaphore.cc \
+ unix_utility.cc utility.hh version.cc version.hh webserver.cc \
+ webserver.hh ws-api.cc ws-api.hh ws-auth.cc ws-auth.hh \
+ zoneparser-tng.cc $(am__append_9) $(am__append_11) \
+ $(am__append_13) $(am__append_15) $(am__append_18)
+pdns_server_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(DYNLINKFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+pdns_server_LDADD = @moduleobjects@ @modulelibs@ $(LIBDL) \
+ $(YAHTTP_LIBS) $(JSON11_LIBS) $(LIBCRYPTO_LIBS) \
+ $(SYSTEMD_LIBS) $(am__append_10) $(am__append_12) \
+ $(am__append_14) $(am__append_16) $(am__append_17) \
+ $(am__append_19) $(am__append_20) $(am__append_21)
+pdnsutil_SOURCES = arguments.cc backends/gsql/gsqlbackend.cc \
+ backends/gsql/gsqlbackend.hh backends/gsql/ssql.hh base32.cc \
+ base64.cc base64.hh bindlexer.l bindparser.yy cachecleaner.hh \
+ dbdnsseckeeper.cc dnsbackend.cc dns.cc dnslabeltext.cc \
+ dnsname.cc dnsname.hh dnspacket.cc dnsparser.cc dnsparser.hh \
+ dns_random.cc dnsrecords.cc dnssecinfra.cc dnssecinfra.hh \
+ dnssecsigner.cc dnswriter.cc dnswriter.hh dynlistener.cc \
+ ednssubnet.cc gss_context.cc gss_context.hh iputils.cc \
+ iputils.hh json.cc logger.cc misc.cc misc.hh nsecrecords.cc \
+ opensslsigners.cc opensslsigners.hh packetcache.cc pdnsutil.cc \
+ qtype.cc randomhelper.cc rcpgenerator.cc rcpgenerator.hh \
+ serialtweaker.cc signingpipe.cc sillyrecords.cc sstuff.hh \
+ statbag.cc ueberbackend.cc unix_utility.cc zoneparser-tng.cc \
+ $(am__append_22) $(am__append_24) $(am__append_26) \
+ $(am__append_28) $(am__append_31)
+pdnsutil_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(DYNLINKFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+pdnsutil_LDADD = @moduleobjects@ @modulelibs@ $(YAHTTP_LIBS) \
+ $(JSON11_LIBS) $(LIBDL) $(BOOST_PROGRAM_OPTIONS_LIBS) \
+ $(LIBCRYPTO_LIBS) $(am__append_23) $(am__append_25) \
+ $(am__append_27) $(am__append_29) $(am__append_30) \
+ $(am__append_32) $(am__append_33)
+zone2sql_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dns.cc \
+ dns_random.cc \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ json.cc json.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2sql.cc \
+ zoneparser-tng.cc
+
+zone2sql_LDADD = $(LIBCRYPTO_LIBS) $(JSON11_LIBS)
+zone2sql_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+zone2json_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2json.cc \
+ zoneparser-tng.cc
+
+zone2json_LDADD = $(LIBCRYPTO_LIBS) $(JSON11_LIBS)
+zone2json_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+zone2ldap_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc \
+ bind-dnssec.schema.sqlite3.sql.h \
+ bindlexer.l \
+ bindparser.yy \
+ bindparserclasses.hh \
+ dns_random.cc \
+ dnsname.cc dnsname.hh \
+ dnslabeltext.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zone2ldap.cc \
+ zoneparser-tng.cc
+
+zone2ldap_LDADD = $(LIBCRYPTO_LIBS)
+zone2ldap_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+sdig_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ ednssubnet.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sdig.cc \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+sdig_LDADD = $(LIBCRYPTO_LIBS)
+sdig_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+calidns_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ calidns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ iputils.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+calidns_LDADD = $(LIBCRYPTO_LIBS)
+calidns_LDFLAGS = $(AM_LDFLAGS) $(THREADFLAGS) $(LIBCRYPTO_LDFLAGS)
+dumresp_SOURCES = \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dumresp.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ statbag.cc \
+ unix_utility.cc \
+ qtype.cc
+
+kvresp_SOURCES = \
+ dnslabeltext.cc dnsname.cc dnsname.hh \
+ kvresp.cc \
+ logger.cc \
+ misc.cc misc.hh \
+ statbag.cc \
+ unix_utility.cc \
+ qtype.cc
+
+stubquery_SOURCES = \
+ arguments.cc arguments.hh \
+ base32.cc \
+ base64.cc \
+ dns_random.cc \
+ dnslabeltext.cc \
+ dnsname.cc \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ stubresolver.cc stubresolver.hh \
+ stubquery.cc \
+ unix_utility.cc
+
+stubquery_LDADD = $(LIBCRYPTO_LIBS)
+stubquery_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+saxfr_SOURCES = base32.cc base64.cc base64.hh dns_random.cc \
+ dns_random.hh dnslabeltext.cc dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh dnsrecords.cc dnssecinfra.cc \
+ dnswriter.cc dnswriter.hh gss_context.cc gss_context.hh \
+ logger.cc misc.cc misc.hh nsecrecords.cc qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh saxfr.cc sillyrecords.cc \
+ sstuff.hh statbag.cc unix_utility.cc $(am__append_35)
+saxfr_LDADD = $(LIBCRYPTO_LIBS) $(am__append_36) $(am__append_37)
+saxfr_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+ixplore_SOURCES = arguments.cc base32.cc base64.cc base64.hh dns.cc \
+ dns_random.cc dns_random.hh dnslabeltext.cc dnsname.cc \
+ dnsname.hh dnsparser.cc dnsparser.hh dnsrecords.cc \
+ dnssecinfra.cc dnswriter.cc dnswriter.hh gss_context.cc \
+ gss_context.hh logger.cc misc.cc misc.hh nsecrecords.cc \
+ qtype.cc rcpgenerator.cc rcpgenerator.hh resolver.cc ixfr.cc \
+ ixfr.hh ixplore.cc sillyrecords.cc sstuff.hh statbag.cc \
+ tsigverifier.cc tsigverifier.hh unix_utility.cc \
+ zoneparser-tng.cc $(am__append_38)
+ixplore_LDADD = $(LIBCRYPTO_LIBS) $(am__append_39) $(am__append_40)
+ixplore_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+dnstcpbench_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnstcpbench.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ sstuff.hh \
+ statbag.cc \
+ unix_utility.cc
+
+dnstcpbench_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnstcpbench_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+nsec3dig_SOURCES = base32.cc base64.cc base64.hh dnsname.cc dnsname.hh \
+ dnslabeltext.cc dnsparser.cc dnsparser.hh dnsrecords.cc \
+ dnssecinfra.cc dnswriter.cc dnswriter.hh gss_context.cc \
+ gss_context.hh logger.cc misc.cc misc.hh nsec3dig.cc \
+ nsecrecords.cc qtype.cc rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc sstuff.hh statbag.cc unix_utility.cc \
+ $(am__append_41)
+nsec3dig_LDADD = $(LIBCRYPTO_LIBS) $(am__append_42) $(am__append_43)
+nsec3dig_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+toysdig_SOURCES = base32.cc base64.cc base64.hh dns_random.cc \
+ dnsname.cc dnsname.hh dnslabeltext.cc dnsparser.cc \
+ dnsparser.hh dnsrecords.cc dnssecinfra.cc dnswriter.cc \
+ dnswriter.hh ednssubnet.cc ednssubnet.hh filterpo.hh \
+ gss_context.cc gss_context.hh logger.cc misc.cc misc.hh \
+ nsecrecords.cc opensslsigners.cc opensslsigners.hh qtype.cc \
+ randomhelper.cc root-dnssec.hh rcpgenerator.cc rcpgenerator.hh \
+ rec-lua-conf.hh recursor_cache.hh sholder.hh sillyrecords.cc \
+ sortlist.hh sstuff.hh statbag.cc toysdig.cc unix_utility.cc \
+ validate.cc validate.hh $(am__append_45) $(am__append_47)
+toysdig_LDFLAGS = $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+toysdig_LDADD = $(LIBCRYPTO_LIBS) $(am__append_44) $(am__append_46) \
+ $(am__append_48)
+tsig_tests_SOURCES = arguments.cc base32.cc base64.cc base64.hh dns.cc \
+ dns_random.cc dns_random.hh dnslabeltext.cc dnsname.cc \
+ dnsname.hh dnsparser.cc dnsparser.hh dnsrecords.cc \
+ dnssecinfra.cc dnswriter.cc dnswriter.hh gss_context.cc \
+ gss_context.hh logger.cc misc.cc misc.hh nsecrecords.cc \
+ qtype.cc randomhelper.cc rcpgenerator.cc rcpgenerator.hh \
+ resolver.cc sillyrecords.cc sstuff.hh statbag.cc tsig-tests.cc \
+ tsigverifier.cc tsigverifier.hh unix_utility.cc \
+ $(am__append_49)
+tsig_tests_LDADD = $(LIBCRYPTO_LIBS) $(am__append_50) $(am__append_51)
+tsig_tests_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+speedtest_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc misc.hh \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ speedtest.cc \
+ statbag.cc \
+ unix_utility.cc
+
+speedtest_LDFLAGS = $(AM_LDFLAGS) $(LIBCRYPTO_LDFLAGS)
+speedtest_LDADD = $(LIBCRYPTO_LIBS) \
+ $(RT_LIBS)
+
+dnswasher_SOURCES = \
+ dnslabeltext.cc \
+ dnsname.hh dnsname.cc \
+ dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnswasher.cc \
+ dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ qtype.cc \
+ statbag.cc \
+ unix_utility.cc
+
+dnsbulktest_SOURCES = \
+ base32.cc \
+ base64.cc \
+ dnsbulktest.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+dnsbulktest_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsbulktest_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+comfun_SOURCES = \
+ base32.cc \
+ base64.cc \
+ comfun.cc \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc \
+ dnsrecords.cc \
+ dnswriter.cc \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ zoneparser-tng.cc zoneparser-tng.hh
+
+comfun_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+comfun_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+dnsscan_SOURCES = \
+ anadns.hh \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsscan.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsscan_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsscan_LDADD = $(LIBCRYPTO_LIBS)
+dnsreplay_SOURCES = \
+ anadns.hh \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsreplay.cc \
+ dnswriter.cc dnswriter.hh \
+ ednssubnet.cc ednssubnet.hh \
+ ednsoptions.cc ednsoptions.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsreplay_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsreplay_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+nproxy_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ mplexer.hh \
+ nproxy.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ selectmplexer.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+nproxy_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+nproxy_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+pdns_notify_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ notify.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ selectmplexer.cc \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc
+
+pdns_notify_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+pdns_notify_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+dnsscope_SOURCES = \
+ arguments.cc \
+ base32.cc \
+ base64.cc base64.hh \
+ dns.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnsscope.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ statnode.cc statnode.hh \
+ unix_utility.cc \
+ utility.hh
+
+dnsscope_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+dnsscope_LDADD = \
+ $(LIBCRYPTO_LIBS) \
+ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+dnsgram_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnsgram.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsgram_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsgram_LDADD = \
+ $(LIBCRYPTO_LIBS)
+
+dnsdemog_SOURCES = \
+ base32.cc \
+ base64.cc base64.hh \
+ dnsdemog.cc \
+ dnslabeltext.cc \
+ dnsname.cc dnsname.hh \
+ dnsparser.cc dnsparser.hh \
+ dnspcap.cc dnspcap.hh \
+ dnsrecords.cc \
+ dnswriter.cc dnswriter.hh \
+ logger.cc \
+ misc.cc \
+ nsecrecords.cc \
+ qtype.cc \
+ rcpgenerator.cc rcpgenerator.hh \
+ sillyrecords.cc \
+ statbag.cc \
+ unix_utility.cc \
+ utility.hh
+
+dnsdemog_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS)
+
+dnsdemog_LDADD = \
+ $(LIBCRYPTO_LIBS)
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnspcap2protobuf_SOURCES = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ base32.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ base64.cc base64.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnslabeltext.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsname.cc dnsname.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsparser.cc dnsparser.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnspcap.cc dnspcap.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnspcap2protobuf.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsrecords.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnswriter.cc dnswriter.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ gettime.cc gettime.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ iputils.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ logger.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ misc.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ nsecrecords.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ protobuf.cc protobuf.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ qtype.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ rcpgenerator.cc rcpgenerator.hh \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ sillyrecords.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ statbag.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ unix_utility.cc \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ utility.hh
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_dnspcap2protobuf_SOURCES = dnsmessage.pb.cc dnsmessage.pb.h
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnspcap2protobuf_LDFLAGS = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(AM_LDFLAGS) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(LIBCRYPTO_LDFLAGS) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(BOOST_PROGRAM_OPTIONS_LDFLAGS)
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnspcap2protobuf_LDADD = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(LIBCRYPTO_LIBS) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(PROTOBUF_LIBS) \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(BOOST_PROGRAM_OPTIONS_LIBS)
+
+testrunner_SOURCES = arguments.cc base32.cc base64.cc bindlexer.l \
+ bindparser.yy dbdnsseckeeper.cc dns.cc dns_random.cc \
+ dnsbackend.cc dnslabeltext.cc dnsname.cc dnsname.hh \
+ dnspacket.cc dnsparser.hh dnsparser.cc dnsrecords.cc \
+ dnssecinfra.cc dnssecsigner.cc dnswriter.cc ednsoptions.cc \
+ ednsoptions.hh ednssubnet.cc gettime.cc gettime.hh \
+ gss_context.cc gss_context.hh iputils.cc logger.cc misc.cc \
+ nameserver.cc nsecrecords.cc packetcache.cc qtype.cc \
+ rcpgenerator.cc recpacketcache.cc recpacketcache.hh \
+ rec-protobuf.hh responsestats.cc responsestats-auth.cc \
+ sillyrecords.cc statbag.cc test-arguments_cc.cc \
+ test-base32_cc.cc test-base64_cc.cc test-bindparser_cc.cc \
+ test-delaypipe_hh.cc test-distributor_hh.cc \
+ test-dns_random_hh.cc test-dnsname_cc.cc test-dnsparser_hh.cc \
+ test-dnsrecords_cc.cc test-iputils_hh.cc test-md5_hh.cc \
+ test-misc_hh.cc test-nameserver_cc.cc test-nmtree.cc \
+ test-packetcache_cc.cc test-rcpgenerator_cc.cc \
+ test-recpacketcache_cc.cc test-signers.cc test-sha_hh.cc \
+ test-statbag_cc.cc test-zoneparser_tng_cc.cc testrunner.cc \
+ ueberbackend.cc unix_utility.cc zoneparser-tng.cc \
+ zoneparser-tng.hh $(am__append_55) $(am__append_57) \
+ $(am__append_59)
+testrunner_LDFLAGS = \
+ $(AM_LDFLAGS) \
+ $(LIBCRYPTO_LDFLAGS) \
+ $(BOOST_UNIT_TEST_FRAMEWORK_LDFLAGS)
+
+testrunner_LDADD = $(LIBCRYPTO_LIBS) $(BOOST_UNIT_TEST_FRAMEWORK_LIBS) \
+ $(RT_LIBS) $(LIBDL) $(am__append_54) $(am__append_56) \
+ $(am__append_58) $(am__append_60)
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@nodist_testrunner_SOURCES = \
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ dnsmessage.pb.cc dnsmessage.pb.h
+
+pdns_control_SOURCES = \
+ arguments.cc \
+ dynloader.cc \
+ dynmessenger.cc \
+ logger.cc \
+ misc.cc \
+ qtype.cc \
+ statbag.cc \
+ unix_utility.cc \
+ dnsname.cc \
+ dnslabeltext.cc
+
+@HAVE_BOOST_GE_148_TRUE@@UNIT_TESTS_TRUE@TESTS_ENVIRONMENT = env BOOST_TEST_LOG_LEVEL=message SRCDIR='$(srcdir)'
+curl_verbose = $(curl_verbose_$(V))
+curl_verbose_ = $(curl_verbose_$(AM_DEFAULT_VERBOSITY))
+curl_verbose_0 = @echo " CURL " $@;
+@HAVE_SYSTEMD_TRUE@systemdsystemunitdir = $(SYSTEMD_DIR)
+@HAVE_SYSTEMD_TRUE@systemdsystemunit_DATA = \
+@HAVE_SYSTEMD_TRUE@ pdns.service \
+@HAVE_SYSTEMD_TRUE@ pdns@.service
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .cc .h .hh .l .lo .log .o .obj .test .test$(EXEEXT) .trs .yy
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
+ @for dep in $?; do \
+ case '$(am__configure_deps)' in \
+ *$$dep*) \
+ ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \
+ && { if test -f $@; then exit 0; else break; fi; }; \
+ exit 1;; \
+ esac; \
+ done; \
+ echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign pdns/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign pdns/Makefile
+.PRECIOUS: Makefile
+Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
+ @case '$?' in \
+ *config.status*) \
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \
+ *) \
+ echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ esac;
+
+$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+
+$(top_srcdir)/configure: $(am__configure_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
+ cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
+$(am__aclocal_m4_deps):
+pdns.init: $(top_builddir)/config.status $(srcdir)/pdns.init.in
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@
+install-binPROGRAMS: $(bin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-binPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(bindir)" && rm -f $$files
+
+clean-binPROGRAMS:
+ @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+install-sbinPROGRAMS: $(sbin_PROGRAMS)
+ @$(NORMAL_INSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sbindir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sbindir)" || exit 1; \
+ fi; \
+ for p in $$list; do echo "$$p $$p"; done | \
+ sed 's/$(EXEEXT)$$//' | \
+ while read p p1; do if test -f $$p \
+ || test -f $$p1 \
+ ; then echo "$$p"; echo "$$p"; else :; fi; \
+ done | \
+ sed -e 'p;s,.*/,,;n;h' \
+ -e 's|.*|.|' \
+ -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \
+ sed 'N;N;N;s,\n, ,g' | \
+ $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \
+ { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \
+ if ($$2 == $$4) files[d] = files[d] " " $$1; \
+ else { print "f", $$3 "/" $$4, $$1; } } \
+ END { for (d in files) print "f", d, files[d] }' | \
+ while read type dir files; do \
+ if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
+ test -z "$$files" || { \
+ echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
+ $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+ } \
+ ; done
+
+uninstall-sbinPROGRAMS:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+ files=`for p in $$list; do echo "$$p"; done | \
+ sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
+ -e 's/$$/$(EXEEXT)/' \
+ `; \
+ test -n "$$list" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+
+clean-sbinPROGRAMS:
+ @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+ echo " rm -f" $$list; \
+ rm -f $$list || exit $$?; \
+ test -n "$(EXEEXT)" || exit 0; \
+ list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+ echo " rm -f" $$list; \
+ rm -f $$list
+
+calidns$(EXEEXT): $(calidns_OBJECTS) $(calidns_DEPENDENCIES) $(EXTRA_calidns_DEPENDENCIES)
+ @rm -f calidns$(EXEEXT)
+ $(AM_V_CXXLD)$(calidns_LINK) $(calidns_OBJECTS) $(calidns_LDADD) $(LIBS)
+
+comfun$(EXEEXT): $(comfun_OBJECTS) $(comfun_DEPENDENCIES) $(EXTRA_comfun_DEPENDENCIES)
+ @rm -f comfun$(EXEEXT)
+ $(AM_V_CXXLD)$(comfun_LINK) $(comfun_OBJECTS) $(comfun_LDADD) $(LIBS)
+
+dnsbulktest$(EXEEXT): $(dnsbulktest_OBJECTS) $(dnsbulktest_DEPENDENCIES) $(EXTRA_dnsbulktest_DEPENDENCIES)
+ @rm -f dnsbulktest$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsbulktest_LINK) $(dnsbulktest_OBJECTS) $(dnsbulktest_LDADD) $(LIBS)
+
+dnsdemog$(EXEEXT): $(dnsdemog_OBJECTS) $(dnsdemog_DEPENDENCIES) $(EXTRA_dnsdemog_DEPENDENCIES)
+ @rm -f dnsdemog$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsdemog_LINK) $(dnsdemog_OBJECTS) $(dnsdemog_LDADD) $(LIBS)
+
+dnsgram$(EXEEXT): $(dnsgram_OBJECTS) $(dnsgram_DEPENDENCIES) $(EXTRA_dnsgram_DEPENDENCIES)
+ @rm -f dnsgram$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsgram_LINK) $(dnsgram_OBJECTS) $(dnsgram_LDADD) $(LIBS)
+
+dnspcap2protobuf$(EXEEXT): $(dnspcap2protobuf_OBJECTS) $(dnspcap2protobuf_DEPENDENCIES) $(EXTRA_dnspcap2protobuf_DEPENDENCIES)
+ @rm -f dnspcap2protobuf$(EXEEXT)
+ $(AM_V_CXXLD)$(dnspcap2protobuf_LINK) $(dnspcap2protobuf_OBJECTS) $(dnspcap2protobuf_LDADD) $(LIBS)
+
+dnsreplay$(EXEEXT): $(dnsreplay_OBJECTS) $(dnsreplay_DEPENDENCIES) $(EXTRA_dnsreplay_DEPENDENCIES)
+ @rm -f dnsreplay$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsreplay_LINK) $(dnsreplay_OBJECTS) $(dnsreplay_LDADD) $(LIBS)
+
+dnsscan$(EXEEXT): $(dnsscan_OBJECTS) $(dnsscan_DEPENDENCIES) $(EXTRA_dnsscan_DEPENDENCIES)
+ @rm -f dnsscan$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsscan_LINK) $(dnsscan_OBJECTS) $(dnsscan_LDADD) $(LIBS)
+
+dnsscope$(EXEEXT): $(dnsscope_OBJECTS) $(dnsscope_DEPENDENCIES) $(EXTRA_dnsscope_DEPENDENCIES)
+ @rm -f dnsscope$(EXEEXT)
+ $(AM_V_CXXLD)$(dnsscope_LINK) $(dnsscope_OBJECTS) $(dnsscope_LDADD) $(LIBS)
+
+dnstcpbench$(EXEEXT): $(dnstcpbench_OBJECTS) $(dnstcpbench_DEPENDENCIES) $(EXTRA_dnstcpbench_DEPENDENCIES)
+ @rm -f dnstcpbench$(EXEEXT)
+ $(AM_V_CXXLD)$(dnstcpbench_LINK) $(dnstcpbench_OBJECTS) $(dnstcpbench_LDADD) $(LIBS)
+
+dnswasher$(EXEEXT): $(dnswasher_OBJECTS) $(dnswasher_DEPENDENCIES) $(EXTRA_dnswasher_DEPENDENCIES)
+ @rm -f dnswasher$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(dnswasher_OBJECTS) $(dnswasher_LDADD) $(LIBS)
+
+dumresp$(EXEEXT): $(dumresp_OBJECTS) $(dumresp_DEPENDENCIES) $(EXTRA_dumresp_DEPENDENCIES)
+ @rm -f dumresp$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(dumresp_OBJECTS) $(dumresp_LDADD) $(LIBS)
+
+ixplore$(EXEEXT): $(ixplore_OBJECTS) $(ixplore_DEPENDENCIES) $(EXTRA_ixplore_DEPENDENCIES)
+ @rm -f ixplore$(EXEEXT)
+ $(AM_V_CXXLD)$(ixplore_LINK) $(ixplore_OBJECTS) $(ixplore_LDADD) $(LIBS)
+
+kvresp$(EXEEXT): $(kvresp_OBJECTS) $(kvresp_DEPENDENCIES) $(EXTRA_kvresp_DEPENDENCIES)
+ @rm -f kvresp$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(kvresp_OBJECTS) $(kvresp_LDADD) $(LIBS)
+
+nproxy$(EXEEXT): $(nproxy_OBJECTS) $(nproxy_DEPENDENCIES) $(EXTRA_nproxy_DEPENDENCIES)
+ @rm -f nproxy$(EXEEXT)
+ $(AM_V_CXXLD)$(nproxy_LINK) $(nproxy_OBJECTS) $(nproxy_LDADD) $(LIBS)
+
+nsec3dig$(EXEEXT): $(nsec3dig_OBJECTS) $(nsec3dig_DEPENDENCIES) $(EXTRA_nsec3dig_DEPENDENCIES)
+ @rm -f nsec3dig$(EXEEXT)
+ $(AM_V_CXXLD)$(nsec3dig_LINK) $(nsec3dig_OBJECTS) $(nsec3dig_LDADD) $(LIBS)
+
+pdns_control$(EXEEXT): $(pdns_control_OBJECTS) $(pdns_control_DEPENDENCIES) $(EXTRA_pdns_control_DEPENDENCIES)
+ @rm -f pdns_control$(EXEEXT)
+ $(AM_V_CXXLD)$(CXXLINK) $(pdns_control_OBJECTS) $(pdns_control_LDADD) $(LIBS)
+
+pdns_notify$(EXEEXT): $(pdns_notify_OBJECTS) $(pdns_notify_DEPENDENCIES) $(EXTRA_pdns_notify_DEPENDENCIES)
+ @rm -f pdns_notify$(EXEEXT)
+ $(AM_V_CXXLD)$(pdns_notify_LINK) $(pdns_notify_OBJECTS) $(pdns_notify_LDADD) $(LIBS)
+backends/gsql/$(am__dirstamp):
+ @$(MKDIR_P) backends/gsql
+ @: > backends/gsql/$(am__dirstamp)
+backends/gsql/$(DEPDIR)/$(am__dirstamp):
+ @$(MKDIR_P) backends/gsql/$(DEPDIR)
+ @: > backends/gsql/$(DEPDIR)/$(am__dirstamp)
+backends/gsql/gsqlbackend.$(OBJEXT): backends/gsql/$(am__dirstamp) \
+ backends/gsql/$(DEPDIR)/$(am__dirstamp)
+
+pdns_server$(EXEEXT): $(pdns_server_OBJECTS) $(pdns_server_DEPENDENCIES) $(EXTRA_pdns_server_DEPENDENCIES)
+ @rm -f pdns_server$(EXEEXT)
+ $(AM_V_CXXLD)$(pdns_server_LINK) $(pdns_server_OBJECTS) $(pdns_server_LDADD) $(LIBS)
+bindparser.hh: bindparser.cc
+ @if test ! -f $@; then rm -f bindparser.cc; else :; fi
+ @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) bindparser.cc; else :; fi
+
+pdnsutil$(EXEEXT): $(pdnsutil_OBJECTS) $(pdnsutil_DEPENDENCIES) $(EXTRA_pdnsutil_DEPENDENCIES)
+ @rm -f pdnsutil$(EXEEXT)
+ $(AM_V_CXXLD)$(pdnsutil_LINK) $(pdnsutil_OBJECTS) $(pdnsutil_LDADD) $(LIBS)
+
+saxfr$(EXEEXT): $(saxfr_OBJECTS) $(saxfr_DEPENDENCIES) $(EXTRA_saxfr_DEPENDENCIES)
+ @rm -f saxfr$(EXEEXT)
+ $(AM_V_CXXLD)$(saxfr_LINK) $(saxfr_OBJECTS) $(saxfr_LDADD) $(LIBS)
+
+sdig$(EXEEXT): $(sdig_OBJECTS) $(sdig_DEPENDENCIES) $(EXTRA_sdig_DEPENDENCIES)
+ @rm -f sdig$(EXEEXT)
+ $(AM_V_CXXLD)$(sdig_LINK) $(sdig_OBJECTS) $(sdig_LDADD) $(LIBS)
+
+speedtest$(EXEEXT): $(speedtest_OBJECTS) $(speedtest_DEPENDENCIES) $(EXTRA_speedtest_DEPENDENCIES)
+ @rm -f speedtest$(EXEEXT)
+ $(AM_V_CXXLD)$(speedtest_LINK) $(speedtest_OBJECTS) $(speedtest_LDADD) $(LIBS)
+
+stubquery$(EXEEXT): $(stubquery_OBJECTS) $(stubquery_DEPENDENCIES) $(EXTRA_stubquery_DEPENDENCIES)
+ @rm -f stubquery$(EXEEXT)
+ $(AM_V_CXXLD)$(stubquery_LINK) $(stubquery_OBJECTS) $(stubquery_LDADD) $(LIBS)
+
+testrunner$(EXEEXT): $(testrunner_OBJECTS) $(testrunner_DEPENDENCIES) $(EXTRA_testrunner_DEPENDENCIES)
+ @rm -f testrunner$(EXEEXT)
+ $(AM_V_CXXLD)$(testrunner_LINK) $(testrunner_OBJECTS) $(testrunner_LDADD) $(LIBS)
+
+toysdig$(EXEEXT): $(toysdig_OBJECTS) $(toysdig_DEPENDENCIES) $(EXTRA_toysdig_DEPENDENCIES)
+ @rm -f toysdig$(EXEEXT)
+ $(AM_V_CXXLD)$(toysdig_LINK) $(toysdig_OBJECTS) $(toysdig_LDADD) $(LIBS)
+
+tsig-tests$(EXEEXT): $(tsig_tests_OBJECTS) $(tsig_tests_DEPENDENCIES) $(EXTRA_tsig_tests_DEPENDENCIES)
+ @rm -f tsig-tests$(EXEEXT)
+ $(AM_V_CXXLD)$(tsig_tests_LINK) $(tsig_tests_OBJECTS) $(tsig_tests_LDADD) $(LIBS)
+
+zone2json$(EXEEXT): $(zone2json_OBJECTS) $(zone2json_DEPENDENCIES) $(EXTRA_zone2json_DEPENDENCIES)
+ @rm -f zone2json$(EXEEXT)
+ $(AM_V_CXXLD)$(zone2json_LINK) $(zone2json_OBJECTS) $(zone2json_LDADD) $(LIBS)
+
+zone2ldap$(EXEEXT): $(zone2ldap_OBJECTS) $(zone2ldap_DEPENDENCIES) $(EXTRA_zone2ldap_DEPENDENCIES)
+ @rm -f zone2ldap$(EXEEXT)
+ $(AM_V_CXXLD)$(zone2ldap_LINK) $(zone2ldap_OBJECTS) $(zone2ldap_LDADD) $(LIBS)
+
+zone2sql$(EXEEXT): $(zone2sql_OBJECTS) $(zone2sql_DEPENDENCIES) $(EXTRA_zone2sql_DEPENDENCIES)
+ @rm -f zone2sql$(EXEEXT)
+ $(AM_V_CXXLD)$(zone2sql_LINK) $(zone2sql_OBJECTS) $(zone2sql_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+ -rm -f backends/gsql/*.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/arguments.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/auth-carbon.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/base64.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bindlexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/bindparser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/botan110signers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/calidns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/comfun.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/common_startup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/communicator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dbdnsseckeeper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/decafsigners.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dns_random.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsbackend.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsbulktest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsdemog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsgram.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnslabeltext.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsmessage.pb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnspacket.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsparser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnspcap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnspcap2protobuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsproxy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsrecords.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsreplay.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsscan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnsscope.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnssecinfra.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnssecsigner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnstcpbench.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnswasher.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dnswriter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dumresp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynhandler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynlistener.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynloader.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/dynmessenger.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednsoptions.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ednssubnet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gettime.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gss_context.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/iputils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ixfr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ixplore.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/kvresp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/logger.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lua-auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lua-iputils.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/lua-pdns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mastercommunicator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/misc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nameserver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/notify.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nproxy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsec3dig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/nsecrecords.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/opensslsigners.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packetcache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/packethandler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pdnsutil.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/pkcs11signers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/protobuf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/qtype.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/randomhelper.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rcpgenerator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/receiver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/recpacketcache.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/resolver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/responsestats-auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/responsestats.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/rfc2136handler.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/saxfr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sdig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/secpoll-auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/selectmplexer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/serialtweaker.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/signingpipe.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sillyrecords.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/slavecommunicator.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/sodiumsigners.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/speedtest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ssqlite3.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statbag.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/statnode.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stubquery.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/stubresolver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tcpreceiver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-arguments_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base32_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-base64_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-bindparser_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-delaypipe_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-distributor_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dns_random_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsname_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsparser_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-dnsrecords_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-iputils_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-md5_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-misc_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nameserver_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-nmtree.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-packetcache_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-rcpgenerator_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-recpacketcache_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-sha_hh.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-signers.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-statbag_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/test-zoneparser_tng_cc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testrunner.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tkey.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/toysdig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsig-tests.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/tsigverifier.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ueberbackend.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix_semaphore.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/unix_utility.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/validate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/version.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/webserver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ws-api.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ws-auth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone2json.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone2ldap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zone2sql.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/zoneparser-tng.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@backends/gsql/$(DEPDIR)/gsqlbackend.Po@am__quote@
+
+.c.o:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $<
+
+.c.obj:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCC_TRUE@ $(COMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.c.lo:
+@am__fastdepCC_TRUE@ $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCC_TRUE@ $(LTCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCC_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
+
+.cc.o:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ $<
+
+.cc.obj:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.obj$$||'`;\
+@am__fastdepCXX_TRUE@ $(CXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ `$(CYGPATH_W) '$<'` &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Po
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(CXXCOMPILE) -c -o $@ `$(CYGPATH_W) '$<'`
+
+.cc.lo:
+@am__fastdepCXX_TRUE@ $(AM_V_CXX)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.lo$$||'`;\
+@am__fastdepCXX_TRUE@ $(LTCXXCOMPILE) -MT $@ -MD -MP -MF $$depbase.Tpo -c -o $@ $< &&\
+@am__fastdepCXX_TRUE@ $(am__mv) $$depbase.Tpo $$depbase.Plo
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ $(AM_V_CXX)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCXX_FALSE@ $(AM_V_CXX@am__nodep@)$(LTCXXCOMPILE) -c -o $@ $<
+
+.l.c:
+ $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
+
+.yy.cc:
+ $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h `echo $@ | $(am__yacc_c2h)` y.output $*.output -- $(YACCCOMPILE)
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-sysconfDATA: $(sysconf_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(sysconfdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(sysconfdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(sysconfdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(sysconfdir)" || exit $$?; \
+ done
+
+uninstall-sysconfDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(sysconf_DATA)'; test -n "$(sysconfdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(sysconfdir)'; $(am__uninstall_files_from_dir)
+install-systemdsystemunitDATA: $(systemdsystemunit_DATA)
+ @$(NORMAL_INSTALL)
+ @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \
+ fi; \
+ for p in $$list; do \
+ if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+ echo "$$d$$p"; \
+ done | $(am__base_list) | \
+ while read files; do \
+ echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \
+ done
+
+uninstall-systemdsystemunitDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir)
+
+ID: $(am__tagged_files)
+ $(am__define_uniq_tagged_files); mkid -fID $$unique
+tags: tags-am
+TAGS: tags
+
+tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ set x; \
+ here=`pwd`; \
+ $(am__define_uniq_tagged_files); \
+ shift; \
+ if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \
+ test -n "$$unique" || unique=$$empty_fix; \
+ if test $$# -gt 0; then \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ "$$@" $$unique; \
+ else \
+ $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \
+ $$unique; \
+ fi; \
+ fi
+ctags: ctags-am
+
+CTAGS: ctags
+ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files)
+ $(am__define_uniq_tagged_files); \
+ test -z "$(CTAGS_ARGS)$$unique" \
+ || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \
+ $$unique
+
+GTAGS:
+ here=`$(am__cd) $(top_builddir) && pwd` \
+ && $(am__cd) $(top_srcdir) \
+ && gtags -i $(GTAGS_ARGS) "$$here"
+cscopelist: cscopelist-am
+
+cscopelist-am: $(am__tagged_files)
+ list='$(am__tagged_files)'; \
+ case "$(srcdir)" in \
+ [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \
+ *) sdir=$(subdir)/$(srcdir) ;; \
+ esac; \
+ for i in $$list; do \
+ if test -f "$$i"; then \
+ echo "$(subdir)/$$i"; \
+ else \
+ echo "$$sdir/$$i"; \
+ fi; \
+ done >> $(top_builddir)/cscope.files
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+# Recover from deleted '.trs' file; this should ensure that
+# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create
+# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells
+# to avoid problems with "make -n".
+.log.trs:
+ rm -f $< $@
+ $(MAKE) $(AM_MAKEFLAGS) $<
+
+# Leading 'am--fnord' is there to ensure the list of targets does not
+# expand to empty, as could happen e.g. with make check TESTS=''.
+am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck)
+am--force-recheck:
+ @:
+
+$(TEST_SUITE_LOG): $(TEST_LOGS)
+ @$(am__set_TESTS_bases); \
+ am__f_ok () { test -f "$$1" && test -r "$$1"; }; \
+ redo_bases=`for i in $$bases; do \
+ am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \
+ done`; \
+ if test -n "$$redo_bases"; then \
+ redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \
+ redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \
+ if $(am__make_dryrun); then :; else \
+ rm -f $$redo_logs && rm -f $$redo_results || exit 1; \
+ fi; \
+ fi; \
+ if test -n "$$am__remaking_logs"; then \
+ echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \
+ "recursion detected" >&2; \
+ else \
+ am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \
+ fi; \
+ if $(am__make_dryrun); then :; else \
+ st=0; \
+ errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \
+ for i in $$redo_bases; do \
+ test -f $$i.trs && test -r $$i.trs \
+ || { echo "$$errmsg $$i.trs" >&2; st=1; }; \
+ test -f $$i.log && test -r $$i.log \
+ || { echo "$$errmsg $$i.log" >&2; st=1; }; \
+ done; \
+ test $$st -eq 0 || exit 1; \
+ fi
+ @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \
+ ws='[ ]'; \
+ results=`for b in $$bases; do echo $$b.trs; done`; \
+ test -n "$$results" || results=/dev/null; \
+ all=` grep "^$$ws*:test-result:" $$results | wc -l`; \
+ pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \
+ fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \
+ skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \
+ xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \
+ xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \
+ error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \
+ if test `expr $$fail + $$xpass + $$error` -eq 0; then \
+ success=true; \
+ else \
+ success=false; \
+ fi; \
+ br='==================='; br=$$br$$br$$br$$br; \
+ result_count () \
+ { \
+ if test x"$$1" = x"--maybe-color"; then \
+ maybe_colorize=yes; \
+ elif test x"$$1" = x"--no-color"; then \
+ maybe_colorize=no; \
+ else \
+ echo "$@: invalid 'result_count' usage" >&2; exit 4; \
+ fi; \
+ shift; \
+ desc=$$1 count=$$2; \
+ if test $$maybe_colorize = yes && test $$count -gt 0; then \
+ color_start=$$3 color_end=$$std; \
+ else \
+ color_start= color_end=; \
+ fi; \
+ echo "$${color_start}# $$desc $$count$${color_end}"; \
+ }; \
+ create_testsuite_report () \
+ { \
+ result_count $$1 "TOTAL:" $$all "$$brg"; \
+ result_count $$1 "PASS: " $$pass "$$grn"; \
+ result_count $$1 "SKIP: " $$skip "$$blu"; \
+ result_count $$1 "XFAIL:" $$xfail "$$lgn"; \
+ result_count $$1 "FAIL: " $$fail "$$red"; \
+ result_count $$1 "XPASS:" $$xpass "$$red"; \
+ result_count $$1 "ERROR:" $$error "$$mgn"; \
+ }; \
+ { \
+ echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \
+ $(am__rst_title); \
+ create_testsuite_report --no-color; \
+ echo; \
+ echo ".. contents:: :depth: 2"; \
+ echo; \
+ for b in $$bases; do echo $$b; done \
+ | $(am__create_global_log); \
+ } >$(TEST_SUITE_LOG).tmp || exit 1; \
+ mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \
+ if $$success; then \
+ col="$$grn"; \
+ else \
+ col="$$red"; \
+ test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \
+ fi; \
+ echo "$${col}$$br$${std}"; \
+ echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \
+ echo "$${col}$$br$${std}"; \
+ create_testsuite_report --maybe-color; \
+ echo "$$col$$br$$std"; \
+ if $$success; then :; else \
+ echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \
+ if test -n "$(PACKAGE_BUGREPORT)"; then \
+ echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \
+ fi; \
+ echo "$$col$$br$$std"; \
+ fi; \
+ $$success || exit 1
+
+check-TESTS:
+ @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list
+ @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ trs_list=`for i in $$bases; do echo $$i.trs; done`; \
+ log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \
+ exit $$?;
+recheck: all
+ @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+ @set +e; $(am__set_TESTS_bases); \
+ bases=`for i in $$bases; do echo $$i; done \
+ | $(am__list_recheck_tests)` || exit 1; \
+ log_list=`for i in $$bases; do echo $$i.log; done`; \
+ log_list=`echo $$log_list`; \
+ $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \
+ am__force_recheck=am--force-recheck \
+ TEST_LOGS="$$log_list"; \
+ exit $$?
+testrunner.log: testrunner$(EXEEXT)
+ @p='testrunner$(EXEEXT)'; \
+ b='testrunner'; \
+ $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+.test.log:
+ @p='$<'; \
+ $(am__set_b); \
+ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+ --log-file $$b.log --trs-file $$b.trs \
+ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+ "$$tst" $(AM_TESTS_FD_REDIRECT)
+@am__EXEEXT_TRUE@.test$(EXEEXT).log:
+@am__EXEEXT_TRUE@ @p='$<'; \
+@am__EXEEXT_TRUE@ $(am__set_b); \
+@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \
+@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \
+@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \
+@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT)
+
+distdir: $(DISTFILES)
+ @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \
+ list='$(DISTFILES)'; \
+ dist_files=`for file in $$list; do echo $$file; done | \
+ sed -e "s|^$$srcdirstrip/||;t" \
+ -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \
+ case $$dist_files in \
+ */*) $(MKDIR_P) `echo "$$dist_files" | \
+ sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \
+ sort -u` ;; \
+ esac; \
+ for file in $$dist_files; do \
+ if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \
+ if test -d $$d/$$file; then \
+ dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \
+ if test -d "$(distdir)/$$file"; then \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \
+ cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \
+ find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \
+ fi; \
+ cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \
+ else \
+ test -f "$(distdir)/$$file" \
+ || cp -p $$d/$$file "$(distdir)/$$file" \
+ || exit 1; \
+ fi; \
+ done
+@HAVE_BOOST_GE_148_TRUE@@UNIT_TESTS_TRUE@check-local:
+check-am: all-am
+ $(MAKE) $(AM_MAKEFLAGS) check-TESTS check-local
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-am
+all-am: Makefile $(PROGRAMS) $(SCRIPTS) $(DATA)
+installdirs:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(sysconfdir)" "$(DESTDIR)$(systemdsystemunitdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-am
+install-exec: install-exec-am
+install-data: install-data-am
+uninstall: uninstall-am
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-am
+install-strip:
+ if test -z '$(STRIP)'; then \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ install; \
+ else \
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \
+ fi
+mostlyclean-generic:
+ -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS)
+ -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs)
+ -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG)
+
+clean-generic:
+ -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES)
+
+distclean-generic:
+ -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
+ -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
+ -rm -f backends/gsql/$(DEPDIR)/$(am__dirstamp)
+ -rm -f backends/gsql/$(am__dirstamp)
+
+maintainer-clean-generic:
+ @echo "This command is intended for maintainers to use"
+ @echo "it deletes files that may require special tools to rebuild."
+ -rm -f bindlexer.c
+ -rm -f bindparser.cc
+ -rm -f bindparser.hh
+ -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
+clean: clean-am
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool \
+ clean-sbinPROGRAMS mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR) backends/gsql/$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-am
+
+dvi-am:
+
+html: html-am
+
+html-am:
+
+info: info-am
+
+info-am:
+
+install-data-am: install-systemdsystemunitDATA
+
+install-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS install-sbinPROGRAMS \
+ install-sysconfDATA
+
+install-html: install-html-am
+
+install-html-am:
+
+install-info: install-info-am
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-am
+
+install-pdf-am:
+
+install-ps: install-ps-am
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-am
+ -rm -rf ./$(DEPDIR) backends/gsql/$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-am
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-am
+
+pdf-am:
+
+ps: ps-am
+
+ps-am:
+
+uninstall-am: uninstall-binPROGRAMS uninstall-sbinPROGRAMS \
+ uninstall-sysconfDATA uninstall-systemdsystemunitDATA
+
+.MAKE: all check check-am install install-am install-strip
+
+.PHONY: CTAGS GTAGS TAGS all all-am check check-TESTS check-am \
+ check-local clean clean-binPROGRAMS clean-generic \
+ clean-libtool clean-sbinPROGRAMS cscopelist-am ctags ctags-am \
+ distclean distclean-compile distclean-generic \
+ distclean-libtool distclean-tags distdir dvi dvi-am html \
+ html-am info info-am install install-am install-binPROGRAMS \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man install-pdf \
+ install-pdf-am install-ps install-ps-am install-sbinPROGRAMS \
+ install-strip install-sysconfDATA \
+ install-systemdsystemunitDATA installcheck installcheck-am \
+ installdirs maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am recheck tags tags-am \
+ uninstall uninstall-am uninstall-binPROGRAMS \
+ uninstall-sbinPROGRAMS uninstall-sysconfDATA \
+ uninstall-systemdsystemunitDATA
+
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnsmessage.pb.cc: dnsmessage.proto
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@ $(AM_V_GEN)$(PROTOC) --cpp_out=./ $<
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@dnspcap2protobuf.$(OBJEXT): dnsmessage.pb.cc
+
+pdns.conf-dist: pdns_server
+ $(AM_V_GEN)./pdns_server --no-config --config 2>/dev/null > $@
+
+@HAVE_PROTOBUF_TRUE@@HAVE_PROTOC_TRUE@recpacketcache.$(OBJEXT): dnsmessage.pb.cc
+@HAVE_BOOST_GE_148_FALSE@@UNIT_TESTS_TRUE@check-local:
+@HAVE_BOOST_GE_148_FALSE@@UNIT_TESTS_TRUE@ @echo "Unit tests disabled, boost is too old"
+
+@UNIT_TESTS_FALSE@check-local:
+@UNIT_TESTS_FALSE@ @echo "Unit tests are not enabled"
+@UNIT_TESTS_FALSE@ @echo "Run ./configure --enable-unit-tests"
+
+dnslabeltext.cc: dnslabeltext.rl
+ $(AM_V_GEN)$(RAGEL) $< -o dnslabeltext.cc
+
+bind-dnssec.schema.sqlite3.sql.h: bind-dnssec.schema.sqlite3.sql
+ ( echo 'static char sqlCreate[] __attribute__((unused))=' ; sed 's/$$/"/g' $< | sed 's/^/"/g' ; echo ';' ) > $@
+
+# for bindparser.h/hh
+.hh.h:
+ cp $< $@
+
+bindlexer.$(OBJEXT): bindparser.h
+$(srcdir)/effective_tld_names.dat:
+ $(curl_verbose)if ! curl -s -S https://publicsuffix.org/list/public_suffix_list.dat > $@; then rm -f $@; exit 1; fi
+
+pubsuffix.cc: $(srcdir)/effective_tld_names.dat
+ $(AM_V_GEN)./mkpubsuffixcc
+
+pdns_recursor rec_control:
+ @echo "Please build the recursor from the recursordist/ dir"
+ @exit 1
+
+dnsdist:
+ @echo "Please build dnsdist from the dnsdistdist/ dir"
+ @exit 1
+
+@HAVE_SYSTEMD_TRUE@pdns.service: pdns.service.in
+@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's![@]sbindir[@]!$(sbindir)!' < $< > $@
+
+@HAVE_SYSTEMD_TRUE@pdns@.service: pdns.service
+@HAVE_SYSTEMD_TRUE@ $(AM_V_GEN)sed -e 's!/pdns_server!& --config-name=%i!' \
+@HAVE_SYSTEMD_TRUE@ -e 's!Authoritative Server!& %i!' \
+@HAVE_SYSTEMD_TRUE@ < $< > $@
+
+# Tell versions [3.59,3.63) of GNU make to not export all variables.
+# Otherwise a system limit (for SysV at least) may be exceeded.
+.NOEXPORT:
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_ANADNS_HH
+#define PDNS_ANADNS_HH
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <string>
+#include <netinet/ip.h>
+#include <netinet/udp.h>
+#include "dnsparser.hh"
+#include "iputils.hh"
+#include "namespaces.hh"
+
+struct QuestionIdentifier
+{
+ QuestionIdentifier()
+ {}
+
+ bool operator<(const QuestionIdentifier& rhs) const
+ {
+ return
+ tie(d_source, d_dest, d_qname, d_qtype, d_id) <
+ tie(rhs.d_source, rhs.d_dest, rhs.d_qname, rhs.d_qtype, rhs.d_id);
+ }
+
+ // the canonical direction is that of the question
+ static QuestionIdentifier create(const ComboAddress& src, const ComboAddress& dst, const MOADNSParser& mdp)
+ {
+ QuestionIdentifier ret;
+
+ if(mdp.d_header.qr) {
+ ret.d_source = dst;
+ ret.d_dest = src;
+ }
+ else {
+ ret.d_source = src;
+ ret.d_dest = dst;
+ }
+ ret.d_qname=mdp.d_qname;
+ ret.d_qtype=mdp.d_qtype;
+ ret.d_id=mdp.d_header.id;
+ return ret;
+ }
+
+ ComboAddress d_source, d_dest;
+
+ DNSName d_qname;
+ uint16_t d_qtype;
+ uint16_t d_id;
+};
+
+inline ostream& operator<<(ostream &s, const QuestionIdentifier& qi)
+{
+ s<< "'"<<qi.d_qname<<"|"<<DNSRecordContent::NumberToType(qi.d_qtype)<<"', with id " << qi.d_id <<" from "<<qi.d_source.toStringWithPort();
+
+ s<<" to " << qi.d_dest.toStringWithPort();
+ return s;
+}
+
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "arguments.hh"
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/compare.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+
+#include "namespaces.hh"
+#include "logger.hh"
+#include <sys/types.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <limits.h>
+
+const ArgvMap::param_t::const_iterator ArgvMap::begin()
+{
+ return params.begin();
+}
+
+const ArgvMap::param_t::const_iterator ArgvMap::end()
+{
+ return params.end();
+}
+
+string & ArgvMap::set(const string &var)
+{
+ return params[var];
+}
+
+bool ArgvMap::mustDo(const string &var)
+{
+ return ((*this)[var]!="no") && ((*this)[var]!="off");
+}
+
+vector<string>ArgvMap::list()
+{
+ vector<string> ret;
+ for(map<string,string>::const_iterator i=params.begin();i!=params.end();++i)
+ ret.push_back(i->first);
+ return ret;
+}
+
+string ArgvMap::getHelp(const string &item)
+{
+ return helpmap[item];
+}
+
+string & ArgvMap::set(const string &var, const string &help)
+{
+ helpmap[var]=help;
+ d_typeMap[var]="Parameter";
+ return set(var);
+}
+
+void ArgvMap::setCmd(const string &var, const string &help)
+{
+ helpmap[var]=help;
+ d_typeMap[var]="Command";
+ set(var)="no";
+}
+
+string & ArgvMap::setSwitch(const string &var, const string &help)
+{
+ helpmap[var]=help;
+ d_typeMap[var]="Switch";
+ return set(var);
+}
+
+
+bool ArgvMap::contains(const string &var, const string &val)
+{
+ params_t::const_iterator param = params.find(var);
+ if(param == params.end() || param->second.empty()) {
+ return false;
+ }
+ vector<string> parts;
+ vector<string>::const_iterator i;
+
+ stringtok( parts, param->second, ", \t" );
+ for( i = parts.begin(); i != parts.end(); i++ ) {
+ if( *i == val ) {
+ return true;
+ }
+ }
+
+ return false;
+}
+
+string ArgvMap::helpstring(string prefix)
+{
+ if(prefix=="no")
+ prefix="";
+
+ string help;
+
+ for(map<string,string>::const_iterator i=helpmap.begin();
+ i!=helpmap.end();
+ i++)
+ {
+ if(!prefix.empty() && i->first.find(prefix)) // only print items with prefix
+ continue;
+
+ help+=" --";
+ help+=i->first;
+
+ string type=d_typeMap[i->first];
+
+ if(type=="Parameter")
+ help+="=...";
+ else if(type=="Switch")
+ {
+ help+=" | --"+i->first+"=yes";
+ help+=" | --"+i->first+"=no";
+ }
+
+
+ help+="\n\t";
+ help+=i->second;
+ help+="\n";
+
+ }
+ return help;
+}
+
+string ArgvMap::configstring(bool current)
+{
+ string help;
+
+ if (current)
+ help="# Autogenerated configuration file based on running instance\n";
+ else
+ help="# Autogenerated configuration file template\n";
+
+ for(map<string,string>::const_iterator i=helpmap.begin(); i!=helpmap.end(); i++) {
+ if(d_typeMap[i->first]=="Command")
+ continue;
+
+ help+="#################################\n";
+ help+="# ";
+ help+=i->first;
+ help+="\t";
+ help+=i->second;
+ help+="\n#\n";
+ if (current) {
+ help+=i->first+"="+params[i->first]+"\n\n";
+ } else {
+ help+="# "+i->first+"="+params[i->first]+"\n\n";
+ }
+ }
+ return help;
+}
+
+const string & ArgvMap::operator[](const string &arg)
+{
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ return params[arg];
+}
+
+mode_t ArgvMap::asMode(const string &arg)
+{
+ mode_t mode;
+ const char *cptr_orig;
+ char *cptr_ret = NULL;
+
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ cptr_orig = params[arg].c_str();
+ mode = static_cast<mode_t>(strtol(cptr_orig, &cptr_ret, 8));
+ if (mode == 0 && cptr_ret == cptr_orig)
+ throw ArgException("'" + arg + string("' contains invalid octal mode"));
+ return mode;
+}
+
+gid_t ArgvMap::asGid(const string &arg)
+{
+ gid_t gid;
+ const char *cptr_orig;
+ char *cptr_ret = NULL;
+
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ cptr_orig = params[arg].c_str();
+ gid = static_cast<gid_t>(strtol(cptr_orig, &cptr_ret, 0));
+ if (gid == 0 && cptr_ret == cptr_orig) {
+ // try to resolve
+ struct group *group = getgrnam(params[arg].c_str());
+ if (group == NULL)
+ throw ArgException("'" + arg + string("' contains invalid group"));
+ gid = group->gr_gid;
+ }
+ return gid;
+}
+
+uid_t ArgvMap::asUid(const string &arg)
+{
+ uid_t uid;
+ const char *cptr_orig;
+ char *cptr_ret = NULL;
+
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ cptr_orig = params[arg].c_str();
+ uid = static_cast<uid_t>(strtol(cptr_orig, &cptr_ret, 0));
+ if (uid == 0 && cptr_ret == cptr_orig) {
+ // try to resolve
+ struct passwd *pwent = getpwnam(params[arg].c_str());
+ if (pwent == NULL)
+ throw ArgException("'" + arg + string("' contains invalid group"));
+ uid = pwent->pw_uid;
+ }
+ return uid;
+}
+
+int ArgvMap::asNum(const string &arg, int def)
+{
+ int retval;
+ const char *cptr_orig;
+ char *cptr_ret = NULL;
+
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ // use default for empty values
+ if (params[arg].empty())
+ return def;
+
+ cptr_orig = params[arg].c_str();
+ retval = static_cast<int>(strtol(cptr_orig, &cptr_ret, 0));
+ if (!retval && cptr_ret == cptr_orig)
+ throw ArgException("'"+arg+"' value '"+string(cptr_orig) + string( "' is not a valid number"));
+
+ return retval;
+}
+
+bool ArgvMap::isEmpty(const string &arg)
+{
+ if(!parmIsset(arg))
+ return true;
+ return params[arg].empty();
+}
+
+double ArgvMap::asDouble(const string &arg)
+{
+ double retval;
+ const char *cptr_orig;
+ char *cptr_ret = NULL;
+
+ if(!parmIsset(arg))
+ throw ArgException(string("Undefined but needed argument: '")+arg+"'");
+
+ if (params[arg].empty())
+ return 0.0;
+
+ cptr_orig = params[arg].c_str();
+ retval = strtod(cptr_orig, &cptr_ret);
+
+ if (retval == 0 && cptr_ret == cptr_orig)
+ throw ArgException("'"+arg+string("' is not valid double"));
+
+ return retval;
+}
+
+ArgvMap::ArgvMap()
+{
+
+}
+
+bool ArgvMap::parmIsset(const string &var)
+{
+ return (params.find(var)!=params.end());
+}
+
+void ArgvMap::parseOne(const string &arg, const string &parseOnly, bool lax)
+{
+ string var, val;
+ string::size_type pos;
+ bool incremental = false;
+
+ if(!arg.find("--") && (pos=arg.find("+="))!=string::npos) // this is a --port+=25 case
+ {
+ var=arg.substr(2,pos-2);
+ val=arg.substr(pos+2);
+ incremental = true;
+ }
+ else if(!arg.find("--") && (pos=arg.find("="))!=string::npos) // this is a --port=25 case
+ {
+ var=arg.substr(2,pos-2);
+ val=arg.substr(pos+1);
+ }
+ else if(!arg.find("--") && (arg.find("=")==string::npos)) // this is a --daemon case
+ {
+ var=arg.substr(2);
+ val="";
+ }
+ else if(arg[0]=='-')
+ {
+ var=arg.substr(1);
+ val="";
+ }
+ else // command
+ d_cmds.push_back(arg);
+
+ boost::trim(var);
+
+ if(var!="" && (parseOnly.empty() || var==parseOnly)) {
+ pos=val.find_first_not_of(" \t"); // strip leading whitespace
+ if(pos && pos!=string::npos)
+ val=val.substr(pos);
+ if(parmIsset(var))
+ {
+ if(incremental)
+ {
+ if(params[var].empty())
+ {
+ if(!d_cleared.count(var))
+ throw ArgException("Incremental parameter '"+var+"' without a parent");
+ params[var]=val;
+ }
+ else
+ params[var]+=", " + val;
+ }
+ else
+ {
+ params[var]=val;
+ d_cleared.insert(var);
+ }
+ }
+ else if(!lax)
+ throw ArgException("Trying to set unknown parameter '"+var+"'");
+ }
+}
+
+const vector<string>&ArgvMap::getCommands()
+{
+ return d_cmds;
+}
+
+void ArgvMap::parse(int &argc, char **argv, bool lax)
+{
+ d_cmds.clear();
+ d_cleared.clear();
+ for(int n=1;n<argc;n++) {
+ parseOne(argv[n],"",lax);
+ }
+}
+
+void ArgvMap::preParse(int &argc, char **argv, const string &arg)
+{
+ for(int n=1;n<argc;n++) {
+ string varval=argv[n];
+ if(!varval.find("--"+arg))
+ parseOne(argv[n]);
+ }
+}
+
+bool ArgvMap::parseFile(const char *fname, const string& arg, bool lax) {
+ string line;
+ string pline;
+ string::size_type pos;
+
+ ifstream f(fname);
+ if(!f)
+ return false;
+
+ while(getline(f,pline)) {
+ trim_right(pline);
+
+ if(!pline.empty() && pline[pline.size()-1]=='\\') {
+ line+=pline.substr(0,pline.length()-1);
+ continue;
+ }
+ else
+ line+=pline;
+
+ // strip everything after a #
+ if((pos=line.find("#"))!=string::npos) {
+ // make sure it's either first char or has whitespace before
+ // fixes issue #354
+ if (pos == 0 || std::isspace(line[pos-1]))
+ line=line.substr(0,pos);
+ }
+
+ // strip trailing spaces
+ trim_right(line);
+
+ // strip leading spaces
+ if((pos=line.find_first_not_of(" \t\r\n"))!=string::npos)
+ line=line.substr(pos);
+
+ // gpgsql-basic-query=sdfsdfs dfsdfsdf sdfsdfsfd
+
+ parseOne( string("--") + line, arg, lax );
+ line="";
+ }
+
+ return true;
+}
+
+
+bool ArgvMap::preParseFile(const char *fname, const string &arg, const string& theDefault)
+{
+ params[arg]=theDefault;
+
+ return parseFile(fname, arg, false);
+}
+
+bool ArgvMap::file(const char *fname, bool lax)
+{
+ return file(fname,lax,false);
+}
+
+bool ArgvMap::file(const char *fname, bool lax, bool included)
+{
+ if (!parmIsset("include-dir")) // inject include-dir
+ set("include-dir","Directory to include configuration files from");
+
+ if(!parseFile(fname, "", lax)) {
+ L << Logger::Warning << "Unable to open " << fname << std::endl;
+ return false;
+ }
+
+ // handle include here (avoid re-include)
+ if (!included && !params["include-dir"].empty()) {
+ std::vector<std::string> extraConfigs;
+ gatherIncludes(extraConfigs);
+ for(const std::string& fn : extraConfigs) {
+ if (!file(fn.c_str(), lax, true)) {
+ L << Logger::Error << fn << " could not be parsed" << std::endl;
+ throw ArgException(fn + " could not be parsed");
+ }
+ }
+ }
+
+ return true;
+}
+
+void ArgvMap::gatherIncludes(std::vector<std::string> &extraConfigs) {
+ extraConfigs.clear();
+ if (params["include-dir"].empty()) return; // nothing to do
+ struct stat st;
+ DIR *dir;
+ struct dirent *ent;
+
+ // stat
+ if (stat(params["include-dir"].c_str(), &st)) {
+ L << Logger::Error << params["include-dir"] << " does not exist!" << std::endl;
+ throw ArgException(params["include-dir"] + " does not exist!");
+ }
+
+ // wonder if it's accessible directory
+ if (!S_ISDIR(st.st_mode)) {
+ L << Logger::Error << params["include-dir"] << " is not a directory" << std::endl;
+ throw ArgException(params["include-dir"] + " is not a directory");
+ }
+
+ if (!(dir = opendir(params["include-dir"].c_str()))) {
+ L << Logger::Error << params["include-dir"] << " is not accessible" << std::endl;
+ throw ArgException(params["include-dir"] + " is not accessible");
+ }
+
+ while((ent = readdir(dir)) != NULL) {
+ if (ent->d_name[0] == '.') continue; // skip any dots
+ if (boost::ends_with(ent->d_name, ".conf")) {
+ // build name
+ std::ostringstream namebuf;
+ namebuf << params["include-dir"].c_str() << "/" << ent->d_name; // FIXME: Use some path separator
+ // ensure it's readable file
+ if (stat(namebuf.str().c_str(), &st) || !S_ISREG(st.st_mode)) {
+ L << Logger::Error << namebuf.str() << " is not a file" << std::endl;
+ closedir(dir);
+ throw ArgException(namebuf.str() + " does not exist!");
+ }
+ extraConfigs.push_back(namebuf.str());
+ }
+ }
+ std::sort(extraConfigs.begin(), extraConfigs.end(), CIStringComparePOSIX());
+ closedir(dir);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef ARGUMENTS_HH
+#define ARGUMENTS_HH
+
+#include <map>
+#include <set>
+#include <string>
+#include <vector>
+#include <fstream>
+#include <iostream>
+#include "misc.hh"
+#include "pdnsexception.hh"
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include "namespaces.hh"
+
+typedef PDNSException ArgException;
+
+/** This class helps parsing argc and argv into a map of parameters. We have 3 kinds of formats:
+
+
+ -w this leads to a key/value pair of "w"/void
+
+ --port=25 "port"/"25"
+
+ --daemon "daemon"/void
+
+ We do not support "--port 25" syntax.
+
+ It can also read from a file. This file can contain '#' to delimit comments.
+
+ Some sample code:
+
+ \code
+
+ ArgvMap R;
+
+ R.set("port")="25"; // use this to specify default parameters
+ R.file("./default.conf"); // parse configuration file
+
+ R.parse(argc, argv); // read the arguments from main()
+
+ cout<<"Will we be a deamon?: "<<R.isset("daemon")<<endl;
+ cout<<"Our port will be "<<R["port"]<<endl;
+
+ map<string,string>::const_iterator i;
+ cout<<"via iterator"<<endl;
+ for(i=R.begin();i!=R.end();i++)
+ cout<<i->first<<"="<<i->second<<endl;
+ \endcode
+*/
+
+
+
+class ArgvMap
+{
+public:
+ ArgvMap();
+ void parse(int &argc, char **argv, bool lax=false); //!< use this to parse from argc and argv
+ void laxParse(int &argc, char **argv) //!< use this to parse from argc and argv
+ {
+ parse(argc,argv,true);
+ }
+ void preParse(int &argc, char **argv, const string &arg); //!< use this to preparse a single var
+ bool preParseFile(const char *fname, const string &arg, const string& theDefault=""); //!< use this to preparse a single var in configuration
+
+ bool file(const char *fname, bool lax=false); //!< Parses a file with parameters
+ bool file(const char *fname, bool lax, bool included);
+ bool laxFile(const char *fname)
+ {
+ return file(fname,true);
+ }
+ bool parseFile(const char *fname, const string& arg, bool lax); //<! parse one line
+ typedef map<string,string> param_t; //!< use this if you need to know the content of the map
+ bool parmIsset(const string &var); //!< Checks if a parameter is set to *a* value
+ bool mustDo(const string &var); //!< if a switch is given, if we must do something (--help)
+ int asNum(const string &var, int def=0); //!< return a variable value as a number or the default if the variable is empty
+ mode_t asMode(const string &var); //!< return value interpreted as octal number
+ uid_t asUid(const string &var); //!< return user id, resolves if necessary
+ gid_t asGid(const string &var); //!< return group id, resolves if necessary
+ double asDouble(const string &var); //!< return a variable value as a number
+ string &set(const string &); //!< Gives a writable reference and allocates space for it
+ string &set(const string &, const string &); //!< Does the same but also allows one to specify a help message
+ void setCmd(const string &, const string &); //!< Add a command flag
+ string &setSwitch(const string &, const string &); //!< Add a command flag
+ string helpstring(string prefix=""); //!< generates the --help
+ string configstring(bool current=false); //!< generates the --mkconfig
+ bool contains(const string &var, const string &val);
+ bool isEmpty(const string &var); //!< checks if variable has value
+
+ vector<string>list();
+ string getHelp(const string &item);
+
+ const param_t::const_iterator begin(); //!< iterator semantics
+ const param_t::const_iterator end(); //!< iterator semantics
+ const string &operator[](const string &); //!< iterator semantics
+ const vector<string>&getCommands();
+ void gatherIncludes(std::vector<std::string> &extraConfigs);
+private:
+ void parseOne(const string &unparsed, const string &parseOnly="", bool lax=false);
+ typedef map<string,string> params_t;
+ params_t params;
+ map<string,string> helpmap;
+ map<string,string> d_typeMap;
+ vector<string> d_cmds;
+ std::set<string> d_cleared;
+};
+
+extern ArgvMap &arg();
+
+#endif /* ARGUMENTS_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "statbag.hh"
+#include "logger.hh"
+#include "iputils.hh"
+#include "sstuff.hh"
+#include "arguments.hh"
+#include "common_startup.hh"
+
+#include "namespaces.hh"
+
+void* carbonDumpThread(void*)
+try
+{
+ extern StatBag S;
+
+ string hostname=arg()["carbon-ourname"];
+ if(hostname.empty()) {
+ char tmp[80];
+ memset(tmp, 0, sizeof(tmp));
+ gethostname(tmp, sizeof(tmp));
+ char *p = strchr(tmp, '.');
+ if(p) *p=0;
+ hostname=tmp;
+ boost::replace_all(hostname, ".", "_");
+ }
+
+ vector<string> carbonServers;
+ stringtok(carbonServers, arg()["carbon-server"], ", ");
+
+ for(;;) {
+ if(carbonServers.empty()) {
+ sleep(1);
+ continue;
+ }
+
+ string msg;
+ vector<string> entries = S.getEntries();
+ ostringstream str;
+ time_t now=time(0);
+ for(const string& entry : entries) {
+ str<<"pdns."<<hostname<<".auth."<<entry<<' '<<S.read(entry)<<' '<<now<<"\r\n";
+ }
+ msg = str.str();
+
+ for (const auto& carbonServer : carbonServers) {
+ ComboAddress remote(carbonServer, 2003);
+
+ try {
+ Socket s(remote.sin4.sin_family, SOCK_STREAM);
+ s.setNonBlocking();
+ s.connect(remote, 2);
+
+ writen2WithTimeout(s.getHandle(), msg.c_str(), msg.length(), 2);
+ } catch (runtime_error &e){
+ L<<Logger::Warning<<"Unable to write data to carbon server at "<<remote.toStringWithPort()<<": "<<e.what()<<endl;
+ continue;
+ }
+ }
+ sleep(arg().asNum("carbon-interval"));
+ }
+ return 0;
+}
+catch(std::exception& e)
+{
+ L<<Logger::Error<<"Carbon thread died: "<<e.what()<<endl;
+ return 0;
+}
+catch(PDNSException& e)
+{
+ L<<Logger::Error<<"Carbon thread died, PDNSException: "<<e.reason<<endl;
+ return 0;
+}
+catch(...)
+{
+ L<<Logger::Error<<"Carbon thread died"<<endl;
+ return 0;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "pdns/dns.hh"
+#include "pdns/dnsbackend.hh"
+#include "gsqlbackend.hh"
+#include "pdns/dnspacket.hh"
+#include "pdns/ueberbackend.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/logger.hh"
+#include "pdns/arguments.hh"
+#include "pdns/base32.hh"
+#include "pdns/dnssecinfra.hh"
+#include <boost/algorithm/string.hpp>
+#include <sstream>
+#include <boost/format.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#define ASSERT_ROW_COLUMNS(query, row, num) { if (row.size() != num) { throw PDNSException(std::string(query) + " returned wrong number of columns, expected " #num ", got " + std::to_string(row.size())); } }
+
+GSQLBackend::GSQLBackend(const string &mode, const string &suffix)
+{
+ setArgPrefix(mode+suffix);
+ d_db=0;
+ d_logprefix="["+mode+"Backend"+suffix+"] ";
+
+ try
+ {
+ d_dnssecQueries = mustDo("dnssec");
+ }
+ catch (ArgException e)
+ {
+ d_dnssecQueries = false;
+ }
+
+ d_NoIdQuery=getArg("basic-query");
+ d_IdQuery=getArg("id-query");
+ d_ANYNoIdQuery=getArg("any-query");
+ d_ANYIdQuery=getArg("any-id-query");
+
+ d_listQuery=getArg("list-query");
+ d_listSubZoneQuery=getArg("list-subzone-query");
+
+ d_MasterOfDomainsZoneQuery=getArg("master-zone-query");
+ d_InfoOfDomainsZoneQuery=getArg("info-zone-query");
+ d_InfoOfAllSlaveDomainsQuery=getArg("info-all-slaves-query");
+ d_SuperMasterInfoQuery=getArg("supermaster-query");
+ d_GetSuperMasterIPs=getArg("supermaster-name-to-ips");
+ d_InsertZoneQuery=getArg("insert-zone-query");
+ d_InsertRecordQuery=getArg("insert-record-query");
+ d_UpdateMasterOfZoneQuery=getArg("update-master-query");
+ d_UpdateKindOfZoneQuery=getArg("update-kind-query");
+ d_UpdateSerialOfZoneQuery=getArg("update-serial-query");
+ d_UpdateLastCheckofZoneQuery=getArg("update-lastcheck-query");
+ d_UpdateAccountOfZoneQuery=getArg("update-account-query");
+ d_ZoneLastChangeQuery=getArg("zone-lastchange-query");
+ d_InfoOfAllMasterDomainsQuery=getArg("info-all-master-query");
+ d_DeleteDomainQuery=getArg("delete-domain-query");
+ d_DeleteZoneQuery=getArg("delete-zone-query");
+ d_DeleteRRSetQuery=getArg("delete-rrset-query");
+ d_DeleteNamesQuery=getArg("delete-names-query");
+ d_getAllDomainsQuery=getArg("get-all-domains-query");
+
+ d_InsertEmptyNonTerminalOrderQuery=getArg("insert-empty-non-terminal-order-query");
+ d_DeleteEmptyNonTerminalQuery = getArg("delete-empty-non-terminal-query");
+ d_RemoveEmptyNonTerminalsFromZoneQuery = getArg("remove-empty-non-terminals-from-zone-query");
+
+ d_ListCommentsQuery = getArg("list-comments-query");
+ d_InsertCommentQuery = getArg("insert-comment-query");
+ d_DeleteCommentRRsetQuery = getArg("delete-comment-rrset-query");
+ d_DeleteCommentsQuery = getArg("delete-comments-query");
+
+ d_firstOrderQuery = getArg("get-order-first-query");
+ d_beforeOrderQuery = getArg("get-order-before-query");
+ d_afterOrderQuery = getArg("get-order-after-query");
+ d_lastOrderQuery = getArg("get-order-last-query");
+
+ d_updateOrderNameAndAuthQuery = getArg("update-ordername-and-auth-query");
+ d_updateOrderNameAndAuthTypeQuery = getArg("update-ordername-and-auth-type-query");
+ d_nullifyOrderNameAndUpdateAuthQuery = getArg("nullify-ordername-and-update-auth-query");
+ d_nullifyOrderNameAndUpdateAuthTypeQuery = getArg("nullify-ordername-and-update-auth-type-query");
+
+ d_AddDomainKeyQuery = getArg("add-domain-key-query");
+ d_ListDomainKeysQuery = getArg("list-domain-keys-query");
+
+ d_GetAllDomainMetadataQuery = getArg("get-all-domain-metadata-query");
+ d_GetDomainMetadataQuery = getArg("get-domain-metadata-query");
+ d_ClearDomainMetadataQuery = getArg("clear-domain-metadata-query");
+ d_ClearDomainAllMetadataQuery = getArg("clear-domain-all-metadata-query");
+ d_SetDomainMetadataQuery = getArg("set-domain-metadata-query");
+
+ d_ActivateDomainKeyQuery = getArg("activate-domain-key-query");
+ d_DeactivateDomainKeyQuery = getArg("deactivate-domain-key-query");
+ d_RemoveDomainKeyQuery = getArg("remove-domain-key-query");
+ d_ClearDomainAllKeysQuery = getArg("clear-domain-all-keys-query");
+
+ d_getTSIGKeyQuery = getArg("get-tsig-key-query");
+ d_setTSIGKeyQuery = getArg("set-tsig-key-query");
+ d_deleteTSIGKeyQuery = getArg("delete-tsig-key-query");
+ d_getTSIGKeysQuery = getArg("get-tsig-keys-query");
+
+ d_SearchRecordsQuery = getArg("search-records-query");
+ d_SearchCommentsQuery = getArg("search-comments-query");
+
+ d_query_stmt = NULL;
+ d_NoIdQuery_stmt = NULL;
+ d_IdQuery_stmt = NULL;
+ d_ANYNoIdQuery_stmt = NULL;
+ d_ANYIdQuery_stmt = NULL;
+ d_listQuery_stmt = NULL;
+ d_listSubZoneQuery_stmt = NULL;
+ d_MasterOfDomainsZoneQuery_stmt = NULL;
+ d_InfoOfDomainsZoneQuery_stmt = NULL;
+ d_InfoOfAllSlaveDomainsQuery_stmt = NULL;
+ d_SuperMasterInfoQuery_stmt = NULL;
+ d_GetSuperMasterIPs_stmt = NULL;
+ d_InsertZoneQuery_stmt = NULL;
+ d_InsertRecordQuery_stmt = NULL;
+ d_InsertEmptyNonTerminalOrderQuery_stmt = NULL;
+ d_UpdateMasterOfZoneQuery_stmt = NULL;
+ d_UpdateKindOfZoneQuery_stmt = NULL;
+ d_UpdateSerialOfZoneQuery_stmt = NULL;
+ d_UpdateLastCheckofZoneQuery_stmt = NULL;
+ d_UpdateAccountOfZoneQuery_stmt = NULL;
+ d_InfoOfAllMasterDomainsQuery_stmt = NULL;
+ d_DeleteDomainQuery_stmt = NULL;
+ d_DeleteZoneQuery_stmt = NULL;
+ d_DeleteRRSetQuery_stmt = NULL;
+ d_DeleteNamesQuery_stmt = NULL;
+ d_ZoneLastChangeQuery_stmt = NULL;
+ d_firstOrderQuery_stmt = NULL;
+ d_beforeOrderQuery_stmt = NULL;
+ d_afterOrderQuery_stmt = NULL;
+ d_lastOrderQuery_stmt = NULL;
+ d_updateOrderNameAndAuthQuery_stmt = NULL;
+ d_updateOrderNameAndAuthTypeQuery_stmt = NULL;
+ d_nullifyOrderNameAndUpdateAuthQuery_stmt = NULL;
+ d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt = NULL;
+ d_RemoveEmptyNonTerminalsFromZoneQuery_stmt = NULL;
+ d_DeleteEmptyNonTerminalQuery_stmt = NULL;
+ d_AddDomainKeyQuery_stmt = NULL;
+ d_ListDomainKeysQuery_stmt = NULL;
+ d_GetAllDomainMetadataQuery_stmt = NULL;
+ d_GetDomainMetadataQuery_stmt = NULL;
+ d_ClearDomainMetadataQuery_stmt = NULL;
+ d_ClearDomainAllMetadataQuery_stmt = NULL;
+ d_SetDomainMetadataQuery_stmt = NULL;
+ d_RemoveDomainKeyQuery_stmt = NULL;
+ d_ActivateDomainKeyQuery_stmt = NULL;
+ d_DeactivateDomainKeyQuery_stmt = NULL;
+ d_ClearDomainAllKeysQuery_stmt = NULL;
+ d_getTSIGKeyQuery_stmt = NULL;
+ d_setTSIGKeyQuery_stmt = NULL;
+ d_deleteTSIGKeyQuery_stmt = NULL;
+ d_getTSIGKeysQuery_stmt = NULL;
+ d_getAllDomainsQuery_stmt = NULL;
+ d_ListCommentsQuery_stmt = NULL;
+ d_InsertCommentQuery_stmt = NULL;
+ d_DeleteCommentRRsetQuery_stmt = NULL;
+ d_DeleteCommentsQuery_stmt = NULL;
+ d_SearchRecordsQuery_stmt = NULL;
+ d_SearchCommentsQuery_stmt = NULL;
+}
+
+void GSQLBackend::setNotified(uint32_t domain_id, uint32_t serial)
+{
+ try {
+ d_UpdateSerialOfZoneQuery_stmt->
+ bind("serial", serial)->
+ bind("domain_id", domain_id)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+}
+
+void GSQLBackend::setFresh(uint32_t domain_id)
+{
+ try {
+ d_UpdateLastCheckofZoneQuery_stmt->
+ bind("last_check", time(0))->
+ bind("domain_id", domain_id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to refresh domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+}
+
+bool GSQLBackend::isMaster(const DNSName &domain, const string &ip)
+{
+ try {
+ d_MasterOfDomainsZoneQuery_stmt->
+ bind("domain", domain)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
+ }
+
+ if(!d_result.empty()) {
+ ASSERT_ROW_COLUMNS("master-zone-query", d_result[0], 1);
+
+ // we can have multiple masters separated by commas
+ vector<string> masters;
+ stringtok(masters, d_result[0][0], " ,\t");
+
+ for(const auto& master: masters) {
+ const ComboAddress caMaster(master);
+ if(ip == caMaster.toString())
+ return true;
+ }
+ }
+
+ // no matching master
+ return false;
+}
+
+bool GSQLBackend::setMaster(const DNSName &domain, const string &ip)
+{
+ try {
+ d_UpdateMasterOfZoneQuery_stmt->
+ bind("master", ip)->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to set master of domain \""+domain.toString()+"\": "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::setKind(const DNSName &domain, const DomainInfo::DomainKind kind)
+{
+ try {
+ d_UpdateKindOfZoneQuery_stmt->
+ bind("kind", toUpper(DomainInfo::getKindString(kind)))->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to set kind of domain \""+domain.toString()+"\": "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::setAccount(const DNSName &domain, const string &account)
+{
+ try {
+ d_UpdateAccountOfZoneQuery_stmt->
+ bind("account", account)->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to set account of domain \""+domain.toString()+"\": "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::getDomainInfo(const DNSName &domain, DomainInfo &di)
+{
+ /* fill DomainInfo from database info:
+ id,name,master IP(s),last_check,notified_serial,type,account */
+ try {
+ d_InfoOfDomainsZoneQuery_stmt->
+ bind("domain", domain)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve information about a domain: "+e.txtReason());
+ }
+
+ int numanswers=d_result.size();
+ if(!numanswers)
+ return false;
+
+ ASSERT_ROW_COLUMNS("info-zone-query", d_result[0], 7);
+
+ di.id=pdns_stou(d_result[0][0]);
+ try {
+ di.zone=DNSName(d_result[0][1]);
+ } catch (...) {
+ return false;
+ }
+ stringtok(di.masters, d_result[0][2], " ,\t");
+ di.last_check=pdns_stou(d_result[0][3]);
+ di.notified_serial = pdns_stou(d_result[0][4]);
+ string type=d_result[0][5];
+ di.account=d_result[0][6];
+ di.backend=this;
+
+ di.serial = 0;
+ try {
+ SOAData sd;
+ if(!getSOA(domain, sd))
+ L<<Logger::Notice<<"No serial for '"<<domain<<"' found - zone is missing?"<<endl;
+ else
+ di.serial = sd.serial;
+ }
+ catch(PDNSException &ae){
+ L<<Logger::Error<<"Error retrieving serial for '"<<domain<<"': "<<ae.reason<<endl;
+ }
+
+ di.kind = DomainInfo::stringToKind(type);
+
+ return true;
+}
+
+void GSQLBackend::getUnfreshSlaveInfos(vector<DomainInfo> *unfreshDomains)
+{
+ /* list all domains that need refreshing for which we are slave, and insert into SlaveDomain:
+ id,name,master IP,serial */
+ try {
+ d_InfoOfAllSlaveDomainsQuery_stmt->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve list of slave domains: "+e.txtReason());
+ }
+
+ vector<DomainInfo> allSlaves;
+ int numanswers=d_result.size();
+ for(int n=0;n<numanswers;++n) { // id,name,master,last_check
+ DomainInfo sd;
+ ASSERT_ROW_COLUMNS("info-all-slaves-query", d_result[n], 4);
+ sd.id=pdns_stou(d_result[n][0]);
+ try {
+ sd.zone= DNSName(d_result[n][1]);
+ } catch (...) {
+ continue;
+ }
+ stringtok(sd.masters, d_result[n][2], ", \t");
+ sd.last_check=pdns_stou(d_result[n][3]);
+ sd.backend=this;
+ sd.kind=DomainInfo::Slave;
+ allSlaves.push_back(sd);
+ }
+
+ for(vector<DomainInfo>::iterator i=allSlaves.begin();i!=allSlaves.end();++i) {
+ SOAData sdata;
+ sdata.serial=0;
+ sdata.refresh=0;
+ getSOA(i->zone,sdata);
+ if((time_t)(i->last_check+sdata.refresh) < time(0)) {
+ i->serial=sdata.serial;
+ unfreshDomains->push_back(*i);
+ }
+ }
+}
+
+void GSQLBackend::getUpdatedMasters(vector<DomainInfo> *updatedDomains)
+{
+ /* list all domains that need notifications for which we are master, and insert into updatedDomains
+ id,name,master IP,serial */
+ try {
+ d_InfoOfAllMasterDomainsQuery_stmt->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve list of master domains: "+e.txtReason());
+ }
+
+ vector<DomainInfo> allMasters;
+ int numanswers=d_result.size();
+ for(int n=0;n<numanswers;++n) { // id,name,master,last_check,notified_serial
+ DomainInfo sd;
+ ASSERT_ROW_COLUMNS("info-all-master-query", d_result[n], 6);
+ sd.id=pdns_stou(d_result[n][0]);
+ try {
+ sd.zone= DNSName(d_result[n][1]);
+ } catch (...) {
+ continue;
+ }
+ sd.last_check=pdns_stou(d_result[n][3]);
+ sd.notified_serial=pdns_stou(d_result[n][4]);
+ sd.backend=this;
+ sd.kind=DomainInfo::Master;
+ allMasters.push_back(sd);
+ }
+
+ for(vector<DomainInfo>::iterator i=allMasters.begin();i!=allMasters.end();++i) {
+ SOAData sdata;
+ sdata.serial=0;
+ sdata.refresh=0;
+ getSOA(i->zone,sdata);
+ if(i->notified_serial!=sdata.serial) {
+ i->serial=sdata.serial;
+ updatedDomains->push_back(*i);
+ }
+ }
+}
+
+bool GSQLBackend::updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ if (!ordername.empty()) {
+ if (qtype == QType::ANY) {
+ try {
+ d_updateOrderNameAndAuthQuery_stmt->
+ bind("ordername", ordername.makeRelative(zonename).labelReverse().toString(" ", false))->
+ bind("auth", auth)->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to update ordername and auth for domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+ } else {
+ try {
+ d_updateOrderNameAndAuthTypeQuery_stmt->
+ bind("ordername", ordername.makeRelative(zonename).labelReverse().toString(" ", false))->
+ bind("auth", auth)->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ bind("qtype", QType(qtype).getName())->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to update ordername and auth per type for domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+ }
+ } else {
+ if (qtype == QType::ANY) {
+ try {
+ d_nullifyOrderNameAndUpdateAuthQuery_stmt->
+ bind("auth", auth)->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to nullify ordername and update auth for domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+ } else {
+ try {
+ d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt->
+ bind("auth", auth)->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ bind("qtype", QType(qtype).getName())->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to nullify ordername and update auth per type for domain_id "+itoa(domain_id)+": "+e.txtReason());
+ }
+ }
+ }
+ return true;
+}
+
+bool GSQLBackend::updateEmptyNonTerminals(uint32_t domain_id, const DNSName& zonename, set<DNSName>& insert, set<DNSName>& erase, bool remove)
+{
+ if(remove) {
+ try {
+ d_RemoveEmptyNonTerminalsFromZoneQuery_stmt->
+ bind("domain_id", domain_id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to delete empty non-terminal records from domain_id "+itoa(domain_id)+": "+e.txtReason());
+ return false;
+ }
+ }
+ else
+ {
+ for(const auto& qname: erase) {
+ try {
+ d_DeleteEmptyNonTerminalQuery_stmt->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to delete empty non-terminal rr "+qname.toString()+" from domain_id "+itoa(domain_id)+": "+e.txtReason());
+ return false;
+ }
+ }
+ }
+
+ for(const auto& qname: insert) {
+ try {
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ bindNull("ordername")->
+ bind("auth", true)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to insert empty non-terminal rr "+qname.toString()+" in domain_id "+itoa(domain_id)+": "+e.txtReason());
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool GSQLBackend::doesDNSSEC()
+{
+ return d_dnssecQueries;
+}
+
+bool GSQLBackend::getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, std::string& before, std::string& after)
+{
+ if(!d_dnssecQueries)
+ return false;
+ // cerr<<"gsql before/after called for id="<<id<<", qname='"<<qname<<"'"<<endl;
+ after.clear();
+
+ SSqlStatement::row_t row;
+ try {
+ d_afterOrderQuery_stmt->
+ bind("ordername", qname)->
+ bind("domain_id", id)->
+ execute();
+ while(d_afterOrderQuery_stmt->hasNextRow()) {
+ d_afterOrderQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-order-after-query", row, 1);
+ after=row[0];
+ }
+ d_afterOrderQuery_stmt->reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to find before/after (after) for domain_id "+itoa(id)+": "+e.txtReason());
+ }
+
+ if(after.empty() && !qname.empty()) {
+ try {
+ d_firstOrderQuery_stmt->
+ bind("domain_id", id)->
+ execute();
+ while(d_firstOrderQuery_stmt->hasNextRow()) {
+ d_firstOrderQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-order-first-query", row, 1);
+ after=row[0];
+ }
+ d_firstOrderQuery_stmt->reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to find before/after (first) for domain_id "+itoa(id)+": "+e.txtReason());
+ }
+ }
+
+ if (before.empty()) {
+ unhashed.clear();
+
+ try {
+ d_beforeOrderQuery_stmt->
+ bind("ordername", qname)->
+ bind("domain_id", id)->
+ execute();
+ while(d_beforeOrderQuery_stmt->hasNextRow()) {
+ d_beforeOrderQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-order-before-query", row, 2);
+ before=row[0];
+ try {
+ unhashed=DNSName(row[1]);
+ } catch (...) {
+ continue;
+ }
+ }
+ d_beforeOrderQuery_stmt->reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to find before/after (before) for domain_id "+itoa(id)+": "+e.txtReason());
+ }
+
+ if(! unhashed.empty())
+ {
+ // cerr<<"unhashed="<<unhashed<<",before="<<before<<", after="<<after<<endl;
+ return true;
+ }
+
+ try {
+ d_lastOrderQuery_stmt->
+ bind("domain_id", id)->
+ execute();
+ while(d_lastOrderQuery_stmt->hasNextRow()) {
+ d_lastOrderQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-order-last-query", row, 2);
+ before=row[0];
+ try {
+ unhashed=DNSName(row[1]);
+ } catch (...) {
+ continue;
+ }
+ }
+ d_lastOrderQuery_stmt->reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to find before/after (last) for domain_id "+itoa(id)+": "+e.txtReason());
+ }
+ } else {
+ before=qname;
+ }
+
+ return true;
+}
+
+int GSQLBackend::addDomainKey(const DNSName& name, const KeyData& key)
+{
+ if(!d_dnssecQueries)
+ return -1;
+
+ try {
+ d_AddDomainKeyQuery_stmt->
+ bind("flags", key.flags)->
+ bind("active", key.active)->
+ bind("content", key.content)->
+ bind("domain", name)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to store key: "+e.txtReason());
+ }
+ return 1; // XXX FIXME, no idea how to get the id
+}
+
+bool GSQLBackend::activateDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ d_ActivateDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to activate key: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ d_DeactivateDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to deactivate key: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::removeDomainKey(const DNSName& name, unsigned int id)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ d_RemoveDomainKeyQuery_stmt->
+ bind("domain", name)->
+ bind("key_id", id)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to remove key: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
+{
+ try {
+ d_getTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ execute();
+
+ SSqlStatement::row_t row;
+
+ content->clear();
+ while(d_getTSIGKeyQuery_stmt->hasNextRow()) {
+ d_getTSIGKeyQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-tsig-key-query", row, 2);
+ try{
+ if(algorithm->empty() || *algorithm==DNSName(row[0])) {
+ *algorithm = DNSName(row[0]);
+ *content = row[1];
+ }
+ } catch (...) {}
+ }
+
+ d_getTSIGKeyQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve named TSIG key: "+e.txtReason());
+ }
+
+ return !content->empty();
+}
+
+bool GSQLBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
+{
+ try {
+ d_setTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ bind("algorithm", algorithm)->
+ bind("content", content)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::deleteTSIGKey(const DNSName& name)
+{
+ try {
+ d_deleteTSIGKeyQuery_stmt->
+ bind("key_name", name)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to store named TSIG key: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
+{
+ try {
+ d_getTSIGKeysQuery_stmt->
+ execute();
+
+ SSqlStatement::row_t row;
+
+ while(d_getTSIGKeysQuery_stmt->hasNextRow()) {
+ d_getTSIGKeysQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-tsig-keys-query", row, 3);
+ struct TSIGKey key;
+ try {
+ key.name = DNSName(row[0]);
+ key.algorithm = DNSName(row[1]);
+ } catch (...) {
+ continue;
+ }
+ key.key = row[2];
+ keys.push_back(key);
+ }
+
+ d_getTSIGKeysQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to retrieve TSIG keys: "+e.txtReason());
+ }
+
+ return keys.empty();
+}
+
+bool GSQLBackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ try {
+ d_ListDomainKeysQuery_stmt->
+ bind("domain", name)->
+ execute();
+
+ SSqlStatement::row_t row;
+ // "select id, kind, active, content from domains, cryptokeys where domain_id=domains.id and name='%s'";
+ KeyData kd;
+ while(d_ListDomainKeysQuery_stmt->hasNextRow()) {
+ d_ListDomainKeysQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("list-domain-keys-query", row, 4);
+ //~ for(const auto& val: row) {
+ //~ cerr<<"'"<<val<<"'"<<endl;
+ //~ }
+ kd.id = pdns_stou(row[0]);
+ kd.flags = pdns_stou(row[1]);
+ kd.active = row[2] == "1";
+ kd.content = row[3];
+ keys.push_back(kd);
+ }
+
+ d_ListDomainKeysQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to list keys: "+e.txtReason());
+ }
+
+ return true;
+}
+
+void GSQLBackend::alsoNotifies(const DNSName &domain, set<string> *ips)
+{
+ vector<string> meta;
+ getDomainMetadata(domain, "ALSO-NOTIFY", meta);
+ for(const auto& str: meta) {
+ ips->insert(str);
+ }
+}
+
+bool GSQLBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
+{
+ try {
+ d_GetAllDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ execute();
+
+ SSqlStatement::row_t row;
+
+ while(d_GetAllDomainMetadataQuery_stmt->hasNextRow()) {
+ d_GetAllDomainMetadataQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-all-domain-metadata-query", row, 2);
+
+ if (!isDnssecDomainMetadata(row[0]))
+ meta[row[0]].push_back(row[1]);
+ }
+
+ d_GetAllDomainMetadataQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason());
+ }
+
+ return true;
+}
+
+
+bool GSQLBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
+{
+ if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
+ return false;
+
+ try {
+ d_GetDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ execute();
+
+ SSqlStatement::row_t row;
+
+ while(d_GetDomainMetadataQuery_stmt->hasNextRow()) {
+ d_GetDomainMetadataQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-domain-metadata-query", row, 1);
+ meta.push_back(row[0]);
+ }
+
+ d_GetDomainMetadataQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to list metadata: "+e.txtReason());
+ }
+
+ return true;
+}
+
+bool GSQLBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
+{
+ if(!d_dnssecQueries && isDnssecDomainMetadata(kind))
+ return false;
+
+ try {
+ d_ClearDomainMetadataQuery_stmt->
+ bind("domain", name)->
+ bind("kind", kind)->
+ execute()->
+ reset();
+ if(!meta.empty()) {
+ for(const auto& value: meta) {
+ d_SetDomainMetadataQuery_stmt->
+ bind("kind", kind)->
+ bind("content", value)->
+ bind("domain", name)->
+ execute()->
+ reset();
+ }
+ }
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to store metadata key: "+e.txtReason());
+ }
+
+ return true;
+}
+
+void GSQLBackend::lookup(const QType &qtype,const DNSName &qname, DNSPacket *pkt_p, int domain_id)
+{
+ try {
+ if(qtype.getCode()!=QType::ANY) {
+ if(domain_id < 0) {
+ d_query_name = "basic-query";
+ d_query_stmt = d_NoIdQuery_stmt;
+ d_query_stmt->
+ bind("qtype", qtype.getName())->
+ bind("qname", qname);
+ } else {
+ d_query_name = "id-query";
+ d_query_stmt = d_IdQuery_stmt;
+ d_query_stmt->
+ bind("qtype", qtype.getName())->
+ bind("qname", qname)->
+ bind("domain_id", domain_id);
+ }
+ } else {
+ // qtype==ANY
+ if(domain_id < 0) {
+ d_query_name = "any-query";
+ d_query_stmt = d_ANYNoIdQuery_stmt;
+ d_query_stmt->
+ bind("qname", qname);
+ } else {
+ d_query_name = "any-id-query";
+ d_query_stmt = d_ANYIdQuery_stmt;
+ d_query_stmt->
+ bind("qname", qname)->
+ bind("domain_id", domain_id);
+ }
+ }
+
+ d_query_stmt->
+ execute();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend lookup query:"+e.txtReason());
+ }
+
+ d_qname=qname;
+}
+
+bool GSQLBackend::list(const DNSName &target, int domain_id, bool include_disabled)
+{
+ DLOG(L<<"GSQLBackend constructing handle for list of domain id '"<<domain_id<<"'"<<endl);
+
+ try {
+ d_query_name = "list-query";
+ d_query_stmt = d_listQuery_stmt;
+ d_query_stmt->
+ bind("include_disabled", (int)include_disabled)->
+ bind("domain_id", domain_id)->
+ execute();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend list query: "+e.txtReason());
+ }
+
+ d_qname.clear();
+ return true;
+}
+
+bool GSQLBackend::listSubZone(const DNSName &zone, int domain_id) {
+
+ string wildzone = "%." + toLower(zone.toStringNoDot());
+
+ try {
+ d_query_name = "list-subzone-query";
+ d_query_stmt = d_listSubZoneQuery_stmt;
+ d_query_stmt->
+ bind("zone", zone)->
+ bind("wildzone", wildzone)->
+ bind("domain_id", domain_id)->
+ execute();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend listSubZone query: "+e.txtReason());
+ }
+ d_qname.clear();
+ return true;
+}
+
+bool GSQLBackend::get(DNSResourceRecord &r)
+{
+ // L << "GSQLBackend get() was called for "<<qtype.getName() << " record: ";
+ SSqlStatement::row_t row;
+
+skiprow:
+ if(d_query_stmt->hasNextRow()) {
+ try {
+ d_query_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS(d_query_name, row, 8);
+ } catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend get: "+e.txtReason());
+ }
+ try {
+ extractRecord(row, r);
+ } catch (...) {
+ goto skiprow;
+ }
+ return true;
+ }
+
+ try {
+ d_query_stmt->reset();
+ } catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend get: "+e.txtReason());
+ }
+ d_query_stmt = NULL;
+ return false;
+}
+
+bool GSQLBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **ddb)
+{
+ // check if we know the ip/ns couple in the database
+ for(vector<DNSResourceRecord>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
+ try {
+ d_SuperMasterInfoQuery_stmt->
+ bind("ip", ip)->
+ bind("nameserver", i->content)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to search for a domain: "+e.txtReason());
+ }
+ if(!d_result.empty()) {
+ ASSERT_ROW_COLUMNS("supermaster-query", d_result[0], 1);
+ *nameserver=i->content;
+ *account=d_result[0][0];
+ *ddb=this;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool GSQLBackend::createDomain(const DNSName &domain, const string &type, const string &masters, const string &account)
+{
+ try {
+ d_InsertZoneQuery_stmt->
+ bind("type", type)->
+ bind("domain", domain)->
+ bind("masters", masters)->
+ bind("account", account)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("Database error trying to insert new domain '"+domain.toString()+"': "+ e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account)
+{
+ string name;
+ string masters(ip);
+ try {
+ if (!nameserver.empty()) {
+ // figure out all IP addresses for the master
+ d_GetSuperMasterIPs_stmt->
+ bind("nameserver", nameserver)->
+ bind("account", account)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ if (!d_result.empty()) {
+ // collect all IP addresses
+ vector<string> tmp;
+ for(const auto& row: d_result) {
+ if (account == row[1])
+ tmp.push_back(row[0]);
+ }
+ // set them as domain's masters, comma separated
+ masters = boost::join(tmp, ", ");
+ }
+ }
+ createDomain(domain, "SLAVE", masters, account);
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("Database error trying to insert new slave domain '"+domain.toString()+"': "+ e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::deleteDomain(const DNSName &domain)
+{
+ DomainInfo di;
+ if (!getDomainInfo(domain, di)) {
+ return false;
+ }
+
+ try {
+ d_DeleteZoneQuery_stmt->
+ bind("domain_id", di.id)->
+ execute()->
+ reset();
+ d_ClearDomainAllMetadataQuery_stmt->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ d_ClearDomainAllKeysQuery_stmt->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ d_DeleteCommentsQuery_stmt->
+ bind("domain_id", di.id)->
+ execute()->
+ reset();
+ d_DeleteDomainQuery_stmt->
+ bind("domain", domain)->
+ execute()->
+ reset();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("Database error trying to delete domain '"+domain.toString()+"': "+ e.txtReason());
+ }
+ return true;
+}
+
+void GSQLBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled)
+{
+ DLOG(L<<"GSQLBackend retrieving all domains."<<endl);
+
+ try {
+ d_getAllDomainsQuery_stmt->
+ bind("include_disabled", (int)include_disabled)->
+ execute();
+
+ SSqlStatement::row_t row;
+ while (d_getAllDomainsQuery_stmt->hasNextRow()) {
+ d_getAllDomainsQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("get-all-domains-query", row, 8);
+ DomainInfo di;
+ di.id = pdns_stou(row[0]);
+ try {
+ di.zone = DNSName(row[1]);
+ } catch (...) {
+ continue;
+ }
+
+ if (!row[4].empty()) {
+ stringtok(di.masters, row[4], " ,\t");
+ }
+
+ SOAData sd;
+ fillSOAData(row[2], sd);
+ di.serial = sd.serial;
+ di.notified_serial = pdns_stou(row[5]);
+ di.last_check = pdns_stou(row[6]);
+ di.account = row[7];
+
+ if (pdns_iequals(row[3], "MASTER"))
+ di.kind = DomainInfo::Master;
+ else if (pdns_iequals(row[3], "SLAVE"))
+ di.kind = DomainInfo::Slave;
+ else
+ di.kind = DomainInfo::Native;
+
+ di.backend = this;
+
+ domains->push_back(di);
+ }
+ d_getAllDomainsQuery_stmt->reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Database error trying to retrieve all domains:" + e.txtReason());
+ }
+}
+
+bool GSQLBackend::replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
+{
+ try {
+ if (qt != QType::ANY) {
+ d_DeleteRRSetQuery_stmt->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ bind("qtype", qt.getName())->
+ execute()->
+ reset();
+ } else {
+ d_DeleteNamesQuery_stmt->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ execute()->
+ reset();
+ }
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to delete RRSet: "+e.txtReason());
+ }
+
+ if (rrset.empty()) {
+ try {
+ d_DeleteCommentRRsetQuery_stmt->
+ bind("domain_id", domain_id)->
+ bind("qname", qname)->
+ bind("qtype", qt.getName())->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason());
+ }
+ }
+ for(const auto& rr: rrset) {
+ feedRecord(rr);
+ }
+
+ return true;
+}
+
+bool GSQLBackend::feedRecord(const DNSResourceRecord &r, string *ordername)
+{
+ int prio=0;
+ string content(r.content);
+ if (r.qtype == QType::MX || r.qtype == QType::SRV) {
+ string::size_type pos = content.find_first_not_of("0123456789");
+ if (pos != string::npos) {
+ prio=pdns_stou(content.substr(0,pos));
+ boost::erase_head(content, pos);
+ }
+ trim_left(content);
+ }
+
+ try {
+ d_InsertRecordQuery_stmt->
+ bind("content",content)->
+ bind("ttl",r.ttl)->
+ bind("priority",prio)->
+ bind("qtype",r.qtype.getName())->
+ bind("domain_id",r.domain_id)->
+ bind("disabled",r.disabled)->
+ bind("qname",r.qname);
+
+ if (ordername == NULL)
+ d_InsertRecordQuery_stmt->bindNull("ordername");
+ else
+ d_InsertRecordQuery_stmt->bind("ordername",*ordername);
+
+ if (d_dnssecQueries)
+ d_InsertRecordQuery_stmt->bind("auth", r.auth);
+ else
+ d_InsertRecordQuery_stmt->bind("auth", true);
+
+ d_InsertRecordQuery_stmt->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to feed record: "+e.txtReason());
+ }
+ return true; // XXX FIXME this API should not return 'true' I think -ahu
+}
+
+bool GSQLBackend::feedEnts(int domain_id, map<DNSName,bool>& nonterm)
+{
+ for(const auto& nt: nonterm) {
+ try {
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bind("domain_id",domain_id)->
+ bind("qname", nt.first)->
+ bindNull("ordername")->
+ bind("auth",(nt.second || !d_dnssecQueries))->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason());
+ }
+ }
+ return true;
+}
+
+bool GSQLBackend::feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow)
+{
+ if(!d_dnssecQueries)
+ return false;
+
+ string ordername;
+
+ for(const auto& nt: nonterm) {
+ try {
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bind("domain_id",domain_id)->
+ bind("qname", nt.first);
+ if (narrow || !nt.second) {
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bindNull("ordername");
+ } else {
+ ordername=toBase32Hex(hashQNameWithSalt(ns3prc, nt.first));
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bind("ordername", ordername);
+ }
+ d_InsertEmptyNonTerminalOrderQuery_stmt->
+ bind("auth",nt.second)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to feed empty non-terminal: "+e.txtReason());
+ }
+ }
+ return true;
+}
+
+bool GSQLBackend::startTransaction(const DNSName &domain, int domain_id)
+{
+ try {
+ d_db->startTransaction();
+ if(domain_id >= 0) {
+ d_DeleteZoneQuery_stmt->
+ bind("domain_id", domain_id)->
+ execute()->
+ reset();
+ }
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Database failed to start transaction: "+e.txtReason());
+ }
+
+ return true;
+}
+
+bool GSQLBackend::commitTransaction()
+{
+ try {
+ d_db->commit();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("Database failed to commit transaction: "+e.txtReason());
+ }
+ return true;
+}
+
+bool GSQLBackend::abortTransaction()
+{
+ try {
+ d_db->rollback();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("Database failed to abort transaction: "+string(e.txtReason()));
+ }
+ return true;
+}
+
+bool GSQLBackend::calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial)
+{
+ if (d_ZoneLastChangeQuery.empty()) {
+ // query not set => fall back to default impl
+ return DNSBackend::calculateSOASerial(domain, sd, serial);
+ }
+
+ try {
+ d_ZoneLastChangeQuery_stmt->
+ bind("domain_id", sd.domain_id)->
+ execute()->
+ getResult(d_result)->
+ reset();
+ }
+ catch (const SSqlException& e) {
+ //DLOG(L<<"GSQLBackend unable to calculate SOA serial: " << e.txtReason()<<endl);
+ return false;
+ }
+
+ if (!d_result.empty()) {
+ ASSERT_ROW_COLUMNS("zone-lastchange-query", d_result[0], 1);
+ serial = pdns_stou(d_result[0][0]);
+ return true;
+ }
+
+ return false;
+}
+
+bool GSQLBackend::listComments(const uint32_t domain_id)
+{
+ try {
+ d_query_name = "list-comments-query";
+ d_query_stmt = d_ListCommentsQuery_stmt;
+ d_query_stmt->
+ bind("domain_id", domain_id)->
+ execute();
+ }
+ catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend list comments query: "+e.txtReason());
+ }
+
+ return true;
+}
+
+bool GSQLBackend::getComment(Comment& comment)
+{
+ SSqlStatement::row_t row;
+
+ for(;;) {
+ if (!d_query_stmt->hasNextRow()) {
+ try {
+ d_query_stmt->reset();
+ } catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend comment get: "+e.txtReason());
+ }
+ d_query_stmt = NULL;
+ return false;
+ }
+
+ try {
+ d_query_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS(d_query_name, row, 6);
+ } catch(SSqlException &e) {
+ throw PDNSException("GSQLBackend comment get: "+e.txtReason());
+ }
+ try {
+ extractComment(row, comment);
+ } catch (...) {
+ continue;
+ }
+ return true;
+ }
+}
+
+void GSQLBackend::feedComment(const Comment& comment)
+{
+ try {
+ d_InsertCommentQuery_stmt->
+ bind("domain_id",comment.domain_id)->
+ bind("qname",comment.qname)->
+ bind("qtype",comment.qtype.getName())->
+ bind("modified_at",comment.modified_at)->
+ bind("account",comment.account)->
+ bind("content",comment.content)->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to feed comment: "+e.txtReason());
+ }
+}
+
+bool GSQLBackend::replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments)
+{
+ try {
+ d_DeleteCommentRRsetQuery_stmt->
+ bind("domain_id",domain_id)->
+ bind("qname", qname)->
+ bind("qtype",qt.getName())->
+ execute()->
+ reset();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to delete comment: "+e.txtReason());
+ }
+
+ for(const auto& comment: comments) {
+ feedComment(comment);
+ }
+
+ return true;
+}
+
+string GSQLBackend::directBackendCmd(const string &query)
+{
+ try {
+ ostringstream out;
+
+ unique_ptr<SSqlStatement> stmt(d_db->prepare(query,0));
+
+ stmt->execute();
+
+ SSqlStatement::row_t row;
+
+ while(stmt->hasNextRow()) {
+ stmt->nextRow(row);
+ for(const auto& col: row)
+ out<<"\'"<<col<<"\'\t";
+ out<<endl;
+ }
+
+ return out.str();
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to execute query: "+e.txtReason());
+ }
+}
+
+string GSQLBackend::pattern2SQLPattern(const string &pattern)
+{
+ string escaped_pattern = boost::replace_all_copy(pattern,"\\","\\\\");
+ boost::replace_all(escaped_pattern,"_","\\_");
+ boost::replace_all(escaped_pattern,"%","\\%");
+ boost::replace_all(escaped_pattern,"*","%");
+ boost::replace_all(escaped_pattern,"?","_");
+ return escaped_pattern;
+}
+
+bool GSQLBackend::searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
+{
+ d_qname.clear();
+ try {
+ string escaped_pattern = pattern2SQLPattern(pattern);
+
+ d_SearchRecordsQuery_stmt->
+ bind("value", escaped_pattern)->
+ bind("value2", escaped_pattern)->
+ bind("limit", maxResults)->
+ execute();
+
+ while(d_SearchRecordsQuery_stmt->hasNextRow())
+ {
+ SSqlStatement::row_t row;
+ DNSResourceRecord r;
+ d_SearchRecordsQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("search-records-query", row, 8);
+ try {
+ extractRecord(row, r);
+ } catch (...) {
+ continue;
+ }
+ result.push_back(r);
+ }
+
+ d_SearchRecordsQuery_stmt->reset();
+
+ return true;
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to execute query: "+e.txtReason());
+ }
+
+ return false;
+}
+
+bool GSQLBackend::searchComments(const string &pattern, int maxResults, vector<Comment>& result)
+{
+ Comment c;
+ try {
+ string escaped_pattern = pattern2SQLPattern(pattern);
+
+ d_SearchCommentsQuery_stmt->
+ bind("value", escaped_pattern)->
+ bind("value2", escaped_pattern)->
+ bind("limit", maxResults)->
+ execute();
+
+ while(d_SearchCommentsQuery_stmt->hasNextRow()) {
+ SSqlStatement::row_t row;
+ d_SearchCommentsQuery_stmt->nextRow(row);
+ ASSERT_ROW_COLUMNS("search-comments-query", row, 6);
+ Comment comment;
+ extractComment(row, comment);
+ result.push_back(comment);
+ }
+
+ d_SearchRecordsQuery_stmt->reset();
+
+ return true;
+ }
+ catch (SSqlException &e) {
+ throw PDNSException("GSQLBackend unable to execute query: "+e.txtReason());
+ }
+
+ return false;
+}
+
+void GSQLBackend::extractRecord(const SSqlStatement::row_t& row, DNSResourceRecord& r)
+{
+ if (row[1].empty())
+ r.ttl = ::arg().asNum( "default-ttl" );
+ else
+ r.ttl=pdns_stou(row[1]);
+ if(!d_qname.empty())
+ r.qname=d_qname;
+ else
+ r.qname=DNSName(row[6]);
+
+ r.qtype=row[3];
+
+ if (r.qtype==QType::MX || r.qtype==QType::SRV)
+ r.content=row[2]+" "+row[0];
+ else
+ r.content=row[0];
+
+ r.last_modified=0;
+
+ if(d_dnssecQueries)
+ r.auth = !row[7].empty() && row[7][0]=='1';
+ else
+ r.auth = 1;
+
+ r.disabled = !row[5].empty() && row[5][0]=='1';
+
+ r.domain_id=pdns_stou(row[4]);
+}
+
+void GSQLBackend::extractComment(const SSqlStatement::row_t& row, Comment& comment)
+{
+ comment.domain_id = pdns_stou(row[0]);
+ comment.qname = DNSName(row[1]);
+ comment.qtype = row[2];
+ comment.modified_at = pdns_stou(row[3]);
+ comment.account = row[4];
+ comment.content = row[5];
+}
+
+SSqlStatement::~SSqlStatement() {
+// make sure vtable won't break
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_GSQLBACKEND_HH
+#define PDNS_GSQLBACKEND_HH
+
+#include <string>
+#include <map>
+#include "ssql.hh"
+#include "pdns/arguments.hh"
+
+#include "pdns/namespaces.hh"
+
+bool isDnssecDomainMetadata (const string& name);
+
+/*
+GSQLBackend is a generic backend used by other sql backends
+*/
+class GSQLBackend : public DNSBackend
+{
+public:
+ GSQLBackend(const string &mode, const string &suffix); //!< Makes our connection to the database. Throws an exception if it fails.
+ virtual ~GSQLBackend()
+ {
+ freeStatements();
+ if(d_db)
+ delete d_db;
+ }
+
+ void setDB(SSql *db)
+ {
+ freeStatements();
+ delete d_db;
+ d_db=db;
+ if (d_db) {
+ d_db->setLog(::arg().mustDo("query-logging"));
+ d_NoIdQuery_stmt = d_db->prepare(d_NoIdQuery, 2);
+ d_IdQuery_stmt = d_db->prepare(d_IdQuery, 3);
+ d_ANYNoIdQuery_stmt = d_db->prepare(d_ANYNoIdQuery, 1);
+ d_ANYIdQuery_stmt = d_db->prepare(d_ANYIdQuery, 2);
+ d_listQuery_stmt = d_db->prepare(d_listQuery, 2);
+ d_listSubZoneQuery_stmt = d_db->prepare(d_listSubZoneQuery, 3);
+ d_MasterOfDomainsZoneQuery_stmt = d_db->prepare(d_MasterOfDomainsZoneQuery, 1);
+ d_InfoOfDomainsZoneQuery_stmt = d_db->prepare(d_InfoOfDomainsZoneQuery, 1);
+ d_InfoOfAllSlaveDomainsQuery_stmt = d_db->prepare(d_InfoOfAllSlaveDomainsQuery, 0);
+ d_SuperMasterInfoQuery_stmt = d_db->prepare(d_SuperMasterInfoQuery, 2);
+ d_GetSuperMasterIPs_stmt = d_db->prepare(d_GetSuperMasterIPs, 2);
+ d_InsertZoneQuery_stmt = d_db->prepare(d_InsertZoneQuery, 4);
+ d_InsertRecordQuery_stmt = d_db->prepare(d_InsertRecordQuery, 9);
+ d_InsertEmptyNonTerminalOrderQuery_stmt = d_db->prepare(d_InsertEmptyNonTerminalOrderQuery, 4);
+ d_UpdateMasterOfZoneQuery_stmt = d_db->prepare(d_UpdateMasterOfZoneQuery, 2);
+ d_UpdateKindOfZoneQuery_stmt = d_db->prepare(d_UpdateKindOfZoneQuery, 2);
+ d_UpdateAccountOfZoneQuery_stmt = d_db->prepare(d_UpdateAccountOfZoneQuery, 2);
+ d_UpdateSerialOfZoneQuery_stmt = d_db->prepare(d_UpdateSerialOfZoneQuery, 2);
+ d_UpdateLastCheckofZoneQuery_stmt = d_db->prepare(d_UpdateLastCheckofZoneQuery, 2);
+ d_InfoOfAllMasterDomainsQuery_stmt = d_db->prepare(d_InfoOfAllMasterDomainsQuery, 0);
+ d_DeleteDomainQuery_stmt = d_db->prepare(d_DeleteDomainQuery, 1);
+ d_DeleteZoneQuery_stmt = d_db->prepare(d_DeleteZoneQuery, 1);
+ d_DeleteRRSetQuery_stmt = d_db->prepare(d_DeleteRRSetQuery, 3);
+ d_DeleteNamesQuery_stmt = d_db->prepare(d_DeleteNamesQuery, 2);
+ d_ZoneLastChangeQuery_stmt = d_db->prepare(d_ZoneLastChangeQuery, 1);
+ d_firstOrderQuery_stmt = d_db->prepare(d_firstOrderQuery, 1);
+ d_beforeOrderQuery_stmt = d_db->prepare(d_beforeOrderQuery, 2);
+ d_afterOrderQuery_stmt = d_db->prepare(d_afterOrderQuery, 2);
+ d_lastOrderQuery_stmt = d_db->prepare(d_lastOrderQuery, 1);
+ d_updateOrderNameAndAuthQuery_stmt = d_db->prepare(d_updateOrderNameAndAuthQuery, 4);
+ d_updateOrderNameAndAuthTypeQuery_stmt = d_db->prepare(d_updateOrderNameAndAuthTypeQuery, 5);
+ d_nullifyOrderNameAndUpdateAuthQuery_stmt = d_db->prepare(d_nullifyOrderNameAndUpdateAuthQuery, 3);
+ d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt = d_db->prepare(d_nullifyOrderNameAndUpdateAuthTypeQuery, 4);
+ d_RemoveEmptyNonTerminalsFromZoneQuery_stmt = d_db->prepare(d_RemoveEmptyNonTerminalsFromZoneQuery, 1);
+ d_DeleteEmptyNonTerminalQuery_stmt = d_db->prepare(d_DeleteEmptyNonTerminalQuery, 2);
+ d_AddDomainKeyQuery_stmt = d_db->prepare(d_AddDomainKeyQuery, 4);
+ d_ListDomainKeysQuery_stmt = d_db->prepare(d_ListDomainKeysQuery, 1);
+ d_GetAllDomainMetadataQuery_stmt = d_db->prepare(d_GetAllDomainMetadataQuery, 1);
+ d_GetDomainMetadataQuery_stmt = d_db->prepare(d_GetDomainMetadataQuery, 2);
+ d_ClearDomainMetadataQuery_stmt = d_db->prepare(d_ClearDomainMetadataQuery, 2);
+ d_ClearDomainAllMetadataQuery_stmt = d_db->prepare(d_ClearDomainAllMetadataQuery, 1);
+ d_SetDomainMetadataQuery_stmt = d_db->prepare(d_SetDomainMetadataQuery, 3);
+ d_RemoveDomainKeyQuery_stmt = d_db->prepare(d_RemoveDomainKeyQuery, 2);
+ d_ActivateDomainKeyQuery_stmt = d_db->prepare(d_ActivateDomainKeyQuery, 2);
+ d_DeactivateDomainKeyQuery_stmt = d_db->prepare(d_DeactivateDomainKeyQuery, 2);
+ d_ClearDomainAllKeysQuery_stmt = d_db->prepare(d_ClearDomainAllKeysQuery, 1);
+ d_getTSIGKeyQuery_stmt = d_db->prepare(d_getTSIGKeyQuery, 1);
+ d_setTSIGKeyQuery_stmt = d_db->prepare(d_setTSIGKeyQuery, 3);
+ d_deleteTSIGKeyQuery_stmt = d_db->prepare(d_deleteTSIGKeyQuery, 1);
+ d_getTSIGKeysQuery_stmt = d_db->prepare(d_getTSIGKeysQuery, 0);
+ d_getAllDomainsQuery_stmt = d_db->prepare(d_getAllDomainsQuery, 1);
+ d_ListCommentsQuery_stmt = d_db->prepare(d_ListCommentsQuery, 1);
+ d_InsertCommentQuery_stmt = d_db->prepare(d_InsertCommentQuery, 6);
+ d_DeleteCommentRRsetQuery_stmt = d_db->prepare(d_DeleteCommentRRsetQuery, 3);
+ d_DeleteCommentsQuery_stmt = d_db->prepare(d_DeleteCommentsQuery, 1);
+ d_SearchRecordsQuery_stmt = d_db->prepare(d_SearchRecordsQuery, 3);
+ d_SearchCommentsQuery_stmt = d_db->prepare(d_SearchCommentsQuery, 3);
+ }
+ }
+
+ void release(SSqlStatement **stmt) {
+ delete *stmt;
+ *stmt = NULL;
+ }
+
+ void freeStatements() {
+ release(&d_NoIdQuery_stmt);
+ release(&d_IdQuery_stmt);
+ release(&d_ANYNoIdQuery_stmt);
+ release(&d_ANYIdQuery_stmt);
+ release(&d_listQuery_stmt);
+ release(&d_listSubZoneQuery_stmt);
+ release(&d_MasterOfDomainsZoneQuery_stmt);
+ release(&d_InfoOfDomainsZoneQuery_stmt);
+ release(&d_InfoOfAllSlaveDomainsQuery_stmt);
+ release(&d_SuperMasterInfoQuery_stmt);
+ release(&d_GetSuperMasterIPs_stmt);
+ release(&d_InsertZoneQuery_stmt);
+ release(&d_InsertRecordQuery_stmt);
+ release(&d_InsertEmptyNonTerminalOrderQuery_stmt);
+ release(&d_UpdateMasterOfZoneQuery_stmt);
+ release(&d_UpdateKindOfZoneQuery_stmt);
+ release(&d_UpdateAccountOfZoneQuery_stmt);
+ release(&d_UpdateSerialOfZoneQuery_stmt);
+ release(&d_UpdateLastCheckofZoneQuery_stmt);
+ release(&d_InfoOfAllMasterDomainsQuery_stmt);
+ release(&d_DeleteDomainQuery_stmt);
+ release(&d_DeleteZoneQuery_stmt);
+ release(&d_DeleteRRSetQuery_stmt);
+ release(&d_DeleteNamesQuery_stmt);
+ release(&d_ZoneLastChangeQuery_stmt);
+ release(&d_firstOrderQuery_stmt);
+ release(&d_beforeOrderQuery_stmt);
+ release(&d_afterOrderQuery_stmt);
+ release(&d_lastOrderQuery_stmt);
+ release(&d_updateOrderNameAndAuthQuery_stmt);
+ release(&d_updateOrderNameAndAuthTypeQuery_stmt);
+ release(&d_nullifyOrderNameAndUpdateAuthQuery_stmt);
+ release(&d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt);
+ release(&d_RemoveEmptyNonTerminalsFromZoneQuery_stmt);
+ release(&d_DeleteEmptyNonTerminalQuery_stmt);
+ release(&d_AddDomainKeyQuery_stmt);
+ release(&d_ListDomainKeysQuery_stmt);
+ release(&d_GetAllDomainMetadataQuery_stmt);
+ release(&d_GetDomainMetadataQuery_stmt);
+ release(&d_ClearDomainMetadataQuery_stmt);
+ release(&d_ClearDomainAllMetadataQuery_stmt);
+ release(&d_SetDomainMetadataQuery_stmt);
+ release(&d_RemoveDomainKeyQuery_stmt);
+ release(&d_ActivateDomainKeyQuery_stmt);
+ release(&d_DeactivateDomainKeyQuery_stmt);
+ release(&d_ClearDomainAllKeysQuery_stmt);
+ release(&d_getTSIGKeyQuery_stmt);
+ release(&d_setTSIGKeyQuery_stmt);
+ release(&d_deleteTSIGKeyQuery_stmt);
+ release(&d_getTSIGKeysQuery_stmt);
+ release(&d_getAllDomainsQuery_stmt);
+ release(&d_ListCommentsQuery_stmt);
+ release(&d_InsertCommentQuery_stmt);
+ release(&d_DeleteCommentRRsetQuery_stmt);
+ release(&d_DeleteCommentsQuery_stmt);
+ release(&d_SearchRecordsQuery_stmt);
+ release(&d_SearchCommentsQuery_stmt);
+ }
+
+ void lookup(const QType &, const DNSName &qdomain, DNSPacket *p=0, int zoneId=-1);
+ bool list(const DNSName &target, int domain_id, bool include_disabled=false);
+ bool get(DNSResourceRecord &r);
+ void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false);
+ bool isMaster(const DNSName &domain, const string &ip);
+ void alsoNotifies(const DNSName &domain, set<string> *ips);
+ bool startTransaction(const DNSName &domain, int domain_id=-1);
+ bool commitTransaction();
+ bool abortTransaction();
+ bool feedRecord(const DNSResourceRecord &r, string *ordername=0);
+ bool feedEnts(int domain_id, map<DNSName,bool>& nonterm);
+ bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow);
+ bool createDomain(const DNSName &domain, const string &type, const string &masters, const string &account);
+ bool createDomain(const DNSName &domain) {
+ return createDomain(domain, "NATIVE", "", "");
+ };
+ bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account);
+ bool deleteDomain(const DNSName &domain);
+ bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db);
+ void setFresh(uint32_t domain_id);
+ void getUnfreshSlaveInfos(vector<DomainInfo> *domains);
+ void getUpdatedMasters(vector<DomainInfo> *updatedDomains);
+ bool getDomainInfo(const DNSName &domain, DomainInfo &di);
+ void setNotified(uint32_t domain_id, uint32_t serial);
+ bool setMaster(const DNSName &domain, const string &ip);
+ bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind);
+ bool setAccount(const DNSName &domain, const string &account);
+
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, std::string& before, std::string& after);
+ virtual bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t=QType::ANY);
+
+ virtual bool updateEmptyNonTerminals(uint32_t domain_id, const DNSName& zonename, set<DNSName>& insert ,set<DNSName>& erase, bool remove);
+ virtual bool doesDNSSEC();
+
+ virtual bool calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial);
+
+ bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset);
+ bool listSubZone(const DNSName &zone, int domain_id);
+ int addDomainKey(const DNSName& name, const KeyData& key);
+ bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys);
+ bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta);
+ bool clearDomainAllMetadata(const DNSName& domain);
+
+ bool removeDomainKey(const DNSName& name, unsigned int id);
+ bool activateDomainKey(const DNSName& name, unsigned int id);
+ bool deactivateDomainKey(const DNSName& name, unsigned int id);
+
+ bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content);
+ bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
+ bool deleteTSIGKey(const DNSName& name);
+ bool getTSIGKeys(std::vector< struct TSIGKey > &keys);
+
+ bool listComments(const uint32_t domain_id);
+ bool getComment(Comment& comment);
+ void feedComment(const Comment& comment);
+ bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments);
+ bool replaceComments(const uint32_t domain_id, const string& qname, const QType& qt, const vector<Comment>& comments);
+ string directBackendCmd(const string &query);
+ bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
+ bool searchComments(const string &pattern, int maxResults, vector<Comment>& result);
+
+protected:
+ string pattern2SQLPattern(const string& pattern);
+ void extractRecord(const SSqlStatement::row_t& row, DNSResourceRecord& rr);
+ void extractComment(const SSqlStatement::row_t& row, Comment& c);
+
+private:
+ string d_query_name;
+ DNSName d_qname;
+ SSql *d_db;
+ SSqlStatement::result_t d_result;
+
+ string d_NoIdQuery;
+ string d_IdQuery;
+ string d_ANYNoIdQuery;
+ string d_ANYIdQuery;
+
+ string d_listQuery;
+ string d_listSubZoneQuery;
+ string d_logprefix;
+
+ string d_MasterOfDomainsZoneQuery;
+ string d_InfoOfDomainsZoneQuery;
+ string d_InfoOfAllSlaveDomainsQuery;
+ string d_SuperMasterInfoQuery;
+ string d_GetSuperMasterName;
+ string d_GetSuperMasterIPs;
+
+ string d_InsertZoneQuery;
+ string d_InsertRecordQuery;
+ string d_InsertEmptyNonTerminalOrderQuery;
+ string d_UpdateMasterOfZoneQuery;
+ string d_UpdateKindOfZoneQuery;
+ string d_UpdateAccountOfZoneQuery;
+ string d_UpdateSerialOfZoneQuery;
+ string d_UpdateLastCheckofZoneQuery;
+ string d_InfoOfAllMasterDomainsQuery;
+ string d_DeleteDomainQuery;
+ string d_DeleteZoneQuery;
+ string d_DeleteRRSetQuery;
+ string d_DeleteNamesQuery;
+ string d_ZoneLastChangeQuery;
+
+ string d_firstOrderQuery;
+ string d_beforeOrderQuery;
+ string d_afterOrderQuery;
+ string d_lastOrderQuery;
+
+ string d_updateOrderNameAndAuthQuery;
+ string d_updateOrderNameAndAuthTypeQuery;
+ string d_nullifyOrderNameAndUpdateAuthQuery;
+ string d_nullifyOrderNameAndUpdateAuthTypeQuery;
+
+ string d_RemoveEmptyNonTerminalsFromZoneQuery;
+ string d_DeleteEmptyNonTerminalQuery;
+
+ string d_AddDomainKeyQuery;
+ string d_ListDomainKeysQuery;
+ string d_GetAllDomainMetadataQuery;
+ string d_GetDomainMetadataQuery;
+ string d_ClearDomainMetadataQuery;
+ string d_ClearDomainAllMetadataQuery;
+ string d_SetDomainMetadataQuery;
+
+ string d_RemoveDomainKeyQuery;
+ string d_ActivateDomainKeyQuery;
+ string d_DeactivateDomainKeyQuery;
+ string d_ClearDomainAllKeysQuery;
+
+ string d_getTSIGKeyQuery;
+ string d_setTSIGKeyQuery;
+ string d_deleteTSIGKeyQuery;
+ string d_getTSIGKeysQuery;
+
+ string d_getAllDomainsQuery;
+
+ string d_ListCommentsQuery;
+ string d_InsertCommentQuery;
+ string d_DeleteCommentRRsetQuery;
+ string d_DeleteCommentsQuery;
+
+ string d_SearchRecordsQuery;
+ string d_SearchCommentsQuery;
+
+ SSqlStatement* d_query_stmt;
+
+ SSqlStatement* d_NoIdQuery_stmt;
+ SSqlStatement* d_IdQuery_stmt;
+ SSqlStatement* d_ANYNoIdQuery_stmt;
+ SSqlStatement* d_ANYIdQuery_stmt;
+ SSqlStatement* d_listQuery_stmt;
+ SSqlStatement* d_listSubZoneQuery_stmt;
+ SSqlStatement* d_MasterOfDomainsZoneQuery_stmt;
+ SSqlStatement* d_InfoOfDomainsZoneQuery_stmt;
+ SSqlStatement* d_InfoOfAllSlaveDomainsQuery_stmt;
+ SSqlStatement* d_SuperMasterInfoQuery_stmt;
+ SSqlStatement* d_GetSuperMasterIPs_stmt;
+ SSqlStatement* d_InsertZoneQuery_stmt;
+ SSqlStatement* d_InsertRecordQuery_stmt;
+ SSqlStatement* d_InsertEmptyNonTerminalOrderQuery_stmt;
+ SSqlStatement* d_UpdateMasterOfZoneQuery_stmt;
+ SSqlStatement* d_UpdateKindOfZoneQuery_stmt;
+ SSqlStatement* d_UpdateAccountOfZoneQuery_stmt;
+ SSqlStatement* d_UpdateSerialOfZoneQuery_stmt;
+ SSqlStatement* d_UpdateLastCheckofZoneQuery_stmt;
+ SSqlStatement* d_InfoOfAllMasterDomainsQuery_stmt;
+ SSqlStatement* d_DeleteDomainQuery_stmt;
+ SSqlStatement* d_DeleteZoneQuery_stmt;
+ SSqlStatement* d_DeleteRRSetQuery_stmt;
+ SSqlStatement* d_DeleteNamesQuery_stmt;
+ SSqlStatement* d_ZoneLastChangeQuery_stmt;
+ SSqlStatement* d_firstOrderQuery_stmt;
+ SSqlStatement* d_beforeOrderQuery_stmt;
+ SSqlStatement* d_afterOrderQuery_stmt;
+ SSqlStatement* d_lastOrderQuery_stmt;
+ SSqlStatement* d_updateOrderNameAndAuthQuery_stmt;
+ SSqlStatement* d_updateOrderNameAndAuthTypeQuery_stmt;
+ SSqlStatement* d_nullifyOrderNameAndUpdateAuthQuery_stmt;
+ SSqlStatement* d_nullifyOrderNameAndUpdateAuthTypeQuery_stmt;
+ SSqlStatement* d_RemoveEmptyNonTerminalsFromZoneQuery_stmt;
+ SSqlStatement* d_DeleteEmptyNonTerminalQuery_stmt;
+ SSqlStatement* d_AddDomainKeyQuery_stmt;
+ SSqlStatement* d_ListDomainKeysQuery_stmt;
+ SSqlStatement* d_GetAllDomainMetadataQuery_stmt;
+ SSqlStatement* d_GetDomainMetadataQuery_stmt;
+ SSqlStatement* d_ClearDomainMetadataQuery_stmt;
+ SSqlStatement* d_ClearDomainAllMetadataQuery_stmt;
+ SSqlStatement* d_SetDomainMetadataQuery_stmt;
+ SSqlStatement* d_RemoveDomainKeyQuery_stmt;
+ SSqlStatement* d_ActivateDomainKeyQuery_stmt;
+ SSqlStatement* d_DeactivateDomainKeyQuery_stmt;
+ SSqlStatement* d_ClearDomainAllKeysQuery_stmt;
+ SSqlStatement* d_getTSIGKeyQuery_stmt;
+ SSqlStatement* d_setTSIGKeyQuery_stmt;
+ SSqlStatement* d_deleteTSIGKeyQuery_stmt;
+ SSqlStatement* d_getTSIGKeysQuery_stmt;
+ SSqlStatement* d_getAllDomainsQuery_stmt;
+ SSqlStatement* d_ListCommentsQuery_stmt;
+ SSqlStatement* d_InsertCommentQuery_stmt;
+ SSqlStatement* d_DeleteCommentRRsetQuery_stmt;
+ SSqlStatement* d_DeleteCommentsQuery_stmt;
+ SSqlStatement* d_SearchRecordsQuery_stmt;
+ SSqlStatement* d_SearchCommentsQuery_stmt;
+
+protected:
+ bool d_dnssecQueries;
+};
+
+#endif /* PDNS_GSQLBACKEND_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SSQL_HH
+#define SSQL_HH
+
+#include <string>
+#include <vector>
+#include <inttypes.h>
+#include "../../dnsname.hh"
+#include "../../namespaces.hh"
+#include "../../misc.hh"
+
+class SSqlException
+{
+public:
+ SSqlException(const string &reason)
+ {
+ d_reason=reason;
+ }
+
+ string txtReason()
+ {
+ return d_reason;
+ }
+private:
+ string d_reason;
+};
+
+class SSqlStatement
+{
+public:
+ typedef vector<string> row_t;
+ typedef vector<row_t> result_t;
+
+ virtual SSqlStatement* bind(const string& name, bool value)=0;
+ virtual SSqlStatement* bind(const string& name, int value)=0;
+ virtual SSqlStatement* bind(const string& name, uint32_t value)=0;
+ virtual SSqlStatement* bind(const string& name, long value)=0;
+ virtual SSqlStatement* bind(const string& name, unsigned long value)=0;
+ virtual SSqlStatement* bind(const string& name, long long value)=0;;
+ virtual SSqlStatement* bind(const string& name, unsigned long long value)=0;
+ virtual SSqlStatement* bind(const string& name, const std::string& value)=0;
+ SSqlStatement* bind(const string& name, const DNSName& value) {
+ return bind(name, toLower(value.toStringRootDot()));
+ }
+ virtual SSqlStatement* bindNull(const string& name)=0;
+ virtual SSqlStatement* execute()=0;;
+ virtual bool hasNextRow()=0;
+ virtual SSqlStatement* nextRow(row_t& row)=0;
+ virtual SSqlStatement* getResult(result_t& result)=0;
+ virtual SSqlStatement* reset()=0;
+ virtual const std::string& getQuery()=0;
+ virtual ~SSqlStatement();
+};
+
+class SSql
+{
+public:
+ virtual SSqlException sPerrorException(const string &reason)=0;
+ virtual SSqlStatement* prepare(const string& query, int nparams)=0;
+ virtual void execute(const string& query)=0;
+ virtual void startTransaction()=0;
+ virtual void rollback()=0;
+ virtual void commit()=0;
+ virtual void setLog(bool state){}
+ virtual ~SSql(){};
+};
+
+#endif /* SSQL_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdint.h>
+#include <stdio.h>
+#include <string>
+#include <cstring>
+#include <stdlib.h>
+#include <iostream>
+#include "base32.hh"
+#include "namespaces.hh"
+
+/* based on freebsd:src/contrib/opie/libopie/btoe.c extract: get bit ranges from a char* */
+/* NOTE: length should not exceed 8; all callers inside PowerDNS only pass length=5 though */
+unsigned char extract_bits(const char *s, int start, int length)
+{
+ uint16_t x;
+ unsigned char cl, cc;
+
+ if(!length)
+ return 0;
+
+ cl = s[start / 8];
+ if(start / 8 < (start + length-1)/8)
+ cc = s[start / 8 + 1];
+ else
+ cc = 0;
+
+ x = (uint16_t) (cl << 8 | cc);
+ x = x >> (16 - (length + (start % 8)));
+ x = (x & (0xffff >> (16 - length)));
+ return (x);
+}
+
+/* same, set bit ranges in a char* */
+static void set_bits(char* s, int x, int start, int length)
+{
+ unsigned char cl, cc, cr;
+ uint32_t y;
+ int shift;
+
+ shift = ((8 - ((start + length) % 8)) % 8);
+ y = (uint32_t) x << shift;
+ cl = (y >> 16) & 0xff;
+ cc = (y >> 8) & 0xff;
+ cr = y & 0xff;
+ if (shift + length > 16) {
+ s[start / 8] |= cl;
+ s[start / 8 + 1] |= cc;
+ s[start / 8 + 2] |= cr;
+ }
+ else {
+ if (shift + length > 8) {
+ s[start / 8] |= cc;
+ s[start / 8 + 1] |= cr;
+ } else {
+ s[start / 8] |= cr;
+ }
+ }
+}
+
+/* convert a base32 hex character to its decoded equivalent */
+static int unbase32hex(char c)
+{
+ if(c >= '0' && c<='9')
+ return c-'0';
+ if(c >= 'a' && c<='z')
+ return 10 + (c-'a');
+ if(c >= 'A' && c<='Z')
+ return 10 + (c-'A');
+ if(c=='=')
+ return '=';
+ return -1;
+}
+
+/* convert a binary string to base32hex */
+string toBase32Hex(const std::string& input)
+{
+ static const char base32hex[] = "0123456789abcdefghijklmnopqrstuv=";
+ string ret;
+ ret.reserve(4+ 8*input.length()/5); // optimization
+ // process input in groups of 5 8-bit chunks, emit 8 5-bit chunks
+ for(string::size_type offset = 0 ; offset < input.length(); offset+=5) {
+ int todo = input.length() - offset;
+ int stuffing; // how much '=' to add at the end
+
+ switch(todo) {
+ case 1:
+ stuffing = 6; break;
+ case 2:
+ stuffing = 4; break;
+ case 3:
+ stuffing = 3; break;
+ case 4:
+ stuffing = 1; break;
+ default: // -> 0 or more than 5, no stuffing
+ stuffing = 0; break;
+ }
+
+ for(int n=0; n < 8 - stuffing; ++n)
+ ret.append(1, base32hex[extract_bits(input.c_str()+offset, n*5, 5)]);
+ ret.append(stuffing, '=');
+ }
+
+ return ret;
+}
+
+// convert base32hex encoded string to normal string
+string fromBase32Hex(const std::string& input)
+{
+ string ret;
+ char block[5]={0,0,0,0,0}; // we process 5 8-bit chunks at a time
+ string::size_type n, toWrite=0;
+ for(n = 0; n < input.length(); ++n) {
+ int c=unbase32hex(input[n]);
+ if(c == '=' || c < 0) // stop at stuffing or error
+ break;
+ set_bits(block, c , (n % 8) * 5, 5);
+ if(++toWrite == 8) {
+ ret.append(block, sizeof(block));
+ memset(block, 0, sizeof(block));
+ toWrite = 0;
+ }
+ }
+ ret.append(block, (toWrite*5)/8);
+
+ return ret;
+}
+
+#if 0
+int main(int argc, char **argv)
+{
+ if(argc!=3 || (argc==3 && strcmp(argv[1],"from") && strcmp(argv[1],"to"))) {
+ printf("syntax: base32 from|to string\n");
+ exit(0);
+ }
+ if(!strcmp(argv[1],"to")) {
+ printf("input: '%s'\noutput: '%s'\n",
+ argv[2],
+ toBase32Hex(argv[2]).c_str());
+ }
+ else {
+ cout<<"input: '"<<argv[2]<<"'\noutput: '"<<fromBase32Hex(argv[2])<<"'\n";
+ }
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_BASE32_HH
+#define PDNS_BASE32_HH
+#include <string>
+
+std::string toBase32Hex(const std::string& input);
+std::string fromBase32Hex(const std::string& input);
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "base64.hh"
+#include <stdexcept>
+#include <boost/scoped_array.hpp>
+#include <openssl/bio.h>
+#include <openssl/evp.h>
+
+int B64Decode(const std::string& src, std::string& dst)
+{
+ if (src.empty() ) {
+ dst.clear();
+ return 0;
+ }
+ int dlen = ( src.length() * 6 + 7 ) / 8 ;
+ ssize_t olen = 0;
+ boost::scoped_array<unsigned char> d( new unsigned char[dlen] );
+ BIO *bio, *b64;
+ bio = BIO_new(BIO_s_mem());
+ BIO_write(bio, src.c_str(), src.length());
+ b64 = BIO_new(BIO_f_base64());
+ bio = BIO_push(b64, bio);
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+ olen = BIO_read(b64, d.get(), dlen);
+ if ((olen == 0 || olen == -1) && BIO_should_retry(bio)) {
+ BIO_free_all(bio);
+ throw std::runtime_error("BIO_read failed to read all data from memory buffer");
+ }
+ BIO_free_all(bio);
+ if (olen > 0) {
+ dst = std::string( reinterpret_cast<const char*>(d.get()), olen );
+ return 0;
+ }
+ return -1;
+}
+
+std::string Base64Encode(const std::string& src)
+{
+ if (!src.empty()) {
+ size_t olen = 0;
+ BIO *bio, *b64;
+ b64 = BIO_new(BIO_f_base64());
+ bio = BIO_new(BIO_s_mem());
+ bio = BIO_push(b64, bio);
+ BIO_set_flags(bio, BIO_FLAGS_BASE64_NO_NL);
+ int bioWriteRet = BIO_write(bio, src.c_str(), src.length());
+ if (bioWriteRet < 0 || (size_t) bioWriteRet != src.length()) {
+ BIO_free_all(bio);
+ throw std::runtime_error("BIO_write failed to write all data to memory buffer");
+ }
+ (void)BIO_flush(bio);
+ char* pp;
+ std::string out;
+ olen = BIO_get_mem_data(bio, &pp);
+ if (olen > 0) {
+ out = std::string(pp, olen);
+ }
+ BIO_free_all(bio);
+ return out;
+ }
+ return "";
+}
+
+#if 0
+#include <iostream>
+int main() {
+ std::string in = "PowerDNS Test String 1";
+ std::string out = Base64Encode(in);
+ std::cout << out << std::endl;
+ if (out != "UG93ZXJETlMgVGVzdCBTdHJpbmcgMQ==") {
+ std::cerr << "output did not match expected data" << std::endl;
+ }
+ std::string roundtrip;
+ B64Decode(out, roundtrip);
+ std::cout << roundtrip << std::endl;
+ if (roundtrip != in) {
+ std::cerr << "roundtripped data did not match input data" << std::endl;
+ }
+ return 0;
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_BASE64_HH
+#define PDNS_BASE64_HH
+
+#include <string>
+
+int B64Decode(const std::string& src, std::string& dst);
+std::string Base64Encode (const std::string& src);
+
+#endif
--- /dev/null
+create table domainmetadata (
+ id INTEGER PRIMARY KEY,
+ domain VARCHAR(255) COLLATE NOCASE,
+ kind VARCHAR(32) COLLATE NOCASE,
+ content TEXT
+);
+
+create index domainmetanameindex on domainmetadata(domain);
+
+create table cryptokeys (
+ id INTEGER PRIMARY KEY,
+ domain VARCHAR(255) COLLATE NOCASE,
+ flags INT NOT NULL,
+ active BOOL,
+ content TEXT
+);
+
+create index domainnameindex on cryptokeys(domain);
+
+create table tsigkeys (
+ id INTEGER PRIMARY KEY,
+ name VARCHAR(255) COLLATE NOCASE,
+ algorithm VARCHAR(50) COLLATE NOCASE,
+ secret VARCHAR(255)
+);
+
+create unique index namealgoindex on tsigkeys(name, algorithm);
--- /dev/null
+static char sqlCreate[] __attribute__((unused))=
+"create table domainmetadata ("
+" id INTEGER PRIMARY KEY,"
+" domain VARCHAR(255) COLLATE NOCASE,"
+" kind VARCHAR(32) COLLATE NOCASE,"
+" content TEXT"
+");"
+""
+"create index domainmetanameindex on domainmetadata(domain);"
+""
+"create table cryptokeys ("
+" id INTEGER PRIMARY KEY,"
+" domain VARCHAR(255) COLLATE NOCASE,"
+" flags INT NOT NULL,"
+" active BOOL,"
+" content TEXT"
+");"
+""
+"create index domainnameindex on cryptokeys(domain);"
+""
+"create table tsigkeys ("
+" id INTEGER PRIMARY KEY,"
+" name VARCHAR(255) COLLATE NOCASE,"
+" algorithm VARCHAR(50) COLLATE NOCASE,"
+" secret VARCHAR(255)"
+");"
+""
+"create unique index namealgoindex on tsigkeys(name, algorithm);"
+;
--- /dev/null
+
+#line 3 "bindlexer.c"
+
+#define YY_INT_ALIGNED short int
+
+/* A lexical scanner generated by flex */
+
+#define FLEX_SCANNER
+#define YY_FLEX_MAJOR_VERSION 2
+#define YY_FLEX_MINOR_VERSION 5
+#define YY_FLEX_SUBMINOR_VERSION 39
+#if YY_FLEX_SUBMINOR_VERSION > 0
+#define FLEX_BETA
+#endif
+
+/* First, we deal with platform-specific or compiler-specific issues. */
+
+/* begin standard C headers. */
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+/* end standard C headers. */
+
+/* flex integer type definitions */
+
+#ifndef FLEXINT_H
+#define FLEXINT_H
+
+/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
+
+#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
+
+/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
+ * if you want the limit (max/min) macros for int types.
+ */
+#ifndef __STDC_LIMIT_MACROS
+#define __STDC_LIMIT_MACROS 1
+#endif
+
+#include <inttypes.h>
+typedef int8_t flex_int8_t;
+typedef uint8_t flex_uint8_t;
+typedef int16_t flex_int16_t;
+typedef uint16_t flex_uint16_t;
+typedef int32_t flex_int32_t;
+typedef uint32_t flex_uint32_t;
+#else
+typedef signed char flex_int8_t;
+typedef short int flex_int16_t;
+typedef int flex_int32_t;
+typedef unsigned char flex_uint8_t;
+typedef unsigned short int flex_uint16_t;
+typedef unsigned int flex_uint32_t;
+
+/* Limits of integral types. */
+#ifndef INT8_MIN
+#define INT8_MIN (-128)
+#endif
+#ifndef INT16_MIN
+#define INT16_MIN (-32767-1)
+#endif
+#ifndef INT32_MIN
+#define INT32_MIN (-2147483647-1)
+#endif
+#ifndef INT8_MAX
+#define INT8_MAX (127)
+#endif
+#ifndef INT16_MAX
+#define INT16_MAX (32767)
+#endif
+#ifndef INT32_MAX
+#define INT32_MAX (2147483647)
+#endif
+#ifndef UINT8_MAX
+#define UINT8_MAX (255U)
+#endif
+#ifndef UINT16_MAX
+#define UINT16_MAX (65535U)
+#endif
+#ifndef UINT32_MAX
+#define UINT32_MAX (4294967295U)
+#endif
+
+#endif /* ! C99 */
+
+#endif /* ! FLEXINT_H */
+
+#ifdef __cplusplus
+
+/* The "const" storage-class-modifier is valid. */
+#define YY_USE_CONST
+
+#else /* ! __cplusplus */
+
+/* C99 requires __STDC__ to be defined as 1. */
+#if defined (__STDC__)
+
+#define YY_USE_CONST
+
+#endif /* defined (__STDC__) */
+#endif /* ! __cplusplus */
+
+#ifdef YY_USE_CONST
+#define yyconst const
+#else
+#define yyconst
+#endif
+
+/* Returned upon end-of-file. */
+#define YY_NULL 0
+
+/* Promotes a possibly negative, possibly signed char to an unsigned
+ * integer for use as an array index. If the signed char is negative,
+ * we want to instead treat it as an 8-bit unsigned char, hence the
+ * double cast.
+ */
+#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
+
+/* Enter a start condition. This macro really ought to take a parameter,
+ * but we do it the disgusting crufty way forced on us by the ()-less
+ * definition of BEGIN.
+ */
+#define BEGIN (yy_start) = 1 + 2 *
+
+/* Translate the current start state into a value that can be later handed
+ * to BEGIN to return to the state. The YYSTATE alias is for lex
+ * compatibility.
+ */
+#define YY_START (((yy_start) - 1) / 2)
+#define YYSTATE YY_START
+
+/* Action number for EOF rule of a given start state. */
+#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
+
+/* Special action meaning "start processing a new file". */
+#define YY_NEW_FILE yyrestart(yyin )
+
+#define YY_END_OF_BUFFER_CHAR 0
+
+/* Size of default input buffer. */
+#ifndef YY_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k.
+ * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
+ * Ditto for the __ia64__ case accordingly.
+ */
+#define YY_BUF_SIZE 32768
+#else
+#define YY_BUF_SIZE 16384
+#endif /* __ia64__ */
+#endif
+
+/* The state buf must be large enough to hold one state per character in the main buffer.
+ */
+#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
+
+#ifndef YY_TYPEDEF_YY_BUFFER_STATE
+#define YY_TYPEDEF_YY_BUFFER_STATE
+typedef struct yy_buffer_state *YY_BUFFER_STATE;
+#endif
+
+#ifndef YY_TYPEDEF_YY_SIZE_T
+#define YY_TYPEDEF_YY_SIZE_T
+typedef size_t yy_size_t;
+#endif
+
+extern yy_size_t yyleng;
+
+extern FILE *yyin, *yyout;
+
+#define EOB_ACT_CONTINUE_SCAN 0
+#define EOB_ACT_END_OF_FILE 1
+#define EOB_ACT_LAST_MATCH 2
+
+ #define YY_LESS_LINENO(n)
+ #define YY_LINENO_REWIND_TO(ptr)
+
+/* Return all but the first "n" matched characters back to the input stream. */
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ *yy_cp = (yy_hold_char); \
+ YY_RESTORE_YY_MORE_OFFSET \
+ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
+ YY_DO_BEFORE_ACTION; /* set up yytext again */ \
+ } \
+ while ( 0 )
+
+#define unput(c) yyunput( c, (yytext_ptr) )
+
+#ifndef YY_STRUCT_YY_BUFFER_STATE
+#define YY_STRUCT_YY_BUFFER_STATE
+struct yy_buffer_state
+ {
+ FILE *yy_input_file;
+
+ char *yy_ch_buf; /* input buffer */
+ char *yy_buf_pos; /* current position in input buffer */
+
+ /* Size of input buffer in bytes, not including room for EOB
+ * characters.
+ */
+ yy_size_t yy_buf_size;
+
+ /* Number of characters read into yy_ch_buf, not including EOB
+ * characters.
+ */
+ yy_size_t yy_n_chars;
+
+ /* Whether we "own" the buffer - i.e., we know we created it,
+ * and can realloc() it to grow it, and should free() it to
+ * delete it.
+ */
+ int yy_is_our_buffer;
+
+ /* Whether this is an "interactive" input source; if so, and
+ * if we're using stdio for input, then we want to use getc()
+ * instead of fread(), to make sure we stop fetching input after
+ * each newline.
+ */
+ int yy_is_interactive;
+
+ /* Whether we're considered to be at the beginning of a line.
+ * If so, '^' rules will be active on the next match, otherwise
+ * not.
+ */
+ int yy_at_bol;
+
+ int yy_bs_lineno; /**< The line count. */
+ int yy_bs_column; /**< The column count. */
+
+ /* Whether to try to fill the input buffer when we reach the
+ * end of it.
+ */
+ int yy_fill_buffer;
+
+ int yy_buffer_status;
+
+#define YY_BUFFER_NEW 0
+#define YY_BUFFER_NORMAL 1
+ /* When an EOF's been seen but there's still some text to process
+ * then we mark the buffer as YY_EOF_PENDING, to indicate that we
+ * shouldn't try reading from the input source any more. We might
+ * still have a bunch of tokens to match, though, because of
+ * possible backing-up.
+ *
+ * When we actually see the EOF, we change the status to "new"
+ * (via yyrestart()), so that the user can continue scanning by
+ * just pointing yyin at a new input file.
+ */
+#define YY_BUFFER_EOF_PENDING 2
+
+ };
+#endif /* !YY_STRUCT_YY_BUFFER_STATE */
+
+/* Stack of input buffers. */
+static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
+static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
+static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
+
+/* We provide macros for accessing buffer states in case in the
+ * future we want to put the buffer states in a more general
+ * "scanner state".
+ *
+ * Returns the top of the stack, or NULL.
+ */
+#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
+ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
+ : NULL)
+
+/* Same as previous macro, but useful when we know that the buffer stack is not
+ * NULL or when we need an lvalue. For internal use only.
+ */
+#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
+
+/* yy_hold_char holds the character lost when yytext is formed. */
+static char yy_hold_char;
+static yy_size_t yy_n_chars; /* number of characters read into yy_ch_buf */
+yy_size_t yyleng;
+
+/* Points to current character in buffer. */
+static char *yy_c_buf_p = (char *) 0;
+static int yy_init = 0; /* whether we need to initialize */
+static int yy_start = 0; /* start state number */
+
+/* Flag which is used to allow yywrap()'s to do buffer switches
+ * instead of setting up a fresh yyin. A bit of a hack ...
+ */
+static int yy_did_buffer_switch_on_eof;
+
+void yyrestart (FILE *input_file );
+void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer );
+YY_BUFFER_STATE yy_create_buffer (FILE *file,int size );
+void yy_delete_buffer (YY_BUFFER_STATE b );
+void yy_flush_buffer (YY_BUFFER_STATE b );
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer );
+void yypop_buffer_state (void );
+
+static void yyensure_buffer_stack (void );
+static void yy_load_buffer_state (void );
+static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file );
+
+#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
+
+YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size );
+YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str );
+YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,yy_size_t len );
+
+void *yyalloc (yy_size_t );
+void *yyrealloc (void *,yy_size_t );
+void yyfree (void * );
+
+#define yy_new_buffer yy_create_buffer
+
+#define yy_set_interactive(is_interactive) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){ \
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
+ }
+
+#define yy_set_bol(at_bol) \
+ { \
+ if ( ! YY_CURRENT_BUFFER ){\
+ yyensure_buffer_stack (); \
+ YY_CURRENT_BUFFER_LVALUE = \
+ yy_create_buffer(yyin,YY_BUF_SIZE ); \
+ } \
+ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
+ }
+
+#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
+
+/* Begin user sect3 */
+
+typedef unsigned char YY_CHAR;
+
+FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
+
+typedef int yy_state_type;
+
+extern int yylineno;
+
+int yylineno = 1;
+
+extern char *yytext;
+#define yytext_ptr yytext
+
+static yy_state_type yy_get_previous_state (void );
+static yy_state_type yy_try_NUL_trans (yy_state_type current_state );
+static int yy_get_next_buffer (void );
+static void yy_fatal_error (yyconst char msg[] );
+
+/* Done after the current pattern has been matched and before the
+ * corresponding action - sets up yytext.
+ */
+#define YY_DO_BEFORE_ACTION \
+ (yytext_ptr) = yy_bp; \
+ yyleng = (size_t) (yy_cp - yy_bp); \
+ (yy_hold_char) = *yy_cp; \
+ *yy_cp = '\0'; \
+ (yy_c_buf_p) = yy_cp;
+
+#define YY_NUM_RULES 29
+#define YY_END_OF_BUFFER 30
+/* This struct is not used in this scanner,
+ but its presence is necessary. */
+struct yy_trans_info
+ {
+ flex_int32_t yy_verify;
+ flex_int32_t yy_nxt;
+ };
+static yyconst flex_int16_t yy_accept[109] =
+ { 0,
+ 21, 21, 2, 2, 7, 7, 19, 19, 30, 21,
+ 26, 25, 18, 21, 21, 24, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 22, 23, 2, 4, 3,
+ 29, 7, 29, 19, 20, 21, 26, 21, 0, 28,
+ 1, 21, 21, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 2, 3, 3, 5, 7, 0, 19, 21,
+ 0, 27, 13, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 0, 21, 21, 10, 21, 21, 21, 21,
+ 17, 9, 8, 21, 21, 21, 21, 21, 21, 21,
+ 21, 21, 21, 21, 21, 21, 21, 6, 14, 16,
+
+ 11, 21, 21, 21, 15, 21, 12, 0
+ } ;
+
+static yyconst flex_int32_t yy_ec[256] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 2, 3,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 2, 1, 4, 5, 1, 1, 1, 1, 1,
+ 1, 6, 1, 1, 7, 1, 8, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 9, 1,
+ 1, 1, 1, 1, 10, 1, 11, 12, 13, 14,
+ 15, 1, 16, 1, 1, 17, 18, 19, 20, 21,
+ 1, 22, 23, 24, 25, 1, 1, 1, 26, 27,
+ 1, 1, 1, 1, 1, 1, 28, 1, 29, 30,
+
+ 31, 32, 33, 1, 34, 1, 1, 35, 36, 37,
+ 38, 39, 1, 40, 41, 42, 43, 1, 1, 1,
+ 44, 45, 46, 1, 47, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1
+ } ;
+
+static yyconst flex_int32_t yy_meta[48] =
+ { 0,
+ 1, 2, 3, 4, 1, 5, 1, 1, 2, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 6, 6
+ } ;
+
+static yyconst flex_int16_t yy_base[121] =
+ { 0,
+ 0, 0, 45, 46, 51, 52, 192, 165, 131, 0,
+ 119, 285, 285, 55, 57, 285, 51, 50, 51, 50,
+ 50, 61, 51, 47, 54, 285, 285, 0, 285, 69,
+ 285, 74, 0, 0, 285, 0, 118, 91, 116, 285,
+ 0, 94, 64, 81, 83, 89, 96, 93, 86, 86,
+ 90, 93, 0, 107, 108, 285, 130, 78, 0, 140,
+ 76, 285, 0, 97, 105, 120, 117, 130, 122, 131,
+ 135, 137, 69, 43, 142, 0, 129, 139, 143, 137,
+ 0, 0, 285, 139, 135, 148, 142, 140, 148, 150,
+ 161, 169, 168, 161, 166, 166, 169, 0, 0, 0,
+
+ 0, 176, 167, 180, 0, 169, 0, 285, 213, 219,
+ 225, 231, 236, 242, 248, 254, 260, 266, 272, 278
+ } ;
+
+static yyconst flex_int16_t yy_def[121] =
+ { 0,
+ 108, 1, 109, 109, 110, 110, 111, 111, 108, 112,
+ 108, 108, 108, 113, 112, 108, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 108, 108, 114, 108, 115,
+ 108, 108, 116, 117, 108, 112, 108, 113, 118, 108,
+ 112, 119, 112, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 114, 115, 115, 108, 108, 116, 117, 119,
+ 120, 108, 112, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 108, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 108, 112, 112, 112, 112, 112, 112, 112,
+ 112, 112, 112, 112, 112, 112, 112, 112, 112, 112,
+
+ 112, 112, 112, 112, 112, 112, 112, 0, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108
+ } ;
+
+static yyconst flex_int16_t yy_nxt[333] =
+ { 0,
+ 10, 11, 12, 13, 14, 10, 10, 15, 16, 17,
+ 10, 18, 10, 19, 10, 20, 21, 22, 10, 23,
+ 10, 10, 10, 24, 10, 10, 25, 17, 10, 18,
+ 10, 19, 10, 20, 21, 22, 10, 23, 10, 10,
+ 10, 24, 10, 10, 25, 26, 27, 29, 29, 84,
+ 30, 30, 32, 32, 33, 33, 39, 40, 39, 32,
+ 32, 43, 41, 39, 42, 45, 46, 44, 47, 48,
+ 49, 50, 51, 52, 55, 57, 56, 83, 62, 43,
+ 63, 73, 57, 45, 46, 44, 47, 48, 49, 50,
+ 51, 52, 39, 40, 39, 61, 62, 61, 63, 39,
+
+ 39, 39, 61, 64, 65, 66, 67, 68, 69, 70,
+ 71, 72, 108, 55, 108, 56, 74, 75, 40, 37,
+ 37, 64, 65, 66, 67, 68, 69, 70, 71, 72,
+ 108, 57, 76, 77, 74, 75, 39, 39, 57, 61,
+ 61, 61, 62, 61, 78, 79, 80, 81, 61, 82,
+ 76, 77, 85, 86, 87, 88, 89, 90, 91, 92,
+ 93, 94, 78, 79, 80, 81, 95, 82, 35, 96,
+ 85, 86, 87, 88, 89, 90, 91, 92, 93, 94,
+ 97, 98, 99, 100, 95, 61, 61, 96, 101, 102,
+ 103, 104, 105, 106, 107, 35, 108, 108, 97, 98,
+
+ 99, 100, 108, 108, 108, 108, 101, 102, 103, 104,
+ 105, 106, 107, 28, 28, 28, 28, 28, 28, 31,
+ 31, 31, 31, 31, 31, 34, 34, 34, 34, 34,
+ 34, 36, 108, 108, 108, 36, 38, 38, 38, 38,
+ 38, 38, 53, 53, 108, 53, 108, 53, 54, 54,
+ 108, 54, 54, 54, 58, 108, 108, 108, 58, 58,
+ 59, 59, 59, 108, 59, 59, 39, 39, 39, 39,
+ 39, 39, 60, 60, 60, 60, 60, 60, 61, 61,
+ 61, 61, 61, 61, 9, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108
+ } ;
+
+static yyconst flex_int16_t yy_chk[333] =
+ { 0,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 3, 4, 74,
+ 3, 4, 5, 6, 5, 6, 14, 14, 14, 5,
+ 6, 17, 15, 14, 15, 18, 19, 17, 20, 21,
+ 22, 23, 24, 25, 30, 32, 30, 73, 61, 17,
+ 43, 58, 32, 18, 19, 17, 20, 21, 22, 23,
+ 24, 25, 38, 38, 38, 42, 42, 42, 43, 38,
+
+ 14, 14, 42, 44, 45, 46, 47, 48, 49, 50,
+ 51, 52, 54, 55, 54, 55, 64, 65, 39, 37,
+ 11, 44, 45, 46, 47, 48, 49, 50, 51, 52,
+ 9, 57, 66, 67, 64, 65, 38, 38, 57, 42,
+ 42, 60, 60, 60, 68, 69, 70, 71, 60, 72,
+ 66, 67, 75, 77, 78, 79, 80, 84, 85, 86,
+ 87, 88, 68, 69, 70, 71, 89, 72, 8, 90,
+ 75, 77, 78, 79, 80, 84, 85, 86, 87, 88,
+ 91, 92, 93, 94, 89, 60, 60, 90, 95, 96,
+ 97, 102, 103, 104, 106, 7, 0, 0, 91, 92,
+
+ 93, 94, 0, 0, 0, 0, 95, 96, 97, 102,
+ 103, 104, 106, 109, 109, 109, 109, 109, 109, 110,
+ 110, 110, 110, 110, 110, 111, 111, 111, 111, 111,
+ 111, 112, 0, 0, 0, 112, 113, 113, 113, 113,
+ 113, 113, 114, 114, 0, 114, 0, 114, 115, 115,
+ 0, 115, 115, 115, 116, 0, 0, 0, 116, 116,
+ 117, 117, 117, 0, 117, 117, 118, 118, 118, 118,
+ 118, 118, 119, 119, 119, 119, 119, 119, 120, 120,
+ 120, 120, 120, 120, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108, 108, 108, 108, 108, 108, 108, 108, 108,
+ 108, 108
+ } ;
+
+static yy_state_type yy_last_accepting_state;
+static char *yy_last_accepting_cpos;
+
+extern int yy_flex_debug;
+int yy_flex_debug = 0;
+
+/* The intent behind this definition is that it'll catch
+ * any uses of REJECT which flex missed.
+ */
+#define REJECT reject_used_but_not_detected
+#define yymore() yymore_used_but_not_detected
+#define YY_MORE_ADJ 0
+#define YY_RESTORE_YY_MORE_OFFSET
+char *yytext;
+#line 1 "bindlexer.l"
+#line 2 "bindlexer.l"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define YY_NO_INPUT 1
+#define YYSTYPE char *
+
+#include "bindparser.h"
+
+int linenumber;
+#define MAX_INCLUDE_DEPTH 10
+YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+int include_stack_ln[MAX_INCLUDE_DEPTH];
+char *include_stack_name[MAX_INCLUDE_DEPTH];
+char *current_filename;
+char *original_filename;
+int include_stack_ptr = 0;
+extern const char *bind_directory;
+
+
+
+
+#define YY_NO_INPUT 1
+#line 595 "bindlexer.c"
+
+#define INITIAL 0
+#define comment 1
+#define incl 2
+#define quoted 3
+
+#ifndef YY_NO_UNISTD_H
+/* Special case for "unistd.h", since it is non-ANSI. We include it way
+ * down here because we want the user's section 1 to have been scanned first.
+ * The user has a chance to override it with an option.
+ */
+#include <unistd.h>
+#endif
+
+#ifndef YY_EXTRA_TYPE
+#define YY_EXTRA_TYPE void *
+#endif
+
+static int yy_init_globals (void );
+
+/* Accessor methods to globals.
+ These are made visible to non-reentrant scanners for convenience. */
+
+int yylex_destroy (void );
+
+int yyget_debug (void );
+
+void yyset_debug (int debug_flag );
+
+YY_EXTRA_TYPE yyget_extra (void );
+
+void yyset_extra (YY_EXTRA_TYPE user_defined );
+
+FILE *yyget_in (void );
+
+void yyset_in (FILE * in_str );
+
+FILE *yyget_out (void );
+
+void yyset_out (FILE * out_str );
+
+yy_size_t yyget_leng (void );
+
+char *yyget_text (void );
+
+int yyget_lineno (void );
+
+void yyset_lineno (int line_number );
+
+/* Macros after this point can all be overridden by user definitions in
+ * section 1.
+ */
+
+#ifndef YY_SKIP_YYWRAP
+#ifdef __cplusplus
+extern "C" int yywrap (void );
+#else
+extern int yywrap (void );
+#endif
+#endif
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char *,yyconst char *,int );
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * );
+#endif
+
+#ifndef YY_NO_INPUT
+
+#ifdef __cplusplus
+static int yyinput (void );
+#else
+static int input (void );
+#endif
+
+#endif
+
+ static int yy_start_stack_ptr = 0;
+ static int yy_start_stack_depth = 0;
+ static int *yy_start_stack = NULL;
+
+ static void yy_push_state (int new_state );
+
+ static void yy_pop_state (void );
+
+/* Amount of stuff to slurp up with each read. */
+#ifndef YY_READ_BUF_SIZE
+#ifdef __ia64__
+/* On IA-64, the buffer size is 16k, not 8k */
+#define YY_READ_BUF_SIZE 16384
+#else
+#define YY_READ_BUF_SIZE 8192
+#endif /* __ia64__ */
+#endif
+
+/* Copy whatever the last rule matched to the standard output. */
+#ifndef ECHO
+/* This used to be an fputs(), but since the string might contain NUL's,
+ * we now use fwrite().
+ */
+#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
+#endif
+
+/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL,
+ * is returned in "result".
+ */
+#ifndef YY_INPUT
+#define YY_INPUT(buf,result,max_size) \
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
+ { \
+ int c = '*'; \
+ int n; \
+ for ( n = 0; n < max_size && \
+ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
+ buf[n] = (char) c; \
+ if ( c == '\n' ) \
+ buf[n++] = (char) c; \
+ if ( c == EOF && ferror( yyin ) ) \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ result = n; \
+ } \
+ else \
+ { \
+ errno=0; \
+ while ( (result = fread(buf, 1, (yy_size_t) max_size, yyin)) == 0 && ferror(yyin)) \
+ { \
+ if( errno != EINTR) \
+ { \
+ YY_FATAL_ERROR( "input in flex scanner failed" ); \
+ break; \
+ } \
+ errno=0; \
+ clearerr(yyin); \
+ } \
+ }\
+\
+
+#endif
+
+/* No semi-colon after return; correct usage is to write "yyterminate();" -
+ * we don't want an extra ';' after the "return" because that will cause
+ * some compilers to complain about unreachable statements.
+ */
+#ifndef yyterminate
+#define yyterminate() return YY_NULL
+#endif
+
+/* Number of entries by which start-condition stack grows. */
+#ifndef YY_START_STACK_INCR
+#define YY_START_STACK_INCR 25
+#endif
+
+/* Report a fatal error. */
+#ifndef YY_FATAL_ERROR
+#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
+#endif
+
+/* end tables serialization structures and prototypes */
+
+/* Default declaration of generated scanner - a define so the user can
+ * easily add parameters.
+ */
+#ifndef YY_DECL
+#define YY_DECL_IS_OURS 1
+
+extern int yylex (void);
+
+#define YY_DECL int yylex (void)
+#endif /* !YY_DECL */
+
+/* Code executed at the beginning of each rule, after yytext and yyleng
+ * have been set up.
+ */
+#ifndef YY_USER_ACTION
+#define YY_USER_ACTION
+#endif
+
+/* Code executed at the end of each rule. */
+#ifndef YY_BREAK
+#define YY_BREAK break;
+#endif
+
+#define YY_RULE_SETUP \
+ YY_USER_ACTION
+
+/** The main scanner function which does all the work.
+ */
+YY_DECL
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp, *yy_bp;
+ register int yy_act;
+
+ if ( !(yy_init) )
+ {
+ (yy_init) = 1;
+
+#ifdef YY_USER_INIT
+ YY_USER_INIT;
+#endif
+
+ if ( ! (yy_start) )
+ (yy_start) = 1; /* first start state */
+
+ if ( ! yyin )
+ yyin = stdin;
+
+ if ( ! yyout )
+ yyout = stdout;
+
+ if ( ! YY_CURRENT_BUFFER ) {
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_load_buffer_state( );
+ }
+
+ {
+#line 32 "bindlexer.l"
+
+
+
+#line 822 "bindlexer.c"
+
+ while ( 1 ) /* loops until end-of-file is reached */
+ {
+ yy_cp = (yy_c_buf_p);
+
+ /* Support of yytext. */
+ *yy_cp = (yy_hold_char);
+
+ /* yy_bp points to the position in yy_ch_buf of the start of
+ * the current run.
+ */
+ yy_bp = yy_cp;
+
+ yy_current_state = (yy_start);
+yy_match:
+ do
+ {
+ register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)] ;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 109 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ ++yy_cp;
+ }
+ while ( yy_base[yy_current_state] != 285 );
+
+yy_find_action:
+ yy_act = yy_accept[yy_current_state];
+ if ( yy_act == 0 )
+ { /* have to back up */
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ yy_act = yy_accept[yy_current_state];
+ }
+
+ YY_DO_BEFORE_ACTION;
+
+do_action: /* This label is used only to access EOF actions. */
+
+ switch ( yy_act )
+ { /* beginning of action switch */
+ case 0: /* must back up */
+ /* undo the effects of YY_DO_BEFORE_ACTION */
+ *yy_cp = (yy_hold_char);
+ yy_cp = (yy_last_accepting_cpos);
+ yy_current_state = (yy_last_accepting_state);
+ goto yy_find_action;
+
+case 1:
+YY_RULE_SETUP
+#line 35 "bindlexer.l"
+BEGIN(comment);
+ YY_BREAK
+case 2:
+YY_RULE_SETUP
+#line 36 "bindlexer.l"
+/* eat anything that's not a '*' */
+ YY_BREAK
+case 3:
+YY_RULE_SETUP
+#line 37 "bindlexer.l"
+/* eat up '*'s not followed by '/'s */
+ YY_BREAK
+case 4:
+/* rule 4 can match eol */
+YY_RULE_SETUP
+#line 38 "bindlexer.l"
+++linenumber;
+ YY_BREAK
+case 5:
+YY_RULE_SETUP
+#line 39 "bindlexer.l"
+BEGIN(INITIAL);
+ YY_BREAK
+case 6:
+YY_RULE_SETUP
+#line 41 "bindlexer.l"
+BEGIN(incl);
+ YY_BREAK
+case 7:
+YY_RULE_SETUP
+#line 42 "bindlexer.l"
+/* eat the whitespace */
+ YY_BREAK
+case 8:
+YY_RULE_SETUP
+#line 43 "bindlexer.l"
+{ /* got the include file name */
+ char filename[1024];
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply\n" );
+ exit( 1 );
+ }
+
+ if (strlen(yytext) <= 2) {
+ fprintf( stderr, "Empty include directive\n" );
+ exit( 1 );
+ }
+
+ yytext[strlen(yytext)-2]=0;
+
+ include_stack[include_stack_ptr]=YY_CURRENT_BUFFER;
+ include_stack_name[include_stack_ptr]=current_filename=strdup(yytext+1);
+ include_stack_ln[include_stack_ptr++]=linenumber;
+ linenumber=1;
+
+ if(*(yytext+1)=='/') {
+ if (strlen(yytext+1) >= sizeof(filename)) {
+ fprintf( stderr, "Filename '%s' is too long\n",yytext+1);
+ exit( 1 );
+ }
+ strcpy(filename,yytext+1);
+ }
+ else {
+ size_t bind_directory_len = strlen(bind_directory);
+ if (bind_directory_len >= sizeof(filename) ||
+ strlen(yytext+1) + 2 >= sizeof(filename) - bind_directory_len) {
+ fprintf( stderr, "Filename '%s' is too long\n",yytext+1);
+ exit( 1 );
+ }
+ strcpy(filename,bind_directory);
+ strcat(filename,"/");
+ strcat(filename,yytext+1);
+ }
+ filename[sizeof(filename)-1]='\0';
+
+ if (!(yyin=fopen(filename,"r"))) {
+ fprintf( stderr, "Unable to open '%s': %s\n",filename,strerror(errno));
+ exit( 1 );
+ }
+
+ BEGIN(INITIAL);
+ yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
+
+ }
+ YY_BREAK
+case YY_STATE_EOF(INITIAL):
+case YY_STATE_EOF(comment):
+case YY_STATE_EOF(incl):
+case YY_STATE_EOF(quoted):
+#line 94 "bindlexer.l"
+{
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(include_stack[include_stack_ptr]);
+ linenumber=include_stack_ln[include_stack_ptr];
+ free(include_stack_name[include_stack_ptr]);
+ if(include_stack_ptr)
+ current_filename=include_stack_name[include_stack_ptr-1];
+ else
+ current_filename=original_filename;
+ }
+ }
+ YY_BREAK
+case 9:
+YY_RULE_SETUP
+#line 117 "bindlexer.l"
+return ZONETOK;
+ YY_BREAK
+case 10:
+YY_RULE_SETUP
+#line 119 "bindlexer.l"
+return FILETOK;
+ YY_BREAK
+case 11:
+YY_RULE_SETUP
+#line 120 "bindlexer.l"
+return OPTIONSTOK;
+ YY_BREAK
+case 12:
+YY_RULE_SETUP
+#line 121 "bindlexer.l"
+return ALSONOTIFYTOK;
+ YY_BREAK
+case 13:
+YY_RULE_SETUP
+#line 122 "bindlexer.l"
+return ACLTOK;
+ YY_BREAK
+case 14:
+YY_RULE_SETUP
+#line 123 "bindlexer.l"
+return LOGGINGTOK;
+ YY_BREAK
+case 15:
+YY_RULE_SETUP
+#line 124 "bindlexer.l"
+return DIRECTORYTOK;
+ YY_BREAK
+case 16:
+YY_RULE_SETUP
+#line 125 "bindlexer.l"
+return MASTERTOK;
+ YY_BREAK
+case 17:
+YY_RULE_SETUP
+#line 126 "bindlexer.l"
+return TYPETOK;
+ YY_BREAK
+case 18:
+YY_RULE_SETUP
+#line 127 "bindlexer.l"
+yy_push_state(quoted);
+ YY_BREAK
+case 19:
+/* rule 19 can match eol */
+YY_RULE_SETUP
+#line 128 "bindlexer.l"
+yylval=strdup(yytext); return QUOTEDWORD;
+ YY_BREAK
+case 20:
+YY_RULE_SETUP
+#line 129 "bindlexer.l"
+yy_pop_state();
+ YY_BREAK
+case 21:
+YY_RULE_SETUP
+#line 130 "bindlexer.l"
+yylval=strdup(yytext);return AWORD;
+ YY_BREAK
+case 22:
+YY_RULE_SETUP
+#line 131 "bindlexer.l"
+return OBRACE;
+ YY_BREAK
+case 23:
+YY_RULE_SETUP
+#line 132 "bindlexer.l"
+return EBRACE;
+ YY_BREAK
+case 24:
+YY_RULE_SETUP
+#line 133 "bindlexer.l"
+return SEMICOLON;
+ YY_BREAK
+case 25:
+/* rule 25 can match eol */
+YY_RULE_SETUP
+#line 134 "bindlexer.l"
+linenumber++;
+ YY_BREAK
+case 26:
+YY_RULE_SETUP
+#line 135 "bindlexer.l"
+;
+ YY_BREAK
+case 27:
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 136 "bindlexer.l"
+;
+ YY_BREAK
+case 28:
+*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */
+(yy_c_buf_p) = yy_cp -= 1;
+YY_DO_BEFORE_ACTION; /* set up yytext again */
+YY_RULE_SETUP
+#line 137 "bindlexer.l"
+;
+ YY_BREAK
+case 29:
+YY_RULE_SETUP
+#line 138 "bindlexer.l"
+ECHO;
+ YY_BREAK
+#line 1106 "bindlexer.c"
+
+ case YY_END_OF_BUFFER:
+ {
+ /* Amount of text matched not including the EOB char. */
+ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
+
+ /* Undo the effects of YY_DO_BEFORE_ACTION. */
+ *yy_cp = (yy_hold_char);
+ YY_RESTORE_YY_MORE_OFFSET
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
+ {
+ /* We're scanning a new file or input source. It's
+ * possible that this happened because the user
+ * just pointed yyin at a new source and called
+ * yylex(). If so, then we have to assure
+ * consistency between YY_CURRENT_BUFFER and our
+ * globals. Here is the right place to do so, because
+ * this is the first action (other than possibly a
+ * back-up) that will match for the new input source.
+ */
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
+ }
+
+ /* Note that here we test for yy_c_buf_p "<=" to the position
+ * of the first EOB in the buffer, since yy_c_buf_p will
+ * already have been incremented past the NUL character
+ * (since all states make transitions on EOB to the
+ * end-of-buffer state). Contrast this with the test
+ * in input().
+ */
+ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ { /* This was really a NUL. */
+ yy_state_type yy_next_state;
+
+ (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ /* Okay, we're now positioned to make the NUL
+ * transition. We couldn't have
+ * yy_get_previous_state() go ahead and do it
+ * for us because it doesn't know how to deal
+ * with the possibility of jamming (and we don't
+ * want to build jamming into it because then it
+ * will run more slowly).
+ */
+
+ yy_next_state = yy_try_NUL_trans( yy_current_state );
+
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+
+ if ( yy_next_state )
+ {
+ /* Consume the NUL. */
+ yy_cp = ++(yy_c_buf_p);
+ yy_current_state = yy_next_state;
+ goto yy_match;
+ }
+
+ else
+ {
+ yy_cp = (yy_c_buf_p);
+ goto yy_find_action;
+ }
+ }
+
+ else switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_END_OF_FILE:
+ {
+ (yy_did_buffer_switch_on_eof) = 0;
+
+ if ( yywrap( ) )
+ {
+ /* Note: because we've taken care in
+ * yy_get_next_buffer() to have set up
+ * yytext, we can now set up
+ * yy_c_buf_p so that if some total
+ * hoser (like flex itself) wants to
+ * call the scanner after we return the
+ * YY_NULL, it'll still work - another
+ * YY_NULL will get returned.
+ */
+ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
+
+ yy_act = YY_STATE_EOF(YY_START);
+ goto do_action;
+ }
+
+ else
+ {
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+ }
+ break;
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) =
+ (yytext_ptr) + yy_amount_of_matched_text;
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_match;
+
+ case EOB_ACT_LAST_MATCH:
+ (yy_c_buf_p) =
+ &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
+
+ yy_current_state = yy_get_previous_state( );
+
+ yy_cp = (yy_c_buf_p);
+ yy_bp = (yytext_ptr) + YY_MORE_ADJ;
+ goto yy_find_action;
+ }
+ break;
+ }
+
+ default:
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--no action found" );
+ } /* end of action switch */
+ } /* end of scanning one token */
+ } /* end of user's declarations */
+} /* end of yylex */
+
+/* yy_get_next_buffer - try to read in a new buffer
+ *
+ * Returns a code representing an action:
+ * EOB_ACT_LAST_MATCH -
+ * EOB_ACT_CONTINUE_SCAN - continue scanning from current position
+ * EOB_ACT_END_OF_FILE - end of file
+ */
+static int yy_get_next_buffer (void)
+{
+ register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
+ register char *source = (yytext_ptr);
+ register int number_to_move, i;
+ int ret_val;
+
+ if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
+ YY_FATAL_ERROR(
+ "fatal flex scanner internal error--end of buffer missed" );
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
+ { /* Don't try to fill the buffer, so this is an EOF. */
+ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
+ {
+ /* We matched a single character, the EOB, so
+ * treat this as a final EOF.
+ */
+ return EOB_ACT_END_OF_FILE;
+ }
+
+ else
+ {
+ /* We matched some text prior to the EOB, first
+ * process it.
+ */
+ return EOB_ACT_LAST_MATCH;
+ }
+ }
+
+ /* Try to read more data. */
+
+ /* First move last chars to start of buffer. */
+ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
+
+ for ( i = 0; i < number_to_move; ++i )
+ *(dest++) = *(source++);
+
+ if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
+ /* don't do the read, it's not guaranteed to return an EOF,
+ * just force an EOF
+ */
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
+
+ else
+ {
+ int num_to_read =
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
+
+ while ( num_to_read <= 0 )
+ { /* Not enough room in the buffer - grow it. */
+
+ /* just a shorter name for the current buffer */
+ YY_BUFFER_STATE b = YY_CURRENT_BUFFER_LVALUE;
+
+ int yy_c_buf_p_offset =
+ (int) ((yy_c_buf_p) - b->yy_ch_buf);
+
+ if ( b->yy_is_our_buffer )
+ {
+ yy_size_t new_size = b->yy_buf_size * 2;
+
+ if ( new_size <= 0 )
+ b->yy_buf_size += b->yy_buf_size / 8;
+ else
+ b->yy_buf_size *= 2;
+
+ b->yy_ch_buf = (char *)
+ /* Include room in for 2 EOB chars. */
+ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
+ }
+ else
+ /* Can't grow it, we don't own it. */
+ b->yy_ch_buf = 0;
+
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR(
+ "fatal error - scanner input buffer overflow" );
+
+ (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
+
+ num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
+ number_to_move - 1;
+
+ }
+
+ if ( num_to_read > YY_READ_BUF_SIZE )
+ num_to_read = YY_READ_BUF_SIZE;
+
+ /* Read in more data. */
+ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
+ (yy_n_chars), num_to_read );
+
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ if ( (yy_n_chars) == 0 )
+ {
+ if ( number_to_move == YY_MORE_ADJ )
+ {
+ ret_val = EOB_ACT_END_OF_FILE;
+ yyrestart(yyin );
+ }
+
+ else
+ {
+ ret_val = EOB_ACT_LAST_MATCH;
+ YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
+ YY_BUFFER_EOF_PENDING;
+ }
+ }
+
+ else
+ ret_val = EOB_ACT_CONTINUE_SCAN;
+
+ if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
+ /* Extend the array by 50%, plus the number we really need. */
+ yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size );
+ if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
+ }
+
+ (yy_n_chars) += number_to_move;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
+ YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
+
+ (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
+
+ return ret_val;
+}
+
+/* yy_get_previous_state - get the state just before the EOB char was reached */
+
+ static yy_state_type yy_get_previous_state (void)
+{
+ register yy_state_type yy_current_state;
+ register char *yy_cp;
+
+ yy_current_state = (yy_start);
+
+ for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
+ {
+ register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 109 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ }
+
+ return yy_current_state;
+}
+
+/* yy_try_NUL_trans - try to make a transition on the NUL character
+ *
+ * synopsis
+ * next_state = yy_try_NUL_trans( current_state );
+ */
+ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state )
+{
+ register int yy_is_jam;
+ register char *yy_cp = (yy_c_buf_p);
+
+ register YY_CHAR yy_c = 1;
+ if ( yy_accept[yy_current_state] )
+ {
+ (yy_last_accepting_state) = yy_current_state;
+ (yy_last_accepting_cpos) = yy_cp;
+ }
+ while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
+ {
+ yy_current_state = (int) yy_def[yy_current_state];
+ if ( yy_current_state >= 109 )
+ yy_c = yy_meta[(unsigned int) yy_c];
+ }
+ yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
+ yy_is_jam = (yy_current_state == 108);
+
+ return yy_is_jam ? 0 : yy_current_state;
+}
+
+#ifndef YY_NO_INPUT
+#ifdef __cplusplus
+ static int yyinput (void)
+#else
+ static int input (void)
+#endif
+
+{
+ int c;
+
+ *(yy_c_buf_p) = (yy_hold_char);
+
+ if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
+ {
+ /* yy_c_buf_p now points to the character we want to return.
+ * If this occurs *before* the EOB characters, then it's a
+ * valid NUL; if not, then we've hit the end of the buffer.
+ */
+ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
+ /* This was really a NUL. */
+ *(yy_c_buf_p) = '\0';
+
+ else
+ { /* need more input */
+ yy_size_t offset = (yy_c_buf_p) - (yytext_ptr);
+ ++(yy_c_buf_p);
+
+ switch ( yy_get_next_buffer( ) )
+ {
+ case EOB_ACT_LAST_MATCH:
+ /* This happens because yy_g_n_b()
+ * sees that we've accumulated a
+ * token and flags that we need to
+ * try matching the token before
+ * proceeding. But for input(),
+ * there's no matching to consider.
+ * So convert the EOB_ACT_LAST_MATCH
+ * to EOB_ACT_END_OF_FILE.
+ */
+
+ /* Reset buffer status. */
+ yyrestart(yyin );
+
+ /*FALLTHROUGH*/
+
+ case EOB_ACT_END_OF_FILE:
+ {
+ if ( yywrap( ) )
+ return EOF;
+
+ if ( ! (yy_did_buffer_switch_on_eof) )
+ YY_NEW_FILE;
+#ifdef __cplusplus
+ return yyinput();
+#else
+ return input();
+#endif
+ }
+
+ case EOB_ACT_CONTINUE_SCAN:
+ (yy_c_buf_p) = (yytext_ptr) + offset;
+ break;
+ }
+ }
+ }
+
+ c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */
+ *(yy_c_buf_p) = '\0'; /* preserve yytext */
+ (yy_hold_char) = *++(yy_c_buf_p);
+
+ return c;
+}
+#endif /* ifndef YY_NO_INPUT */
+
+/** Immediately switch to a different input stream.
+ * @param input_file A readable stream.
+ *
+ * @note This function does not reset the start condition to @c INITIAL .
+ */
+ void yyrestart (FILE * input_file )
+{
+
+ if ( ! YY_CURRENT_BUFFER ){
+ yyensure_buffer_stack ();
+ YY_CURRENT_BUFFER_LVALUE =
+ yy_create_buffer(yyin,YY_BUF_SIZE );
+ }
+
+ yy_init_buffer(YY_CURRENT_BUFFER,input_file );
+ yy_load_buffer_state( );
+}
+
+/** Switch to a different input buffer.
+ * @param new_buffer The new input buffer.
+ *
+ */
+ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer )
+{
+
+ /* TODO. We should be able to replace this entire function body
+ * with
+ * yypop_buffer_state();
+ * yypush_buffer_state(new_buffer);
+ */
+ yyensure_buffer_stack ();
+ if ( YY_CURRENT_BUFFER == new_buffer )
+ return;
+
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+ yy_load_buffer_state( );
+
+ /* We don't actually know whether we did this switch during
+ * EOF (yywrap()) processing, but the only time this flag
+ * is looked at is after yywrap() is called, so it's safe
+ * to go ahead and always set it.
+ */
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+static void yy_load_buffer_state (void)
+{
+ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
+ (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
+ yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
+ (yy_hold_char) = *(yy_c_buf_p);
+}
+
+/** Allocate and initialize an input buffer state.
+ * @param file A readable stream.
+ * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
+ *
+ * @return the allocated buffer state.
+ */
+ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size )
+{
+ YY_BUFFER_STATE b;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_buf_size = size;
+
+ /* yy_ch_buf has to be 2 characters longer than the size given because
+ * we need to put in 2 end-of-buffer characters.
+ */
+ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 );
+ if ( ! b->yy_ch_buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
+
+ b->yy_is_our_buffer = 1;
+
+ yy_init_buffer(b,file );
+
+ return b;
+}
+
+/** Destroy the buffer.
+ * @param b a buffer created with yy_create_buffer()
+ *
+ */
+ void yy_delete_buffer (YY_BUFFER_STATE b )
+{
+
+ if ( ! b )
+ return;
+
+ if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
+ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
+
+ if ( b->yy_is_our_buffer )
+ yyfree((void *) b->yy_ch_buf );
+
+ yyfree((void *) b );
+}
+
+/* Initializes or reinitializes a buffer.
+ * This function is sometimes called more than once on the same buffer,
+ * such as during a yyrestart() or at EOF.
+ */
+ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file )
+
+{
+ int oerrno = errno;
+
+ yy_flush_buffer(b );
+
+ b->yy_input_file = file;
+ b->yy_fill_buffer = 1;
+
+ /* If b is the current buffer, then yy_init_buffer was _probably_
+ * called from yyrestart() or through yy_get_next_buffer.
+ * In that case, we don't want to reset the lineno or column.
+ */
+ if (b != YY_CURRENT_BUFFER){
+ b->yy_bs_lineno = 1;
+ b->yy_bs_column = 0;
+ }
+
+ b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
+
+ errno = oerrno;
+}
+
+/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
+ * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
+ *
+ */
+ void yy_flush_buffer (YY_BUFFER_STATE b )
+{
+ if ( ! b )
+ return;
+
+ b->yy_n_chars = 0;
+
+ /* We always need two end-of-buffer characters. The first causes
+ * a transition to the end-of-buffer state. The second causes
+ * a jam in that state.
+ */
+ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
+ b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
+
+ b->yy_buf_pos = &b->yy_ch_buf[0];
+
+ b->yy_at_bol = 1;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ if ( b == YY_CURRENT_BUFFER )
+ yy_load_buffer_state( );
+}
+
+/** Pushes the new state onto the stack. The new state becomes
+ * the current state. This function will allocate the stack
+ * if necessary.
+ * @param new_buffer The new state.
+ *
+ */
+void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
+{
+ if (new_buffer == NULL)
+ return;
+
+ yyensure_buffer_stack();
+
+ /* This block is copied from yy_switch_to_buffer. */
+ if ( YY_CURRENT_BUFFER )
+ {
+ /* Flush out information for old buffer. */
+ *(yy_c_buf_p) = (yy_hold_char);
+ YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
+ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
+ }
+
+ /* Only push if top exists. Otherwise, replace top. */
+ if (YY_CURRENT_BUFFER)
+ (yy_buffer_stack_top)++;
+ YY_CURRENT_BUFFER_LVALUE = new_buffer;
+
+ /* copied from yy_switch_to_buffer. */
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+}
+
+/** Removes and deletes the top of the stack, if present.
+ * The next element becomes the new top.
+ *
+ */
+void yypop_buffer_state (void)
+{
+ if (!YY_CURRENT_BUFFER)
+ return;
+
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ if ((yy_buffer_stack_top) > 0)
+ --(yy_buffer_stack_top);
+
+ if (YY_CURRENT_BUFFER) {
+ yy_load_buffer_state( );
+ (yy_did_buffer_switch_on_eof) = 1;
+ }
+}
+
+/* Allocates the stack if it does not exist.
+ * Guarantees space for at least one push.
+ */
+static void yyensure_buffer_stack (void)
+{
+ yy_size_t num_to_alloc;
+
+ if (!(yy_buffer_stack)) {
+
+ /* First allocation is just for 2 elements, since we don't know if this
+ * scanner will even need a stack. We use 2 instead of 1 to avoid an
+ * immediate realloc on the next call.
+ */
+ num_to_alloc = 1;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
+ (num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
+
+ (yy_buffer_stack_max) = num_to_alloc;
+ (yy_buffer_stack_top) = 0;
+ return;
+ }
+
+ if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
+
+ /* Increase the buffer to prepare for a possible push. */
+ int grow_size = 8 /* arbitrary grow size */;
+
+ num_to_alloc = (yy_buffer_stack_max) + grow_size;
+ (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
+ ((yy_buffer_stack),
+ num_to_alloc * sizeof(struct yy_buffer_state*)
+ );
+ if ( ! (yy_buffer_stack) )
+ YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
+
+ /* zero only the new slots.*/
+ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
+ (yy_buffer_stack_max) = num_to_alloc;
+ }
+}
+
+/** Setup the input buffer state to scan directly from a user-specified character buffer.
+ * @param base the character buffer
+ * @param size the size in bytes of the character buffer
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size )
+{
+ YY_BUFFER_STATE b;
+
+ if ( size < 2 ||
+ base[size-2] != YY_END_OF_BUFFER_CHAR ||
+ base[size-1] != YY_END_OF_BUFFER_CHAR )
+ /* They forgot to leave room for the EOB's. */
+ return 0;
+
+ b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) );
+ if ( ! b )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
+
+ b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */
+ b->yy_buf_pos = b->yy_ch_buf = base;
+ b->yy_is_our_buffer = 0;
+ b->yy_input_file = 0;
+ b->yy_n_chars = b->yy_buf_size;
+ b->yy_is_interactive = 0;
+ b->yy_at_bol = 1;
+ b->yy_fill_buffer = 0;
+ b->yy_buffer_status = YY_BUFFER_NEW;
+
+ yy_switch_to_buffer(b );
+
+ return b;
+}
+
+/** Setup the input buffer state to scan a string. The next call to yylex() will
+ * scan from a @e copy of @a str.
+ * @param yystr a NUL-terminated string to scan
+ *
+ * @return the newly allocated buffer state object.
+ * @note If you want to scan bytes that may contain NUL values, then use
+ * yy_scan_bytes() instead.
+ */
+YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
+{
+
+ return yy_scan_bytes(yystr,strlen(yystr) );
+}
+
+/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
+ * scan from a @e copy of @a bytes.
+ * @param yybytes the byte buffer to scan
+ * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
+ *
+ * @return the newly allocated buffer state object.
+ */
+YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, yy_size_t _yybytes_len )
+{
+ YY_BUFFER_STATE b;
+ char *buf;
+ yy_size_t n;
+ yy_size_t i;
+
+ /* Get memory for full buffer, including space for trailing EOB's. */
+ n = _yybytes_len + 2;
+ buf = (char *) yyalloc(n );
+ if ( ! buf )
+ YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
+
+ for ( i = 0; i < _yybytes_len; ++i )
+ buf[i] = yybytes[i];
+
+ buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
+
+ b = yy_scan_buffer(buf,n );
+ if ( ! b )
+ YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
+
+ /* It's okay to grow etc. this buffer, and we should throw it
+ * away when we're done.
+ */
+ b->yy_is_our_buffer = 1;
+
+ return b;
+}
+
+ static void yy_push_state (int new_state )
+{
+ if ( (yy_start_stack_ptr) >= (yy_start_stack_depth) )
+ {
+ yy_size_t new_size;
+
+ (yy_start_stack_depth) += YY_START_STACK_INCR;
+ new_size = (yy_start_stack_depth) * sizeof( int );
+
+ if ( ! (yy_start_stack) )
+ (yy_start_stack) = (int *) yyalloc(new_size );
+
+ else
+ (yy_start_stack) = (int *) yyrealloc((void *) (yy_start_stack),new_size );
+
+ if ( ! (yy_start_stack) )
+ YY_FATAL_ERROR( "out of memory expanding start-condition stack" );
+ }
+
+ (yy_start_stack)[(yy_start_stack_ptr)++] = YY_START;
+
+ BEGIN(new_state);
+}
+
+ static void yy_pop_state (void)
+{
+ if ( --(yy_start_stack_ptr) < 0 )
+ YY_FATAL_ERROR( "start-condition stack underflow" );
+
+ BEGIN((yy_start_stack)[(yy_start_stack_ptr)]);
+}
+
+#ifndef YY_EXIT_FAILURE
+#define YY_EXIT_FAILURE 2
+#endif
+
+static void yy_fatal_error (yyconst char* msg )
+{
+ (void) fprintf( stderr, "%s\n", msg );
+ exit( YY_EXIT_FAILURE );
+}
+
+/* Redefine yyless() so it works in section 3 code. */
+
+#undef yyless
+#define yyless(n) \
+ do \
+ { \
+ /* Undo effects of setting up yytext. */ \
+ int yyless_macro_arg = (n); \
+ YY_LESS_LINENO(yyless_macro_arg);\
+ yytext[yyleng] = (yy_hold_char); \
+ (yy_c_buf_p) = yytext + yyless_macro_arg; \
+ (yy_hold_char) = *(yy_c_buf_p); \
+ *(yy_c_buf_p) = '\0'; \
+ yyleng = yyless_macro_arg; \
+ } \
+ while ( 0 )
+
+/* Accessor methods (get/set functions) to struct members. */
+
+/** Get the current line number.
+ *
+ */
+int yyget_lineno (void)
+{
+
+ return yylineno;
+}
+
+/** Get the input stream.
+ *
+ */
+FILE *yyget_in (void)
+{
+ return yyin;
+}
+
+/** Get the output stream.
+ *
+ */
+FILE *yyget_out (void)
+{
+ return yyout;
+}
+
+/** Get the length of the current token.
+ *
+ */
+yy_size_t yyget_leng (void)
+{
+ return yyleng;
+}
+
+/** Get the current token.
+ *
+ */
+
+char *yyget_text (void)
+{
+ return yytext;
+}
+
+/** Set the current line number.
+ * @param line_number
+ *
+ */
+void yyset_lineno (int line_number )
+{
+
+ yylineno = line_number;
+}
+
+/** Set the input stream. This does not discard the current
+ * input buffer.
+ * @param in_str A readable stream.
+ *
+ * @see yy_switch_to_buffer
+ */
+void yyset_in (FILE * in_str )
+{
+ yyin = in_str ;
+}
+
+void yyset_out (FILE * out_str )
+{
+ yyout = out_str ;
+}
+
+int yyget_debug (void)
+{
+ return yy_flex_debug;
+}
+
+void yyset_debug (int bdebug )
+{
+ yy_flex_debug = bdebug ;
+}
+
+static int yy_init_globals (void)
+{
+ /* Initialization is the same as for the non-reentrant scanner.
+ * This function is called from yylex_destroy(), so don't allocate here.
+ */
+
+ (yy_buffer_stack) = 0;
+ (yy_buffer_stack_top) = 0;
+ (yy_buffer_stack_max) = 0;
+ (yy_c_buf_p) = (char *) 0;
+ (yy_init) = 0;
+ (yy_start) = 0;
+
+ (yy_start_stack_ptr) = 0;
+ (yy_start_stack_depth) = 0;
+ (yy_start_stack) = NULL;
+
+/* Defined in main.c */
+#ifdef YY_STDINIT
+ yyin = stdin;
+ yyout = stdout;
+#else
+ yyin = (FILE *) 0;
+ yyout = (FILE *) 0;
+#endif
+
+ /* For future reference: Set errno on error, since we are called by
+ * yylex_init()
+ */
+ return 0;
+}
+
+/* yylex_destroy is for both reentrant and non-reentrant scanners. */
+int yylex_destroy (void)
+{
+
+ /* Pop the buffer stack, destroying each element. */
+ while(YY_CURRENT_BUFFER){
+ yy_delete_buffer(YY_CURRENT_BUFFER );
+ YY_CURRENT_BUFFER_LVALUE = NULL;
+ yypop_buffer_state();
+ }
+
+ /* Destroy the stack itself. */
+ yyfree((yy_buffer_stack) );
+ (yy_buffer_stack) = NULL;
+
+ /* Destroy the start condition stack. */
+ yyfree((yy_start_stack) );
+ (yy_start_stack) = NULL;
+
+ /* Reset the globals. This is important in a non-reentrant scanner so the next time
+ * yylex() is called, initialization will occur. */
+ yy_init_globals( );
+
+ return 0;
+}
+
+/*
+ * Internal utility routines.
+ */
+
+#ifndef yytext_ptr
+static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
+{
+ register int i;
+ for ( i = 0; i < n; ++i )
+ s1[i] = s2[i];
+}
+#endif
+
+#ifdef YY_NEED_STRLEN
+static int yy_flex_strlen (yyconst char * s )
+{
+ register int n;
+ for ( n = 0; s[n]; ++n )
+ ;
+
+ return n;
+}
+#endif
+
+void *yyalloc (yy_size_t size )
+{
+ return (void *) malloc( size );
+}
+
+void *yyrealloc (void * ptr, yy_size_t size )
+{
+ /* The cast to (char *) in the following accommodates both
+ * implementations that use char* generic pointers, and those
+ * that use void* generic pointers. It works with the latter
+ * because both ANSI C and C++ allow castless assignment from
+ * any pointer type to void*, and deal with argument conversions
+ * as though doing an assignment.
+ */
+ return (void *) realloc( (char *) ptr, size );
+}
+
+void yyfree (void * ptr )
+{
+ free( (char *) ptr ); /* see yyrealloc() for (char *) cast */
+}
+
+#define YYTABLES_NAME "yytables"
+
+#line 137 "bindlexer.l"
+
+
+
--- /dev/null
+%{
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define YY_NO_INPUT 1
+#define YYSTYPE char *
+
+#include "bindparser.h"
+
+int linenumber;
+#define MAX_INCLUDE_DEPTH 10
+YY_BUFFER_STATE include_stack[MAX_INCLUDE_DEPTH];
+int include_stack_ln[MAX_INCLUDE_DEPTH];
+char *include_stack_name[MAX_INCLUDE_DEPTH];
+char *current_filename;
+char *original_filename;
+int include_stack_ptr = 0;
+extern const char *bind_directory;
+
+%}
+
+%x comment
+%x incl
+%x quoted
+%option stack
+%option nounput
+%option noyy_top_state
+%option noinput
+
+%%
+
+
+"/*" BEGIN(comment);
+<comment>[^*\n]* /* eat anything that's not a '*' */
+<comment>"*"+[^*/\n]* /* eat up '*'s not followed by '/'s */
+<comment>\n ++linenumber;
+<comment>"*"+"/" BEGIN(INITIAL);
+
+include BEGIN(incl);
+<incl>[ \t;]* /* eat the whitespace */
+<incl>\"[^ \t\n";]+\"; { /* got the include file name */
+ char filename[1024];
+ if ( include_stack_ptr >= MAX_INCLUDE_DEPTH )
+ {
+ fprintf( stderr, "Includes nested too deeply\n" );
+ exit( 1 );
+ }
+
+ if (strlen(yytext) <= 2) {
+ fprintf( stderr, "Empty include directive\n" );
+ exit( 1 );
+ }
+
+ yytext[strlen(yytext)-2]=0;
+
+ include_stack[include_stack_ptr]=YY_CURRENT_BUFFER;
+ include_stack_name[include_stack_ptr]=current_filename=strdup(yytext+1);
+ include_stack_ln[include_stack_ptr++]=linenumber;
+ linenumber=1;
+
+ if(*(yytext+1)=='/') {
+ if (strlen(yytext+1) >= sizeof(filename)) {
+ fprintf( stderr, "Filename '%s' is too long\n",yytext+1);
+ exit( 1 );
+ }
+ strcpy(filename,yytext+1);
+ }
+ else {
+ size_t bind_directory_len = strlen(bind_directory);
+ if (bind_directory_len >= sizeof(filename) ||
+ strlen(yytext+1) + 2 >= sizeof(filename) - bind_directory_len) {
+ fprintf( stderr, "Filename '%s' is too long\n",yytext+1);
+ exit( 1 );
+ }
+ strcpy(filename,bind_directory);
+ strcat(filename,"/");
+ strcat(filename,yytext+1);
+ }
+ filename[sizeof(filename)-1]='\0';
+
+ if (!(yyin=fopen(filename,"r"))) {
+ fprintf( stderr, "Unable to open '%s': %s\n",filename,strerror(errno));
+ exit( 1 );
+ }
+
+ BEGIN(INITIAL);
+ yy_switch_to_buffer(yy_create_buffer(yyin,YY_BUF_SIZE));
+
+ }
+
+
+<<EOF>> {
+ if ( --include_stack_ptr < 0 )
+ {
+ yyterminate();
+ }
+
+ else
+ {
+ fclose(yyin);
+ yy_delete_buffer(YY_CURRENT_BUFFER);
+ yy_switch_to_buffer(include_stack[include_stack_ptr]);
+ linenumber=include_stack_ln[include_stack_ptr];
+ free(include_stack_name[include_stack_ptr]);
+ if(include_stack_ptr)
+ current_filename=include_stack_name[include_stack_ptr-1];
+ else
+ current_filename=original_filename;
+ }
+ }
+
+
+
+
+zone return ZONETOK;
+
+file return FILETOK;
+options return OPTIONSTOK;
+also-notify return ALSONOTIFYTOK;
+acl return ACLTOK;
+logging return LOGGINGTOK;
+directory return DIRECTORYTOK;
+masters return MASTERTOK;
+type return TYPETOK;
+\" yy_push_state(quoted);
+<quoted>[^\"]* yylval=strdup(yytext); return QUOTEDWORD;
+<quoted>\" yy_pop_state();
+[^\" \t\n{};]* yylval=strdup(yytext);return AWORD;
+\{ return OBRACE;
+\} return EBRACE;
+; return SEMICOLON;
+\n linenumber++;
+[ \t]* ;
+\/\/.*$ ;
+\#.*$ ;
+%%
--- /dev/null
+/* A Bison parser, made by GNU Bison 3.0.2. */
+
+/* Bison implementation for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+/* C LALR(1) parser skeleton written by Richard Stallman, by
+ simplifying the original so-called "semantic" parser. */
+
+/* All symbols defined below should begin with yy or YY, to avoid
+ infringing on user name space. This should be done even for local
+ variables, as they might otherwise be expanded by user macros.
+ There are some unavoidable exceptions within include files to
+ define necessary library symbols; they are noted "INFRINGES ON
+ USER NAME SPACE" below. */
+
+/* Identify Bison output. */
+#define YYBISON 1
+
+/* Bison version. */
+#define YYBISON_VERSION "3.0.2"
+
+/* Skeleton name. */
+#define YYSKELETON_NAME "yacc.c"
+
+/* Pure parsers. */
+#define YYPURE 0
+
+/* Push parsers. */
+#define YYPUSH 0
+
+/* Pull parsers. */
+#define YYPULL 1
+
+
+
+
+/* Copy the first part of user declarations. */
+#line 1 "bindparser.yy" /* yacc.c:339 */
+
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string>
+#include <iostream>
+#include <utility>
+#include <errno.h>
+#include "misc.hh"
+#include "pdnsexception.hh"
+#include "namespaces.hh"
+#define YYDEBUG 1
+extern int yydebug;
+#include "bindparserclasses.hh"
+
+#define YYSTYPE char *
+
+extern "C"
+{
+ int yyparse(void);
+ int yylex(void);
+ void yyrestart(FILE *);
+ int yywrap()
+ {
+ return 1;
+ }
+}
+
+
+extern int yydebug;
+const char *bind_directory;
+extern int linenumber;
+static void yyerror(const char *str)
+{
+ extern char *current_filename;
+ throw PDNSException("Error in bind configuration '"+string(current_filename)+"' on line "+itoa(linenumber)+": "+str);
+}
+
+extern FILE *yyin;
+static BindParser *parent;
+BindDomainInfo s_di;
+
+void BindParser::parse(const string &fname)
+{
+ yydebug=0;
+ yyin=fopen(fname.c_str(),"r");
+ yyrestart(yyin);
+ if(!yyin)
+ throw PDNSException("Unable to open '"+fname+"': "+strerror(errno));
+
+ linenumber=1;
+ parent=this;
+ extern char *current_filename;
+ extern char *original_filename;
+
+ current_filename=original_filename=(char*)fname.c_str();
+
+ yyparse();
+
+// cerr<<"Need to parse "<<d_zonedomains.size()<<" zone statements"<<endl;
+}
+
+void BindParser::setDirectory(const string &dir)
+{
+ d_dir=dir;
+ bind_directory=d_dir.c_str();
+}
+
+void BindParser::addAlsoNotify(const string & host)
+{
+ alsoNotify.insert(host);
+}
+
+const string &BindParser::getDirectory()
+{
+ return d_dir;
+}
+
+const vector<BindDomainInfo>& BindParser::getDomains()
+{
+ return d_zonedomains;
+}
+
+void BindParser::setVerbose(bool verbose)
+{
+ d_verbose=verbose;
+}
+
+void BindParser::commit(BindDomainInfo DI)
+{
+ if(DI.filename[0]!='/')
+ DI.filename=d_dir+"/"+DI.filename;
+
+ if(d_verbose)
+ cerr<<"Domain "<<DI.name.toStringNoDot()<<" lives in file '"<<DI.filename<<"'"<<endl;
+
+ d_zonedomains.push_back(DI);
+}
+
+
+#line 168 "bindparser.cc" /* yacc.c:339 */
+
+# ifndef YY_NULLPTR
+# if defined __cplusplus && 201103L <= __cplusplus
+# define YY_NULLPTR nullptr
+# else
+# define YY_NULLPTR 0
+# endif
+# endif
+
+/* Enabling verbose error messages. */
+#ifdef YYERROR_VERBOSE
+# undef YYERROR_VERBOSE
+# define YYERROR_VERBOSE 1
+#else
+# define YYERROR_VERBOSE 0
+#endif
+
+/* In a future release of Bison, this section will be replaced
+ by #include "y.tab.h". */
+#ifndef YY_YY_BINDPARSER_HH_INCLUDED
+# define YY_YY_BINDPARSER_HH_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ AWORD = 258,
+ QUOTEDWORD = 259,
+ OBRACE = 260,
+ EBRACE = 261,
+ SEMICOLON = 262,
+ ZONETOK = 263,
+ FILETOK = 264,
+ OPTIONSTOK = 265,
+ DIRECTORYTOK = 266,
+ ACLTOK = 267,
+ LOGGINGTOK = 268,
+ CLASSTOK = 269,
+ TYPETOK = 270,
+ MASTERTOK = 271,
+ ALSONOTIFYTOK = 272
+ };
+#endif
+/* Tokens. */
+#define AWORD 258
+#define QUOTEDWORD 259
+#define OBRACE 260
+#define EBRACE 261
+#define SEMICOLON 262
+#define ZONETOK 263
+#define FILETOK 264
+#define OPTIONSTOK 265
+#define DIRECTORYTOK 266
+#define ACLTOK 267
+#define LOGGINGTOK 268
+#define CLASSTOK 269
+#define TYPETOK 270
+#define MASTERTOK 271
+#define ALSONOTIFYTOK 272
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+#endif /* !YY_YY_BINDPARSER_HH_INCLUDED */
+
+/* Copy the second part of user declarations. */
+
+#line 253 "bindparser.cc" /* yacc.c:358 */
+
+#ifdef short
+# undef short
+#endif
+
+#ifdef YYTYPE_UINT8
+typedef YYTYPE_UINT8 yytype_uint8;
+#else
+typedef unsigned char yytype_uint8;
+#endif
+
+#ifdef YYTYPE_INT8
+typedef YYTYPE_INT8 yytype_int8;
+#else
+typedef signed char yytype_int8;
+#endif
+
+#ifdef YYTYPE_UINT16
+typedef YYTYPE_UINT16 yytype_uint16;
+#else
+typedef unsigned short int yytype_uint16;
+#endif
+
+#ifdef YYTYPE_INT16
+typedef YYTYPE_INT16 yytype_int16;
+#else
+typedef short int yytype_int16;
+#endif
+
+#ifndef YYSIZE_T
+# ifdef __SIZE_TYPE__
+# define YYSIZE_T __SIZE_TYPE__
+# elif defined size_t
+# define YYSIZE_T size_t
+# elif ! defined YYSIZE_T
+# include <stddef.h> /* INFRINGES ON USER NAME SPACE */
+# define YYSIZE_T size_t
+# else
+# define YYSIZE_T unsigned int
+# endif
+#endif
+
+#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
+
+#ifndef YY_
+# if defined YYENABLE_NLS && YYENABLE_NLS
+# if ENABLE_NLS
+# include <libintl.h> /* INFRINGES ON USER NAME SPACE */
+# define YY_(Msgid) dgettext ("bison-runtime", Msgid)
+# endif
+# endif
+# ifndef YY_
+# define YY_(Msgid) Msgid
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE
+# if (defined __GNUC__ \
+ && (2 < __GNUC__ || (__GNUC__ == 2 && 96 <= __GNUC_MINOR__))) \
+ || defined __SUNPRO_C && 0x5110 <= __SUNPRO_C
+# define YY_ATTRIBUTE(Spec) __attribute__(Spec)
+# else
+# define YY_ATTRIBUTE(Spec) /* empty */
+# endif
+#endif
+
+#ifndef YY_ATTRIBUTE_PURE
+# define YY_ATTRIBUTE_PURE YY_ATTRIBUTE ((__pure__))
+#endif
+
+#ifndef YY_ATTRIBUTE_UNUSED
+# define YY_ATTRIBUTE_UNUSED YY_ATTRIBUTE ((__unused__))
+#endif
+
+#if !defined _Noreturn \
+ && (!defined __STDC_VERSION__ || __STDC_VERSION__ < 201112)
+# if defined _MSC_VER && 1200 <= _MSC_VER
+# define _Noreturn __declspec (noreturn)
+# else
+# define _Noreturn YY_ATTRIBUTE ((__noreturn__))
+# endif
+#endif
+
+/* Suppress unused-variable warnings by "using" E. */
+#if ! defined lint || defined __GNUC__
+# define YYUSE(E) ((void) (E))
+#else
+# define YYUSE(E) /* empty */
+#endif
+
+#if defined __GNUC__ && 407 <= __GNUC__ * 100 + __GNUC_MINOR__
+/* Suppress an incorrect diagnostic about yylval being uninitialized. */
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN \
+ _Pragma ("GCC diagnostic push") \
+ _Pragma ("GCC diagnostic ignored \"-Wuninitialized\"")\
+ _Pragma ("GCC diagnostic ignored \"-Wmaybe-uninitialized\"")
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END \
+ _Pragma ("GCC diagnostic pop")
+#else
+# define YY_INITIAL_VALUE(Value) Value
+#endif
+#ifndef YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+# define YY_IGNORE_MAYBE_UNINITIALIZED_END
+#endif
+#ifndef YY_INITIAL_VALUE
+# define YY_INITIAL_VALUE(Value) /* Nothing. */
+#endif
+
+
+#if ! defined yyoverflow || YYERROR_VERBOSE
+
+/* The parser invokes alloca or malloc; define the necessary symbols. */
+
+# ifdef YYSTACK_USE_ALLOCA
+# if YYSTACK_USE_ALLOCA
+# ifdef __GNUC__
+# define YYSTACK_ALLOC __builtin_alloca
+# elif defined __BUILTIN_VA_ARG_INCR
+# include <alloca.h> /* INFRINGES ON USER NAME SPACE */
+# elif defined _AIX
+# define YYSTACK_ALLOC __alloca
+# elif defined _MSC_VER
+# include <malloc.h> /* INFRINGES ON USER NAME SPACE */
+# define alloca _alloca
+# else
+# define YYSTACK_ALLOC alloca
+# if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+ /* Use EXIT_SUCCESS as a witness for stdlib.h. */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# endif
+# endif
+# endif
+
+# ifdef YYSTACK_ALLOC
+ /* Pacify GCC's 'empty if-body' warning. */
+# define YYSTACK_FREE(Ptr) do { /* empty */; } while (0)
+# ifndef YYSTACK_ALLOC_MAXIMUM
+ /* The OS might guarantee only one guard page at the bottom of the stack,
+ and a page size can be as small as 4096 bytes. So we cannot safely
+ invoke alloca (N) if N exceeds 4096. Use a slightly smaller number
+ to allow for a few compiler-allocated temporary stack slots. */
+# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
+# endif
+# else
+# define YYSTACK_ALLOC YYMALLOC
+# define YYSTACK_FREE YYFREE
+# ifndef YYSTACK_ALLOC_MAXIMUM
+# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
+# endif
+# if (defined __cplusplus && ! defined EXIT_SUCCESS \
+ && ! ((defined YYMALLOC || defined malloc) \
+ && (defined YYFREE || defined free)))
+# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
+# ifndef EXIT_SUCCESS
+# define EXIT_SUCCESS 0
+# endif
+# endif
+# ifndef YYMALLOC
+# define YYMALLOC malloc
+# if ! defined malloc && ! defined EXIT_SUCCESS
+void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# ifndef YYFREE
+# define YYFREE free
+# if ! defined free && ! defined EXIT_SUCCESS
+void free (void *); /* INFRINGES ON USER NAME SPACE */
+# endif
+# endif
+# endif
+#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
+
+
+#if (! defined yyoverflow \
+ && (! defined __cplusplus \
+ || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
+
+/* A type that is properly aligned for any stack member. */
+union yyalloc
+{
+ yytype_int16 yyss_alloc;
+ YYSTYPE yyvs_alloc;
+};
+
+/* The size of the maximum gap between one aligned stack and the next. */
+# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
+
+/* The size of an array large to enough to hold all stacks, each with
+ N elements. */
+# define YYSTACK_BYTES(N) \
+ ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
+ + YYSTACK_GAP_MAXIMUM)
+
+# define YYCOPY_NEEDED 1
+
+/* Relocate STACK from its old location to the new one. The
+ local variables YYSIZE and YYSTACKSIZE give the old and new number of
+ elements in the stack, and YYPTR gives the new location of the
+ stack. Advance YYPTR to a properly aligned location for the next
+ stack. */
+# define YYSTACK_RELOCATE(Stack_alloc, Stack) \
+ do \
+ { \
+ YYSIZE_T yynewbytes; \
+ YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \
+ Stack = &yyptr->Stack_alloc; \
+ yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
+ yyptr += yynewbytes / sizeof (*yyptr); \
+ } \
+ while (0)
+
+#endif
+
+#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
+/* Copy COUNT objects from SRC to DST. The source and destination do
+ not overlap. */
+# ifndef YYCOPY
+# if defined __GNUC__ && 1 < __GNUC__
+# define YYCOPY(Dst, Src, Count) \
+ __builtin_memcpy (Dst, Src, (Count) * sizeof (*(Src)))
+# else
+# define YYCOPY(Dst, Src, Count) \
+ do \
+ { \
+ YYSIZE_T yyi; \
+ for (yyi = 0; yyi < (Count); yyi++) \
+ (Dst)[yyi] = (Src)[yyi]; \
+ } \
+ while (0)
+# endif
+# endif
+#endif /* !YYCOPY_NEEDED */
+
+/* YYFINAL -- State number of the termination state. */
+#define YYFINAL 2
+/* YYLAST -- Last index in YYTABLE. */
+#define YYLAST 72
+
+/* YYNTOKENS -- Number of terminals. */
+#define YYNTOKENS 18
+/* YYNNTS -- Number of nonterminals. */
+#define YYNNTS 33
+/* YYNRULES -- Number of rules. */
+#define YYNRULES 58
+/* YYNSTATES -- Number of states. */
+#define YYNSTATES 93
+
+/* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned
+ by yylex, with out-of-bounds checking. */
+#define YYUNDEFTOK 2
+#define YYMAXUTOK 272
+
+#define YYTRANSLATE(YYX) \
+ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
+
+/* YYTRANSLATE[TOKEN-NUM] -- Symbol number corresponding to TOKEN-NUM
+ as returned by yylex, without out-of-bounds checking. */
+static const yytype_uint8 yytranslate[] =
+{
+ 0, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
+ 15, 16, 17
+};
+
+#if YYDEBUG
+ /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */
+static const yytype_uint16 yyrline[] =
+{
+ 0, 108, 108, 110, 113, 113, 113, 113, 116, 118,
+ 122, 126, 134, 145, 147, 152, 152, 155, 158, 160,
+ 164, 167, 169, 172, 172, 175, 175, 178, 185, 188,
+ 190, 193, 199, 201, 204, 204, 204, 207, 211, 214,
+ 216, 222, 222, 222, 226, 226, 226, 229, 232, 235,
+ 237, 240, 247, 249, 252, 260, 269, 278, 284
+};
+#endif
+
+#if YYDEBUG || YYERROR_VERBOSE || 0
+/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
+ First, the terminals, then, starting at YYNTOKENS, nonterminals. */
+static const char *const yytname[] =
+{
+ "$end", "error", "$undefined", "AWORD", "QUOTEDWORD", "OBRACE",
+ "EBRACE", "SEMICOLON", "ZONETOK", "FILETOK", "OPTIONSTOK",
+ "DIRECTORYTOK", "ACLTOK", "LOGGINGTOK", "CLASSTOK", "TYPETOK",
+ "MASTERTOK", "ALSONOTIFYTOK", "$accept", "root_commands", "root_command",
+ "commands", "command", "global_zone_command", "global_options_command",
+ "acl_command", "acl_block", "acls", "acl", "options_commands",
+ "options_command", "options_directory_command", "also_notify_command",
+ "also_notify_list", "also_notify", "terms", "term", "block",
+ "zone_block", "zone_commands", "zone_command", "zone_masters_command",
+ "zone_also_notify_command", "zone_also_notify_list", "zone_also_notify",
+ "masters", "master", "zone_file_command", "zone_type_command",
+ "quotedname", "filename", YY_NULLPTR
+};
+#endif
+
+# ifdef YYPRINT
+/* YYTOKNUM[NUM] -- (External) token number corresponding to the
+ (internal) symbol number NUM (which must be that of a token). */
+static const yytype_uint16 yytoknum[] =
+{
+ 0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
+ 265, 266, 267, 268, 269, 270, 271, 272
+};
+# endif
+
+#define YYPACT_NINF -31
+
+#define yypact_value_is_default(Yystate) \
+ (!!((Yystate) == (-31)))
+
+#define YYTABLE_NINF -22
+
+#define yytable_value_is_error(Yytable_value) \
+ 0
+
+ /* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
+ STATE-NUM. */
+static const yytype_int8 yypact[] =
+{
+ -31, 2, -31, 5, 5, 11, 5, 32, 24, 34,
+ 35, 37, -3, -31, -31, -31, -31, -31, -31, 23,
+ -31, -31, -31, -31, 18, -31, 28, -31, -31, 38,
+ 38, 28, -31, -31, 41, -31, -31, -31, -31, -31,
+ -31, 42, -31, -31, -31, -31, 40, 43, 45, -31,
+ -31, 46, 0, -31, 47, 44, 48, -31, 16, -31,
+ 28, -31, 50, 51, -31, -31, -31, 52, -31, 41,
+ -31, 53, -31, 56, -31, -31, 55, -31, -31, -31,
+ 45, -31, -31, -31, 60, -31, -31, -31, 58, 59,
+ -31, 60, -31
+};
+
+ /* YYDEFACT[STATE-NUM] -- Default reduction number in state STATE-NUM.
+ Performed when YYTABLE does not specify something else to do. Zero
+ means the default is an error. */
+static const yytype_uint8 yydefact[] =
+{
+ 2, 32, 1, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 4, 6, 7, 5, 25, 26, 10,
+ 46, 44, 45, 57, 0, 55, 32, 27, 58, 0,
+ 0, 32, 56, 52, 29, 3, 34, 8, 33, 35,
+ 36, 0, 39, 11, 23, 24, 0, 0, 18, 15,
+ 16, 0, 0, 31, 0, 0, 32, 12, 32, 13,
+ 32, 20, 0, 0, 14, 54, 47, 0, 28, 29,
+ 37, 0, 38, 0, 41, 42, 0, 43, 22, 17,
+ 18, 53, 30, 9, 49, 40, 19, 51, 0, 0,
+ 48, 49, 50
+};
+
+ /* YYPGOTO[NTERM-NUM]. */
+static const yytype_int8 yypgoto[] =
+{
+ -31, -31, -31, -31, -1, -9, 64, -31, 39, -13,
+ -31, -30, -31, -31, -31, 3, -31, -31, -31, -31,
+ 27, -31, -31, -31, -31, -21, -31, -31, -31, -31,
+ -31, 1, -31
+};
+
+ /* YYDEFGOTO[NTERM-NUM]. */
+static const yytype_int8 yydefgoto[] =
+{
+ -1, 1, 12, 56, 44, 14, 45, 16, 49, 62,
+ 63, 46, 47, 17, 18, 54, 55, 19, 38, 39,
+ 43, 58, 76, 20, 77, 88, 89, 52, 67, 21,
+ 22, 24, 30
+};
+
+ /* YYTABLE[YYPACT[STATE-NUM]] -- What to do in state STATE-NUM. If
+ positive, shift that token. If negative, reduce the rule whose
+ number is the opposite. If YYTABLE_NINF, syntax error. */
+static const yytype_int8 yytable[] =
+{
+ 13, 51, 2, 65, 35, 25, 66, 27, 29, 23,
+ 3, 4, 5, 6, 7, 8, 26, 9, 10, 11,
+ 40, 41, 72, 42, 3, 4, 36, 23, 37, 31,
+ 78, 9, 10, 73, -21, 28, 23, 32, 5, 6,
+ 33, 8, 34, 48, 53, 11, 59, 42, 61, 75,
+ 60, 69, 64, 68, 70, 71, 79, 74, 80, 81,
+ 83, 84, 85, 87, 90, 15, 91, 86, 57, 50,
+ 92, 0, 82
+};
+
+static const yytype_int8 yycheck[] =
+{
+ 1, 31, 0, 3, 7, 4, 6, 6, 7, 4,
+ 8, 9, 10, 11, 12, 13, 5, 15, 16, 17,
+ 19, 3, 6, 5, 8, 9, 3, 4, 5, 5,
+ 60, 15, 16, 17, 6, 3, 4, 3, 10, 11,
+ 5, 13, 5, 5, 3, 17, 6, 5, 3, 58,
+ 7, 7, 6, 6, 6, 56, 6, 58, 7, 7,
+ 7, 5, 7, 3, 6, 1, 7, 80, 41, 30,
+ 91, -1, 69
+};
+
+ /* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
+ symbol of state STATE-NUM. */
+static const yytype_uint8 yystos[] =
+{
+ 0, 19, 0, 8, 9, 10, 11, 12, 13, 15,
+ 16, 17, 20, 22, 23, 24, 25, 31, 32, 35,
+ 41, 47, 48, 4, 49, 49, 5, 49, 3, 49,
+ 50, 5, 3, 5, 5, 7, 3, 5, 36, 37,
+ 49, 3, 5, 38, 22, 24, 29, 30, 5, 26,
+ 26, 29, 45, 3, 33, 34, 21, 38, 39, 6,
+ 7, 3, 27, 28, 6, 3, 6, 46, 6, 7,
+ 6, 22, 6, 17, 22, 23, 40, 42, 29, 6,
+ 7, 7, 33, 7, 5, 7, 27, 3, 43, 44,
+ 6, 7, 43
+};
+
+ /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */
+static const yytype_uint8 yyr1[] =
+{
+ 0, 18, 19, 19, 20, 20, 20, 20, 21, 21,
+ 22, 23, 23, 24, 24, 25, 25, 26, 27, 27,
+ 28, 29, 29, 30, 30, 24, 24, 31, 32, 33,
+ 33, 34, 35, 35, 36, 36, 36, 37, 38, 39,
+ 39, 40, 40, 40, 23, 23, 23, 41, 42, 43,
+ 43, 44, 45, 45, 46, 47, 48, 49, 50
+};
+
+ /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */
+static const yytype_uint8 yyr2[] =
+{
+ 0, 2, 0, 3, 1, 1, 1, 1, 0, 3,
+ 1, 3, 4, 4, 4, 3, 3, 3, 0, 3,
+ 1, 0, 3, 1, 1, 1, 1, 2, 4, 0,
+ 3, 1, 0, 2, 1, 1, 1, 3, 3, 0,
+ 3, 1, 1, 1, 1, 1, 1, 4, 4, 0,
+ 3, 1, 0, 3, 1, 2, 2, 1, 1
+};
+
+
+#define yyerrok (yyerrstatus = 0)
+#define yyclearin (yychar = YYEMPTY)
+#define YYEMPTY (-2)
+#define YYEOF 0
+
+#define YYACCEPT goto yyacceptlab
+#define YYABORT goto yyabortlab
+#define YYERROR goto yyerrorlab
+
+
+#define YYRECOVERING() (!!yyerrstatus)
+
+#define YYBACKUP(Token, Value) \
+do \
+ if (yychar == YYEMPTY) \
+ { \
+ yychar = (Token); \
+ yylval = (Value); \
+ YYPOPSTACK (yylen); \
+ yystate = *yyssp; \
+ goto yybackup; \
+ } \
+ else \
+ { \
+ yyerror (YY_("syntax error: cannot back up")); \
+ YYERROR; \
+ } \
+while (0)
+
+/* Error token number */
+#define YYTERROR 1
+#define YYERRCODE 256
+
+
+
+/* Enable debugging if requested. */
+#if YYDEBUG
+
+# ifndef YYFPRINTF
+# include <stdio.h> /* INFRINGES ON USER NAME SPACE */
+# define YYFPRINTF fprintf
+# endif
+
+# define YYDPRINTF(Args) \
+do { \
+ if (yydebug) \
+ YYFPRINTF Args; \
+} while (0)
+
+/* This macro is provided for backward compatibility. */
+#ifndef YY_LOCATION_PRINT
+# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
+#endif
+
+
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \
+do { \
+ if (yydebug) \
+ { \
+ YYFPRINTF (stderr, "%s ", Title); \
+ yy_symbol_print (stderr, \
+ Type, Value); \
+ YYFPRINTF (stderr, "\n"); \
+ } \
+} while (0)
+
+
+/*----------------------------------------.
+| Print this symbol's value on YYOUTPUT. |
+`----------------------------------------*/
+
+static void
+yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+ FILE *yyo = yyoutput;
+ YYUSE (yyo);
+ if (!yyvaluep)
+ return;
+# ifdef YYPRINT
+ if (yytype < YYNTOKENS)
+ YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
+# endif
+ YYUSE (yytype);
+}
+
+
+/*--------------------------------.
+| Print this symbol on YYOUTPUT. |
+`--------------------------------*/
+
+static void
+yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
+{
+ YYFPRINTF (yyoutput, "%s %s (",
+ yytype < YYNTOKENS ? "token" : "nterm", yytname[yytype]);
+
+ yy_symbol_value_print (yyoutput, yytype, yyvaluep);
+ YYFPRINTF (yyoutput, ")");
+}
+
+/*------------------------------------------------------------------.
+| yy_stack_print -- Print the state stack from its BOTTOM up to its |
+| TOP (included). |
+`------------------------------------------------------------------*/
+
+static void
+yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
+{
+ YYFPRINTF (stderr, "Stack now");
+ for (; yybottom <= yytop; yybottom++)
+ {
+ int yybot = *yybottom;
+ YYFPRINTF (stderr, " %d", yybot);
+ }
+ YYFPRINTF (stderr, "\n");
+}
+
+# define YY_STACK_PRINT(Bottom, Top) \
+do { \
+ if (yydebug) \
+ yy_stack_print ((Bottom), (Top)); \
+} while (0)
+
+
+/*------------------------------------------------.
+| Report that the YYRULE is going to be reduced. |
+`------------------------------------------------*/
+
+static void
+yy_reduce_print (yytype_int16 *yyssp, YYSTYPE *yyvsp, int yyrule)
+{
+ unsigned long int yylno = yyrline[yyrule];
+ int yynrhs = yyr2[yyrule];
+ int yyi;
+ YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
+ yyrule - 1, yylno);
+ /* The symbols being reduced. */
+ for (yyi = 0; yyi < yynrhs; yyi++)
+ {
+ YYFPRINTF (stderr, " $%d = ", yyi + 1);
+ yy_symbol_print (stderr,
+ yystos[yyssp[yyi + 1 - yynrhs]],
+ &(yyvsp[(yyi + 1) - (yynrhs)])
+ );
+ YYFPRINTF (stderr, "\n");
+ }
+}
+
+# define YY_REDUCE_PRINT(Rule) \
+do { \
+ if (yydebug) \
+ yy_reduce_print (yyssp, yyvsp, Rule); \
+} while (0)
+
+/* Nonzero means print parse trace. It is left uninitialized so that
+ multiple parsers can coexist. */
+int yydebug;
+#else /* !YYDEBUG */
+# define YYDPRINTF(Args)
+# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
+# define YY_STACK_PRINT(Bottom, Top)
+# define YY_REDUCE_PRINT(Rule)
+#endif /* !YYDEBUG */
+
+
+/* YYINITDEPTH -- initial size of the parser's stacks. */
+#ifndef YYINITDEPTH
+# define YYINITDEPTH 200
+#endif
+
+/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
+ if the built-in stack extension method is used).
+
+ Do not make this value too large; the results are undefined if
+ YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
+ evaluated with infinite-precision integer arithmetic. */
+
+#ifndef YYMAXDEPTH
+# define YYMAXDEPTH 10000
+#endif
+
+
+#if YYERROR_VERBOSE
+
+# ifndef yystrlen
+# if defined __GLIBC__ && defined _STRING_H
+# define yystrlen strlen
+# else
+/* Return the length of YYSTR. */
+static YYSIZE_T
+yystrlen (const char *yystr)
+{
+ YYSIZE_T yylen;
+ for (yylen = 0; yystr[yylen]; yylen++)
+ continue;
+ return yylen;
+}
+# endif
+# endif
+
+# ifndef yystpcpy
+# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
+# define yystpcpy stpcpy
+# else
+/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
+ YYDEST. */
+static char *
+yystpcpy (char *yydest, const char *yysrc)
+{
+ char *yyd = yydest;
+ const char *yys = yysrc;
+
+ while ((*yyd++ = *yys++) != '\0')
+ continue;
+
+ return yyd - 1;
+}
+# endif
+# endif
+
+# ifndef yytnamerr
+/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
+ quotes and backslashes, so that it's suitable for yyerror. The
+ heuristic is that double-quoting is unnecessary unless the string
+ contains an apostrophe, a comma, or backslash (other than
+ backslash-backslash). YYSTR is taken from yytname. If YYRES is
+ null, do not copy; instead, return the length of what the result
+ would have been. */
+static YYSIZE_T
+yytnamerr (char *yyres, const char *yystr)
+{
+ if (*yystr == '"')
+ {
+ YYSIZE_T yyn = 0;
+ char const *yyp = yystr;
+
+ for (;;)
+ switch (*++yyp)
+ {
+ case '\'':
+ case ',':
+ goto do_not_strip_quotes;
+
+ case '\\':
+ if (*++yyp != '\\')
+ goto do_not_strip_quotes;
+ /* Fall through. */
+ default:
+ if (yyres)
+ yyres[yyn] = *yyp;
+ yyn++;
+ break;
+
+ case '"':
+ if (yyres)
+ yyres[yyn] = '\0';
+ return yyn;
+ }
+ do_not_strip_quotes: ;
+ }
+
+ if (! yyres)
+ return yystrlen (yystr);
+
+ return yystpcpy (yyres, yystr) - yyres;
+}
+# endif
+
+/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
+ about the unexpected token YYTOKEN for the state stack whose top is
+ YYSSP.
+
+ Return 0 if *YYMSG was successfully written. Return 1 if *YYMSG is
+ not large enough to hold the message. In that case, also set
+ *YYMSG_ALLOC to the required number of bytes. Return 2 if the
+ required number of bytes is too large to store. */
+static int
+yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
+ yytype_int16 *yyssp, int yytoken)
+{
+ YYSIZE_T yysize0 = yytnamerr (YY_NULLPTR, yytname[yytoken]);
+ YYSIZE_T yysize = yysize0;
+ enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
+ /* Internationalized format string. */
+ const char *yyformat = YY_NULLPTR;
+ /* Arguments of yyformat. */
+ char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
+ /* Number of reported tokens (one for the "unexpected", one per
+ "expected"). */
+ int yycount = 0;
+
+ /* There are many possibilities here to consider:
+ - If this state is a consistent state with a default action, then
+ the only way this function was invoked is if the default action
+ is an error action. In that case, don't check for expected
+ tokens because there are none.
+ - The only way there can be no lookahead present (in yychar) is if
+ this state is a consistent state with a default action. Thus,
+ detecting the absence of a lookahead is sufficient to determine
+ that there is no unexpected or expected token to report. In that
+ case, just report a simple "syntax error".
+ - Don't assume there isn't a lookahead just because this state is a
+ consistent state with a default action. There might have been a
+ previous inconsistent state, consistent state with a non-default
+ action, or user semantic action that manipulated yychar.
+ - Of course, the expected token list depends on states to have
+ correct lookahead information, and it depends on the parser not
+ to perform extra reductions after fetching a lookahead from the
+ scanner and before detecting a syntax error. Thus, state merging
+ (from LALR or IELR) and default reductions corrupt the expected
+ token list. However, the list is correct for canonical LR with
+ one exception: it will still contain any token that will not be
+ accepted due to an error action in a later state.
+ */
+ if (yytoken != YYEMPTY)
+ {
+ int yyn = yypact[*yyssp];
+ yyarg[yycount++] = yytname[yytoken];
+ if (!yypact_value_is_default (yyn))
+ {
+ /* Start YYX at -YYN if negative to avoid negative indexes in
+ YYCHECK. In other words, skip the first -YYN actions for
+ this state because they are default actions. */
+ int yyxbegin = yyn < 0 ? -yyn : 0;
+ /* Stay within bounds of both yycheck and yytname. */
+ int yychecklim = YYLAST - yyn + 1;
+ int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
+ int yyx;
+
+ for (yyx = yyxbegin; yyx < yyxend; ++yyx)
+ if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
+ && !yytable_value_is_error (yytable[yyx + yyn]))
+ {
+ if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
+ {
+ yycount = 1;
+ yysize = yysize0;
+ break;
+ }
+ yyarg[yycount++] = yytname[yyx];
+ {
+ YYSIZE_T yysize1 = yysize + yytnamerr (YY_NULLPTR, yytname[yyx]);
+ if (! (yysize <= yysize1
+ && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+ }
+ }
+ }
+
+ switch (yycount)
+ {
+# define YYCASE_(N, S) \
+ case N: \
+ yyformat = S; \
+ break
+ YYCASE_(0, YY_("syntax error"));
+ YYCASE_(1, YY_("syntax error, unexpected %s"));
+ YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
+ YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
+ YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
+ YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
+# undef YYCASE_
+ }
+
+ {
+ YYSIZE_T yysize1 = yysize + yystrlen (yyformat);
+ if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
+ return 2;
+ yysize = yysize1;
+ }
+
+ if (*yymsg_alloc < yysize)
+ {
+ *yymsg_alloc = 2 * yysize;
+ if (! (yysize <= *yymsg_alloc
+ && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
+ *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
+ return 1;
+ }
+
+ /* Avoid sprintf, as that infringes on the user's name space.
+ Don't have undefined behavior even if the translation
+ produced a string with the wrong number of "%s"s. */
+ {
+ char *yyp = *yymsg;
+ int yyi = 0;
+ while ((*yyp = *yyformat) != '\0')
+ if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
+ {
+ yyp += yytnamerr (yyp, yyarg[yyi++]);
+ yyformat += 2;
+ }
+ else
+ {
+ yyp++;
+ yyformat++;
+ }
+ }
+ return 0;
+}
+#endif /* YYERROR_VERBOSE */
+
+/*-----------------------------------------------.
+| Release the memory associated to this symbol. |
+`-----------------------------------------------*/
+
+static void
+yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
+{
+ YYUSE (yyvaluep);
+ if (!yymsg)
+ yymsg = "Deleting";
+ YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ YYUSE (yytype);
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+}
+
+
+
+
+/* The lookahead symbol. */
+int yychar;
+
+/* The semantic value of the lookahead symbol. */
+YYSTYPE yylval;
+/* Number of syntax errors so far. */
+int yynerrs;
+
+
+/*----------.
+| yyparse. |
+`----------*/
+
+int
+yyparse (void)
+{
+ int yystate;
+ /* Number of tokens to shift before error messages enabled. */
+ int yyerrstatus;
+
+ /* The stacks and their tools:
+ 'yyss': related to states.
+ 'yyvs': related to semantic values.
+
+ Refer to the stacks through separate pointers, to allow yyoverflow
+ to reallocate them elsewhere. */
+
+ /* The state stack. */
+ yytype_int16 yyssa[YYINITDEPTH];
+ yytype_int16 *yyss;
+ yytype_int16 *yyssp;
+
+ /* The semantic value stack. */
+ YYSTYPE yyvsa[YYINITDEPTH];
+ YYSTYPE *yyvs;
+ YYSTYPE *yyvsp;
+
+ YYSIZE_T yystacksize;
+
+ int yyn;
+ int yyresult;
+ /* Lookahead token as an internal (translated) token number. */
+ int yytoken = 0;
+ /* The variables used to return semantic value and location from the
+ action routines. */
+ YYSTYPE yyval;
+
+#if YYERROR_VERBOSE
+ /* Buffer for error messages, and its allocated size. */
+ char yymsgbuf[128];
+ char *yymsg = yymsgbuf;
+ YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
+#endif
+
+#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N))
+
+ /* The number of symbols on the RHS of the reduced rule.
+ Keep to zero when no symbol should be popped. */
+ int yylen = 0;
+
+ yyssp = yyss = yyssa;
+ yyvsp = yyvs = yyvsa;
+ yystacksize = YYINITDEPTH;
+
+ YYDPRINTF ((stderr, "Starting parse\n"));
+
+ yystate = 0;
+ yyerrstatus = 0;
+ yynerrs = 0;
+ yychar = YYEMPTY; /* Cause a token to be read. */
+ goto yysetstate;
+
+/*------------------------------------------------------------.
+| yynewstate -- Push a new state, which is found in yystate. |
+`------------------------------------------------------------*/
+ yynewstate:
+ /* In all cases, when you get here, the value and location stacks
+ have just been pushed. So pushing a state here evens the stacks. */
+ yyssp++;
+
+ yysetstate:
+ *yyssp = yystate;
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ {
+ /* Get the current used size of the three stacks, in elements. */
+ YYSIZE_T yysize = yyssp - yyss + 1;
+
+#ifdef yyoverflow
+ {
+ /* Give user a chance to reallocate the stack. Use copies of
+ these so that the &'s don't force the real ones into
+ memory. */
+ YYSTYPE *yyvs1 = yyvs;
+ yytype_int16 *yyss1 = yyss;
+
+ /* Each stack pointer address is followed by the size of the
+ data in use in that stack, in bytes. This used to be a
+ conditional around just the two extra args, but that might
+ be undefined if yyoverflow is a macro. */
+ yyoverflow (YY_("memory exhausted"),
+ &yyss1, yysize * sizeof (*yyssp),
+ &yyvs1, yysize * sizeof (*yyvsp),
+ &yystacksize);
+
+ yyss = yyss1;
+ yyvs = yyvs1;
+ }
+#else /* no yyoverflow */
+# ifndef YYSTACK_RELOCATE
+ goto yyexhaustedlab;
+# else
+ /* Extend the stack our own way. */
+ if (YYMAXDEPTH <= yystacksize)
+ goto yyexhaustedlab;
+ yystacksize *= 2;
+ if (YYMAXDEPTH < yystacksize)
+ yystacksize = YYMAXDEPTH;
+
+ {
+ yytype_int16 *yyss1 = yyss;
+ union yyalloc *yyptr =
+ (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
+ if (! yyptr)
+ goto yyexhaustedlab;
+ YYSTACK_RELOCATE (yyss_alloc, yyss);
+ YYSTACK_RELOCATE (yyvs_alloc, yyvs);
+# undef YYSTACK_RELOCATE
+ if (yyss1 != yyssa)
+ YYSTACK_FREE (yyss1);
+ }
+# endif
+#endif /* no yyoverflow */
+
+ yyssp = yyss + yysize - 1;
+ yyvsp = yyvs + yysize - 1;
+
+ YYDPRINTF ((stderr, "Stack size increased to %lu\n",
+ (unsigned long int) yystacksize));
+
+ if (yyss + yystacksize - 1 <= yyssp)
+ YYABORT;
+ }
+
+ YYDPRINTF ((stderr, "Entering state %d\n", yystate));
+
+ if (yystate == YYFINAL)
+ YYACCEPT;
+
+ goto yybackup;
+
+/*-----------.
+| yybackup. |
+`-----------*/
+yybackup:
+
+ /* Do appropriate processing given the current state. Read a
+ lookahead token if we need one and don't already have one. */
+
+ /* First try to decide what to do without reference to lookahead token. */
+ yyn = yypact[yystate];
+ if (yypact_value_is_default (yyn))
+ goto yydefault;
+
+ /* Not known => get a lookahead token if don't already have one. */
+
+ /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */
+ if (yychar == YYEMPTY)
+ {
+ YYDPRINTF ((stderr, "Reading a token: "));
+ yychar = yylex ();
+ }
+
+ if (yychar <= YYEOF)
+ {
+ yychar = yytoken = YYEOF;
+ YYDPRINTF ((stderr, "Now at end of input.\n"));
+ }
+ else
+ {
+ yytoken = YYTRANSLATE (yychar);
+ YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
+ }
+
+ /* If the proper action on seeing token YYTOKEN is to reduce or to
+ detect an error, take that action. */
+ yyn += yytoken;
+ if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
+ goto yydefault;
+ yyn = yytable[yyn];
+ if (yyn <= 0)
+ {
+ if (yytable_value_is_error (yyn))
+ goto yyerrlab;
+ yyn = -yyn;
+ goto yyreduce;
+ }
+
+ /* Count tokens shifted since error; after three, turn off error
+ status. */
+ if (yyerrstatus)
+ yyerrstatus--;
+
+ /* Shift the lookahead token. */
+ YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
+
+ /* Discard the shifted token. */
+ yychar = YYEMPTY;
+
+ yystate = yyn;
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+ goto yynewstate;
+
+
+/*-----------------------------------------------------------.
+| yydefault -- do the default action for the current state. |
+`-----------------------------------------------------------*/
+yydefault:
+ yyn = yydefact[yystate];
+ if (yyn == 0)
+ goto yyerrlab;
+ goto yyreduce;
+
+
+/*-----------------------------.
+| yyreduce -- Do a reduction. |
+`-----------------------------*/
+yyreduce:
+ /* yyn is the number of a rule to reduce with. */
+ yylen = yyr2[yyn];
+
+ /* If YYLEN is nonzero, implement the default value of the action:
+ '$$ = $1'.
+
+ Otherwise, the following line sets YYVAL to garbage.
+ This behavior is undocumented and Bison
+ users should not rely upon it. Assigning to YYVAL
+ unconditionally makes the parser a bit smaller, and it avoids a
+ GCC warning that YYVAL may be used uninitialized. */
+ yyval = yyvsp[1-yylen];
+
+
+ YY_REDUCE_PRINT (yyn);
+ switch (yyn)
+ {
+ case 11:
+#line 127 "bindparser.yy" /* yacc.c:1646 */
+ {
+ s_di.name=DNSName((yyvsp[-1]));
+ free((yyvsp[-1]));
+ parent->commit(s_di);
+ s_di.clear();
+ }
+#line 1398 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 12:
+#line 135 "bindparser.yy" /* yacc.c:1646 */
+ {
+ s_di.name=DNSName((yyvsp[-2]));
+ free((yyvsp[-2]));
+ parent->commit(s_di);
+ s_di.clear();
+ }
+#line 1409 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 27:
+#line 179 "bindparser.yy" /* yacc.c:1646 */
+ {
+ parent->setDirectory((yyvsp[0]));
+ free((yyvsp[0]));
+ }
+#line 1418 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 31:
+#line 194 "bindparser.yy" /* yacc.c:1646 */
+ {
+ parent->addAlsoNotify((yyvsp[0]));
+ free((yyvsp[0]));
+ }
+#line 1427 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 51:
+#line 241 "bindparser.yy" /* yacc.c:1646 */
+ {
+ s_di.alsoNotify.insert((yyvsp[0]));
+ free((yyvsp[0]));
+ }
+#line 1436 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 54:
+#line 253 "bindparser.yy" /* yacc.c:1646 */
+ {
+ s_di.masters.push_back((yyvsp[0]));
+ free((yyvsp[0]));
+ }
+#line 1445 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 55:
+#line 261 "bindparser.yy" /* yacc.c:1646 */
+ {
+ // printf("Found a filename: '%s'\n",$2);
+ s_di.filename=(yyvsp[0]);
+ free((yyvsp[0]));
+ }
+#line 1455 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 56:
+#line 270 "bindparser.yy" /* yacc.c:1646 */
+ {
+ s_di.type=(yyvsp[0]);
+ free((yyvsp[0]));
+ }
+#line 1464 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+ case 57:
+#line 279 "bindparser.yy" /* yacc.c:1646 */
+ {
+ (yyval)=(yyvsp[0]);
+ }
+#line 1472 "bindparser.cc" /* yacc.c:1646 */
+ break;
+
+
+#line 1476 "bindparser.cc" /* yacc.c:1646 */
+ default: break;
+ }
+ /* User semantic actions sometimes alter yychar, and that requires
+ that yytoken be updated with the new translation. We take the
+ approach of translating immediately before every use of yytoken.
+ One alternative is translating here after every semantic action,
+ but that translation would be missed if the semantic action invokes
+ YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
+ if it invokes YYBACKUP. In the case of YYABORT or YYACCEPT, an
+ incorrect destructor might then be invoked immediately. In the
+ case of YYERROR or YYBACKUP, subsequent parser actions might lead
+ to an incorrect destructor call or verbose syntax error message
+ before the lookahead is translated. */
+ YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
+
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+
+ *++yyvsp = yyval;
+
+ /* Now 'shift' the result of the reduction. Determine what state
+ that goes to, based on the state we popped back to and the rule
+ number reduced by. */
+
+ yyn = yyr1[yyn];
+
+ yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
+ if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
+ yystate = yytable[yystate];
+ else
+ yystate = yydefgoto[yyn - YYNTOKENS];
+
+ goto yynewstate;
+
+
+/*--------------------------------------.
+| yyerrlab -- here on detecting error. |
+`--------------------------------------*/
+yyerrlab:
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
+
+ /* If not already recovering from an error, report this error. */
+ if (!yyerrstatus)
+ {
+ ++yynerrs;
+#if ! YYERROR_VERBOSE
+ yyerror (YY_("syntax error"));
+#else
+# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
+ yyssp, yytoken)
+ {
+ char const *yymsgp = YY_("syntax error");
+ int yysyntax_error_status;
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ if (yysyntax_error_status == 0)
+ yymsgp = yymsg;
+ else if (yysyntax_error_status == 1)
+ {
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+ yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
+ if (!yymsg)
+ {
+ yymsg = yymsgbuf;
+ yymsg_alloc = sizeof yymsgbuf;
+ yysyntax_error_status = 2;
+ }
+ else
+ {
+ yysyntax_error_status = YYSYNTAX_ERROR;
+ yymsgp = yymsg;
+ }
+ }
+ yyerror (yymsgp);
+ if (yysyntax_error_status == 2)
+ goto yyexhaustedlab;
+ }
+# undef YYSYNTAX_ERROR
+#endif
+ }
+
+
+
+ if (yyerrstatus == 3)
+ {
+ /* If just tried and failed to reuse lookahead token after an
+ error, discard it. */
+
+ if (yychar <= YYEOF)
+ {
+ /* Return failure if at end of input. */
+ if (yychar == YYEOF)
+ YYABORT;
+ }
+ else
+ {
+ yydestruct ("Error: discarding",
+ yytoken, &yylval);
+ yychar = YYEMPTY;
+ }
+ }
+
+ /* Else will try to reuse lookahead token after shifting the error
+ token. */
+ goto yyerrlab1;
+
+
+/*---------------------------------------------------.
+| yyerrorlab -- error raised explicitly by YYERROR. |
+`---------------------------------------------------*/
+yyerrorlab:
+
+ /* Pacify compilers like GCC when the user code never invokes
+ YYERROR and the label yyerrorlab therefore never appears in user
+ code. */
+ if (/*CONSTCOND*/ 0)
+ goto yyerrorlab;
+
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYERROR. */
+ YYPOPSTACK (yylen);
+ yylen = 0;
+ YY_STACK_PRINT (yyss, yyssp);
+ yystate = *yyssp;
+ goto yyerrlab1;
+
+
+/*-------------------------------------------------------------.
+| yyerrlab1 -- common code for both syntax error and YYERROR. |
+`-------------------------------------------------------------*/
+yyerrlab1:
+ yyerrstatus = 3; /* Each real token shifted decrements this. */
+
+ for (;;)
+ {
+ yyn = yypact[yystate];
+ if (!yypact_value_is_default (yyn))
+ {
+ yyn += YYTERROR;
+ if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
+ {
+ yyn = yytable[yyn];
+ if (0 < yyn)
+ break;
+ }
+ }
+
+ /* Pop the current state because it cannot handle the error token. */
+ if (yyssp == yyss)
+ YYABORT;
+
+
+ yydestruct ("Error: popping",
+ yystos[yystate], yyvsp);
+ YYPOPSTACK (1);
+ yystate = *yyssp;
+ YY_STACK_PRINT (yyss, yyssp);
+ }
+
+ YY_IGNORE_MAYBE_UNINITIALIZED_BEGIN
+ *++yyvsp = yylval;
+ YY_IGNORE_MAYBE_UNINITIALIZED_END
+
+
+ /* Shift the error token. */
+ YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
+
+ yystate = yyn;
+ goto yynewstate;
+
+
+/*-------------------------------------.
+| yyacceptlab -- YYACCEPT comes here. |
+`-------------------------------------*/
+yyacceptlab:
+ yyresult = 0;
+ goto yyreturn;
+
+/*-----------------------------------.
+| yyabortlab -- YYABORT comes here. |
+`-----------------------------------*/
+yyabortlab:
+ yyresult = 1;
+ goto yyreturn;
+
+#if !defined yyoverflow || YYERROR_VERBOSE
+/*-------------------------------------------------.
+| yyexhaustedlab -- memory exhaustion comes here. |
+`-------------------------------------------------*/
+yyexhaustedlab:
+ yyerror (YY_("memory exhausted"));
+ yyresult = 2;
+ /* Fall through. */
+#endif
+
+yyreturn:
+ if (yychar != YYEMPTY)
+ {
+ /* Make sure we have latest lookahead translation. See comments at
+ user semantic actions for why this is necessary. */
+ yytoken = YYTRANSLATE (yychar);
+ yydestruct ("Cleanup: discarding lookahead",
+ yytoken, &yylval);
+ }
+ /* Do not reclaim the symbols of the rule whose action triggered
+ this YYABORT or YYACCEPT. */
+ YYPOPSTACK (yylen);
+ YY_STACK_PRINT (yyss, yyssp);
+ while (yyssp != yyss)
+ {
+ yydestruct ("Cleanup: popping",
+ yystos[*yyssp], yyvsp);
+ YYPOPSTACK (1);
+ }
+#ifndef yyoverflow
+ if (yyss != yyssa)
+ YYSTACK_FREE (yyss);
+#endif
+#if YYERROR_VERBOSE
+ if (yymsg != yymsgbuf)
+ YYSTACK_FREE (yymsg);
+#endif
+ return yyresult;
+}
--- /dev/null
+/* A Bison parser, made by GNU Bison 3.0.2. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_BINDPARSER_HH_INCLUDED
+# define YY_YY_BINDPARSER_HH_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ AWORD = 258,
+ QUOTEDWORD = 259,
+ OBRACE = 260,
+ EBRACE = 261,
+ SEMICOLON = 262,
+ ZONETOK = 263,
+ FILETOK = 264,
+ OPTIONSTOK = 265,
+ DIRECTORYTOK = 266,
+ ACLTOK = 267,
+ LOGGINGTOK = 268,
+ CLASSTOK = 269,
+ TYPETOK = 270,
+ MASTERTOK = 271,
+ ALSONOTIFYTOK = 272
+ };
+#endif
+/* Tokens. */
+#define AWORD 258
+#define QUOTEDWORD 259
+#define OBRACE 260
+#define EBRACE 261
+#define SEMICOLON 262
+#define ZONETOK 263
+#define FILETOK 264
+#define OPTIONSTOK 265
+#define DIRECTORYTOK 266
+#define ACLTOK 267
+#define LOGGINGTOK 268
+#define CLASSTOK 269
+#define TYPETOK 270
+#define MASTERTOK 271
+#define ALSONOTIFYTOK 272
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+#endif /* !YY_YY_BINDPARSER_HH_INCLUDED */
--- /dev/null
+/* A Bison parser, made by GNU Bison 3.0.2. */
+
+/* Bison interface for Yacc-like parsers in C
+
+ Copyright (C) 1984, 1989-1990, 2000-2013 Free Software Foundation, Inc.
+
+ This program is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
+
+/* As a special exception, you may create a larger work that contains
+ part or all of the Bison parser skeleton and distribute that work
+ under terms of your choice, so long as that work isn't itself a
+ parser generator using the skeleton or a modified version thereof
+ as a parser skeleton. Alternatively, if you modify or redistribute
+ the parser skeleton itself, you may (at your option) remove this
+ special exception, which will cause the skeleton and the resulting
+ Bison output files to be licensed under the GNU General Public
+ License without this special exception.
+
+ This special exception was added by the Free Software Foundation in
+ version 2.2 of Bison. */
+
+#ifndef YY_YY_BINDPARSER_HH_INCLUDED
+# define YY_YY_BINDPARSER_HH_INCLUDED
+/* Debug traces. */
+#ifndef YYDEBUG
+# define YYDEBUG 1
+#endif
+#if YYDEBUG
+extern int yydebug;
+#endif
+
+/* Token type. */
+#ifndef YYTOKENTYPE
+# define YYTOKENTYPE
+ enum yytokentype
+ {
+ AWORD = 258,
+ QUOTEDWORD = 259,
+ OBRACE = 260,
+ EBRACE = 261,
+ SEMICOLON = 262,
+ ZONETOK = 263,
+ FILETOK = 264,
+ OPTIONSTOK = 265,
+ DIRECTORYTOK = 266,
+ ACLTOK = 267,
+ LOGGINGTOK = 268,
+ CLASSTOK = 269,
+ TYPETOK = 270,
+ MASTERTOK = 271,
+ ALSONOTIFYTOK = 272
+ };
+#endif
+/* Tokens. */
+#define AWORD 258
+#define QUOTEDWORD 259
+#define OBRACE 260
+#define EBRACE 261
+#define SEMICOLON 262
+#define ZONETOK 263
+#define FILETOK 264
+#define OPTIONSTOK 265
+#define DIRECTORYTOK 266
+#define ACLTOK 267
+#define LOGGINGTOK 268
+#define CLASSTOK 269
+#define TYPETOK 270
+#define MASTERTOK 271
+#define ALSONOTIFYTOK 272
+
+/* Value type. */
+#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
+typedef int YYSTYPE;
+# define YYSTYPE_IS_TRIVIAL 1
+# define YYSTYPE_IS_DECLARED 1
+#endif
+
+
+extern YYSTYPE yylval;
+
+int yyparse (void);
+
+#endif /* !YY_YY_BINDPARSER_HH_INCLUDED */
--- /dev/null
+%{
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <string>
+#include <iostream>
+#include <utility>
+#include <errno.h>
+#include "misc.hh"
+#include "pdnsexception.hh"
+#include "namespaces.hh"
+#define YYDEBUG 1
+extern int yydebug;
+#include "bindparserclasses.hh"
+
+#define YYSTYPE char *
+
+extern "C"
+{
+ int yyparse(void);
+ int yylex(void);
+ void yyrestart(FILE *);
+ int yywrap()
+ {
+ return 1;
+ }
+}
+
+
+extern int yydebug;
+const char *bind_directory;
+extern int linenumber;
+static void yyerror(const char *str)
+{
+ extern char *current_filename;
+ throw PDNSException("Error in bind configuration '"+string(current_filename)+"' on line "+itoa(linenumber)+": "+str);
+}
+
+extern FILE *yyin;
+static BindParser *parent;
+BindDomainInfo s_di;
+
+void BindParser::parse(const string &fname)
+{
+ yydebug=0;
+ yyin=fopen(fname.c_str(),"r");
+ yyrestart(yyin);
+ if(!yyin)
+ throw PDNSException("Unable to open '"+fname+"': "+strerror(errno));
+
+ linenumber=1;
+ parent=this;
+ extern char *current_filename;
+ extern char *original_filename;
+
+ current_filename=original_filename=(char*)fname.c_str();
+
+ yyparse();
+
+// cerr<<"Need to parse "<<d_zonedomains.size()<<" zone statements"<<endl;
+}
+
+void BindParser::setDirectory(const string &dir)
+{
+ d_dir=dir;
+ bind_directory=d_dir.c_str();
+}
+
+void BindParser::addAlsoNotify(const string & host)
+{
+ alsoNotify.insert(host);
+}
+
+const string &BindParser::getDirectory()
+{
+ return d_dir;
+}
+
+const vector<BindDomainInfo>& BindParser::getDomains()
+{
+ return d_zonedomains;
+}
+
+void BindParser::setVerbose(bool verbose)
+{
+ d_verbose=verbose;
+}
+
+void BindParser::commit(BindDomainInfo DI)
+{
+ if(DI.filename[0]!='/')
+ DI.filename=d_dir+"/"+DI.filename;
+
+ if(d_verbose)
+ cerr<<"Domain "<<DI.name.toStringNoDot()<<" lives in file '"<<DI.filename<<"'"<<endl;
+
+ d_zonedomains.push_back(DI);
+}
+
+%}
+
+%token AWORD QUOTEDWORD OBRACE EBRACE SEMICOLON ZONETOK FILETOK OPTIONSTOK
+%token DIRECTORYTOK ACLTOK LOGGINGTOK CLASSTOK TYPETOK MASTERTOK ALSONOTIFYTOK
+
+%%
+
+root_commands:
+ |
+ root_commands root_command SEMICOLON
+ ;
+
+root_command: command | acl_command | global_zone_command | global_options_command
+ ;
+
+commands:
+ |
+ commands command SEMICOLON
+ ;
+
+command:
+ terms
+ ;
+
+global_zone_command:
+ ZONETOK quotedname zone_block
+ {
+ s_di.name=DNSName($2);
+ free($2);
+ parent->commit(s_di);
+ s_di.clear();
+ }
+ |
+ ZONETOK quotedname AWORD zone_block
+ {
+ s_di.name=DNSName($2);
+ free($2);
+ parent->commit(s_di);
+ s_di.clear();
+ }
+ ;
+
+
+global_options_command:
+ OPTIONSTOK OBRACE options_commands EBRACE
+ |
+ LOGGINGTOK OBRACE options_commands EBRACE
+ ;
+
+
+acl_command:
+ ACLTOK quotedname acl_block | ACLTOK filename acl_block
+ ;
+
+acl_block: OBRACE acls EBRACE
+ ;
+
+acls:
+ |
+ acl SEMICOLON acls
+ ;
+
+acl:
+ AWORD
+ ;
+
+options_commands:
+ |
+ options_command SEMICOLON options_commands
+ ;
+
+options_command: command | global_options_command
+ ;
+
+global_options_command: options_directory_command | also_notify_command
+ ;
+
+options_directory_command: DIRECTORYTOK quotedname
+ {
+ parent->setDirectory($2);
+ free($2);
+ }
+ ;
+
+also_notify_command: ALSONOTIFYTOK OBRACE also_notify_list EBRACE
+ ;
+
+also_notify_list:
+ |
+ also_notify SEMICOLON also_notify_list
+ ;
+
+also_notify: AWORD
+ {
+ parent->addAlsoNotify($1);
+ free($1);
+ }
+ ;
+terms: /* empty */
+ |
+ terms term
+ ;
+
+term: AWORD | block | quotedname
+ ;
+block:
+ OBRACE commands EBRACE
+ ;
+
+zone_block:
+ OBRACE zone_commands EBRACE
+ ;
+
+zone_commands:
+ |
+ zone_commands zone_command SEMICOLON
+ ;
+
+/* commands in zone
+ * in global scope also_notify_command is used instead of zone_also_notify_command
+ */
+zone_command: command | global_zone_command | zone_also_notify_command
+ ;
+
+/* zone commands that also are available at global scope */
+global_zone_command: zone_file_command | zone_type_command | zone_masters_command
+ ;
+
+zone_masters_command: MASTERTOK OBRACE masters EBRACE
+ ;
+
+zone_also_notify_command: ALSONOTIFYTOK OBRACE zone_also_notify_list EBRACE
+ ;
+
+zone_also_notify_list:
+ |
+ zone_also_notify SEMICOLON zone_also_notify_list
+ ;
+
+zone_also_notify: AWORD
+ {
+ s_di.alsoNotify.insert($1);
+ free($1);
+ }
+ ;
+
+masters: /* empty */
+ |
+ masters master SEMICOLON
+ ;
+
+master: AWORD
+ {
+ s_di.masters.push_back($1);
+ free($1);
+ }
+ ;
+
+zone_file_command:
+ FILETOK quotedname
+ {
+ // printf("Found a filename: '%s'\n",$2);
+ s_di.filename=$2;
+ free($2);
+ }
+ ;
+
+zone_type_command:
+TYPETOK AWORD
+ {
+ s_di.type=$2;
+ free($2);
+ }
+ ;
+
+
+quotedname:
+ QUOTEDWORD
+ {
+ $$=$1;
+ }
+ ;
+
+filename: AWORD
+ ;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef BINDPARSER_HH
+#define BINDPARSER_HH
+#include <string>
+#include <map>
+#include <vector>
+#include <set>
+#include <stdio.h>
+#include <sys/stat.h>
+
+#include "namespaces.hh"
+
+class BindDomainInfo
+{
+public:
+ BindDomainInfo() : d_dev(0), d_ino(0)
+ {}
+
+ void clear()
+ {
+ name=DNSName();
+ filename=type="";
+ masters.clear();
+ alsoNotify.clear();
+ d_dev=0;
+ d_ino=0;
+ }
+ DNSName name;
+ string viewName;
+ string filename;
+ vector<string> masters;
+ set<string> alsoNotify;
+ string type;
+
+ dev_t d_dev;
+ ino_t d_ino;
+
+ bool operator<(const BindDomainInfo& b) const
+ {
+ return make_pair(d_dev, d_ino) < make_pair(b.d_dev, b.d_ino);
+ }
+};
+
+extern const char *bind_directory;
+extern FILE *yyin;
+class BindParser
+{
+ public:
+ BindParser() : d_dir("."), d_verbose(false)
+ {
+ yyin=0;
+ extern int include_stack_ptr;
+ include_stack_ptr=0;
+
+ bind_directory=d_dir.c_str();
+ }
+ ~BindParser()
+ {
+ if(yyin) {
+ fclose(yyin);
+ yyin=0;
+ }
+ }
+ void parse(const string &fname);
+ void commit(BindDomainInfo DI);
+ void setDirectory(const string &dir);
+ const string &getDirectory();
+ const vector<BindDomainInfo>& getDomains();
+ void setVerbose(bool verbose);
+ void addAlsoNotify(const string &host);
+ set<string> & getAlsoNotify() { return this->alsoNotify; }
+private:
+ string d_dir;
+ typedef map<DNSName,string> zonedomain_t;
+ set<string> alsoNotify;
+ vector<BindDomainInfo> d_zonedomains;
+ bool d_verbose;
+};
+
+#endif /* BINDPARSER_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <botan/botan.h>
+#include <botan/gost_3410.h>
+#include <botan/gost_3411.h>
+#include "dnssecinfra.hh"
+
+using namespace Botan;
+
+/* Государственный гимн Российской Федерации
+ (Gosudarstvenny Gimn Rossiyskoy Federatsii)
+ "The National Anthem of the Russian Federation"
+
+ ~ Rossiya - svyashchennaya nasha derzhava, ~
+ ~ Rossiya - lyubimaya nasha strana. ~
+ ~ Moguchaya volya, velikaya slava - ~
+ ~ Tvoyo dostoyanye na vse vremena! ~
+ */
+
+class GOSTDNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit GOSTDNSCryptoKeyEngine(unsigned int algorithm) : DNSCryptoKeyEngine(algorithm) {}
+ // XXX FIXME NEEDS COPY CONSTRUCTOR SO WE DON'T SHARE KEYS
+ ~GOSTDNSCryptoKeyEngine(){}
+ void create(unsigned int bits) override;
+ string getName() const override { return "Botan 1.10 GOST"; }
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& hash) const override;
+ std::string hash(const std::string& hash) const override;
+ bool verify(const std::string& hash, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& content) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<GOSTDNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ shared_ptr<GOST_3410_PrivateKey> d_key;
+ shared_ptr<GOST_3410_PublicKey> d_pubkey;
+};
+
+/*
+ ~ Slav'sya, Otechestvo nashe svobodnoye, ~
+ ~ Bratskikh narodov soyuz vekovoy, ~
+ ~ Predkami dannaya mudrost' narodnaya! ~
+ ~ Slav'sya, strana! My gordimsya toboy! ~
+*/
+
+
+void GOSTDNSCryptoKeyEngine::create(unsigned int bits)
+{
+ AutoSeeded_RNG rng;
+ EC_Domain_Params params("1.2.643.2.2.35.1");
+ d_key = shared_ptr<GOST_3410_PrivateKey>(new GOST_3410_PrivateKey(rng, params));
+}
+
+int GOSTDNSCryptoKeyEngine::getBits() const
+{
+ return 256;
+}
+
+/*
+ ~ Ot yuzhnykh morey do polyarnogo kraya ~
+ ~ Raskinulis' nashi lesa i polya. ~
+ ~ Odna ty na svete! Odna ty takaya - ~
+ ~ Khranimaya Bogom rodnaya zemlya! ~
+*/
+
+DNSCryptoKeyEngine::storvector_t GOSTDNSCryptoKeyEngine::convertToISCVector() const
+{
+ storvector_t storvect;
+ storvect.push_back(make_pair("Algorithm", "12 (ECC-GOST)"));
+
+ unsigned char asn1Prefix[]=
+ {0x30, 0x45, 0x02, 0x01, 0x00, 0x30, 0x1c, 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02,
+ 0x13, 0x30, 0x12, 0x06, 0x07, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x23, 0x01, 0x06, 0x07,
+ 0x2a, 0x85, 0x03, 0x02, 0x02, 0x1e, 0x01, 0x04, 0x22, 0x04, 0x20}; // this is DER, fixed for a 32 byte key
+
+ SecureVector<byte> buffer=BigInt::encode(d_key->private_value());
+ string gostasn1((const char*)asn1Prefix, sizeof(asn1Prefix));
+ gostasn1.append((const char*)&*buffer.begin(), (const char*)&*buffer.end());
+ storvect.push_back(make_pair("GostAsn1", gostasn1));
+ return storvect;
+}
+
+/*
+ ~ Slav'sya, Otechestvo nashe svobodnoye, ~
+ ~ Bratskikh narodov soyuz vekovoy, ~
+ ~ Predkami dannaya mudrost' narodnaya! ~
+ ~ Slav'sya, strana! My gordimsya toboy! ~
+*/
+
+void GOSTDNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey=stormap["gostasn1"];
+ //cerr<<"PrivateKey.size() = "<<privateKey.size()<<endl;
+ //cerr<<makeHexDump(string(privateKey.c_str(), 39))<<endl;
+ string rawKey(privateKey.c_str()+39, privateKey.length()-39);
+
+ for(size_t i = 0; i < rawKey.size() / 2; ++i)
+ {
+ std::swap(rawKey[i], rawKey[rawKey.size()-1-i]);
+ }
+
+ BigInt bigint((byte*)rawKey.c_str(), rawKey.size());
+
+ EC_Group params("1.2.643.2.2.35.1");
+ AutoSeeded_RNG rng;
+ d_key=shared_ptr<GOST_3410_PrivateKey>(new GOST_3410_PrivateKey(rng, params, bigint));
+
+ //cerr<<"Is the just imported key on the curve? " << d_key->public_point().on_the_curve()<<endl;
+ //cerr<<"Is the just imported key zero? " << d_key->public_point().is_zero()<<endl;
+
+ const BigInt&x = d_key->private_value();
+ SecureVector<byte> buffer=BigInt::encode(x);
+ // cerr<<"And out again! "<<makeHexDump(string((const char*)buffer.begin(), (const char*)buffer.end()))<<endl;
+}
+namespace {
+
+BigInt decode_le(const byte msg[], size_t msg_len)
+ {
+ SecureVector<byte> msg_le(msg, msg_len);
+
+ for(size_t i = 0; i != msg_le.size() / 2; ++i)
+ std::swap(msg_le[i], msg_le[msg_le.size()-1-i]);
+
+ return BigInt(&msg_le[0], msg_le.size());
+ }
+
+}
+void GOSTDNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ BigInt x, y;
+
+ x=decode_le((const byte*)input.c_str(), input.length()/2);
+ y=decode_le((const byte*)input.c_str() + input.length()/2, input.length()/2);
+
+ EC_Domain_Params params("1.2.643.2.2.35.1");
+ PointGFp point(params.get_curve(), x,y);
+ d_pubkey = shared_ptr<GOST_3410_PublicKey>(new GOST_3410_PublicKey(params, point));
+ d_key.reset();
+}
+
+std::string GOSTDNSCryptoKeyEngine::getPubKeyHash() const
+{
+ const BigInt&x = d_key->private_value();
+ SecureVector<byte> buffer=BigInt::encode(x);
+ return string((const char*)buffer.begin(), (const char*)buffer.end());
+}
+
+std::string GOSTDNSCryptoKeyEngine::getPublicKeyString() const
+{
+ const BigInt&x =d_key->public_point().get_affine_x();
+ const BigInt&y =d_key->public_point().get_affine_y();
+
+ size_t part_size = std::max(x.bytes(), y.bytes());
+
+ MemoryVector<byte> bits(2*part_size);
+
+ x.binary_encode(&bits[part_size - x.bytes()]);
+ y.binary_encode(&bits[2*part_size - y.bytes()]);
+
+ // Keys are stored in little endian format (WTF)
+ for(size_t i = 0; i != part_size / 2; ++i)
+ {
+ std::swap(bits[i], bits[part_size-1-i]);
+ std::swap(bits[part_size+i], bits[2*part_size-1-i]);
+ }
+
+ return string((const char*)bits.begin(), (const char*)bits.end());
+}
+
+/*
+ ~ Shirokiy prostor dlya mechty i dlya zhizni. ~
+ ~ Gryadushchiye nam otkryvayut goda. ~
+ ~ Nam silu dayot nasha vernost' Otchizne. ~
+ ~ Tak bylo, tak yest' i tak budet vsegda! ~
+ */
+
+std::string GOSTDNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ GOST_3410_Signature_Operation ops(*d_key);
+ AutoSeeded_RNG rng;
+
+ string hash= this->hash(msg);
+
+ SecureVector<byte> signature=ops.sign((byte*)hash.c_str(), hash.length(), rng);
+
+#if BOTAN_VERSION_CODE <= BOTAN_VERSION_CODE_FOR(1,9,12) // see http://bit.ly/gTytUf
+ string reversed((const char*)signature.begin()+ signature.size()/2, signature.size()/2);
+ reversed.append((const char*)signature.begin(), signature.size()/2);
+ return reversed;
+#else
+ return string((const char*)signature.begin(), (const char*) signature.end());
+#endif
+}
+
+std::string GOSTDNSCryptoKeyEngine::hash(const std::string& orig) const
+{
+ SecureVector<byte> result;
+
+ GOST_34_11 hasher;
+ result= hasher.process(orig);
+ return string((const char*)result.begin(), (const char*) result.end());
+}
+
+
+bool GOSTDNSCryptoKeyEngine::verify(const std::string& message, const std::string& signature) const
+{
+ string hash = this->hash(message);
+ GOST_3410_PublicKey* pk;
+ if(d_pubkey) {
+ pk =d_pubkey.get();
+ }
+ else
+ pk = d_key.get();
+
+ GOST_3410_Verification_Operation ops(*pk);
+#if BOTAN_VERSION_CODE <= BOTAN_VERSION_CODE_FOR(1,9,12) // see http://bit.ly/gTytUf
+ string rsignature(signature.substr(32));
+ rsignature.append(signature.substr(0,32));
+ return ops.verify ((byte*)hash.c_str(), hash.length(), (byte*)rsignature.c_str(), rsignature.length());
+#else
+ return ops.verify ((byte*)hash.c_str(), hash.length(), (byte*)signature.c_str(), signature.length());
+#endif
+}
+
+/*
+ ~ Slav'sya, Otechestvo nashe svobodnoye, ~
+ ~ Bratskikh narodov soyuz vekovoy, ~
+ ~ Predkami dannaya mudrost' narodnaya! ~
+ ~ Slav'sya, strana! My gordimsya toboy! ~
+*/
+
+
+//////////////////////////////
+
+namespace {
+struct LoaderStruct
+{
+ LoaderStruct()
+ {
+ new Botan::LibraryInitializer("thread_safe=true");
+ // this leaks, but is fine
+ Botan::global_state().set_default_allocator("malloc"); // the other Botan allocator slows down for us
+
+ DNSCryptoKeyEngine::report(12, &GOSTDNSCryptoKeyEngine::maker);
+ }
+} loaderBotan110;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_CACHECLEANER_HH
+#define PDNS_CACHECLEANER_HH
+
+// this function can clean any cache that has a getTTD() method on its entries, and a 'sequence' index as its second index
+// the ritual is that the oldest entries are in *front* of the sequence collection, so on a hit, move an item to the end
+// on a miss, move it to the beginning
+template <typename T> void pruneCollection(T& collection, unsigned int maxCached, unsigned int scanFraction=1000)
+{
+ uint32_t now=(uint32_t)time(0);
+ unsigned int toTrim=0;
+
+ unsigned int cacheSize=collection.size();
+
+ if(cacheSize > maxCached) {
+ toTrim = cacheSize - maxCached;
+ }
+
+// cout<<"Need to trim "<<toTrim<<" from cache to meet target!\n";
+
+ typedef typename T::template nth_index<1>::type sequence_t;
+ sequence_t& sidx=collection.template get<1>();
+
+ unsigned int tried=0, lookAt, erased=0;
+
+ // two modes - if toTrim is 0, just look through 1/scanFraction of all records
+ // and nuke everything that is expired
+ // otherwise, scan first 5*toTrim records, and stop once we've nuked enough
+ if(toTrim)
+ lookAt=5*toTrim;
+ else
+ lookAt=cacheSize/scanFraction;
+
+ typename sequence_t::iterator iter=sidx.begin(), eiter;
+ for(; iter != sidx.end() && tried < lookAt ; ++tried) {
+ if(iter->getTTD() < now) {
+ sidx.erase(iter++);
+ erased++;
+ }
+ else
+ ++iter;
+
+ if(toTrim && erased > toTrim)
+ break;
+ }
+
+ //cout<<"erased "<<erased<<" records based on ttd\n";
+
+ if(erased >= toTrim) // done
+ return;
+
+ toTrim -= erased;
+
+ //if(toTrim)
+ // cout<<"Still have "<<toTrim - erased<<" entries left to erase to meet target\n";
+
+ eiter=iter=sidx.begin();
+ std::advance(eiter, toTrim);
+ sidx.erase(iter, eiter); // just lob it off from the beginning
+}
+
+// note: this expects iterator from first index, and sequence MUST be second index!
+template <typename T> void moveCacheItemToFrontOrBack(T& collection, typename T::iterator& iter, bool front)
+{
+ typedef typename T::template nth_index<1>::type sequence_t;
+ sequence_t& sidx=collection.template get<1>();
+ typename sequence_t::iterator si=collection.template project<1>(iter);
+ if(front)
+ sidx.relocate(sidx.begin(), si); // at the beginning of the delete queue
+ else
+ sidx.relocate(sidx.end(), si); // back
+}
+
+template <typename T> void moveCacheItemToFront(T& collection, typename T::iterator& iter)
+{
+ moveCacheItemToFrontOrBack(collection, iter, true);
+}
+
+template <typename T> void moveCacheItemToBack(T& collection, typename T::iterator& iter)
+{
+ moveCacheItemToFrontOrBack(collection, iter, false);
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <iostream>
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include <thread>
+#include <atomic>
+#include "statbag.hh"
+#include <fstream>
+#include <poll.h>
+#include <memory>
+using std::thread;
+using std::unique_ptr;
+
+StatBag S;
+
+std::atomic<unsigned int> g_recvcounter;
+volatile bool g_done;
+
+void* recvThread(const vector<Socket*>* sockets)
+{
+ vector<pollfd> rfds, fds;
+ for(const auto& s : *sockets) {
+ struct pollfd pfd;
+ pfd.fd = s->getHandle();
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ rfds.push_back(pfd);
+ }
+
+ int err;
+
+ vector<struct mmsghdr> buf(100);
+ for(auto& m : buf) {
+ fillMSGHdr(&m.msg_hdr, new struct iovec, new char[512], 512, new char[1500], 1500, new ComboAddress("127.0.0.1"));
+ }
+
+ while(!g_done) {
+ fds=rfds;
+
+ err = poll(&fds[0], fds.size(), -1);
+ if(err < 0) {
+ if(errno==EINTR)
+ continue;
+ unixDie("Unable to poll for new UDP events");
+ }
+
+ for(auto &pfd : fds) {
+ if(pfd.revents & POLLIN) {
+
+ if((err=recvmmsg(pfd.fd, &buf[0], buf.size(), MSG_WAITFORONE, 0)) < 0 ) {
+ if(errno != EAGAIN)
+ cerr<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
+ unixDie("recvmmsg");
+ continue;
+ }
+ g_recvcounter+=err;
+ }
+ }
+ }
+
+ return 0;
+}
+
+
+void setSocketBuffer(int fd, int optname, uint32_t size)
+{
+ uint32_t psize=0;
+ socklen_t len=sizeof(psize);
+
+ if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
+ cerr<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
+ return;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
+ cerr<<"Warning: unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
+}
+
+
+static void setSocketReceiveBuffer(int fd, uint32_t size)
+{
+ setSocketBuffer(fd, SO_RCVBUF, size);
+}
+
+static void setSocketSendBuffer(int fd, uint32_t size)
+{
+ setSocketBuffer(fd, SO_SNDBUF, size);
+}
+
+void sendPackets(const vector<Socket*>* sockets, const vector<vector<uint8_t>* >& packets, int qps, ComboAddress dest)
+{
+ unsigned int burst=100;
+ struct timespec nsec;
+ nsec.tv_sec=0;
+ nsec.tv_nsec=1*(unsigned long)(burst*1000000000.0/qps);
+ int count=0;
+
+ struct Unit {
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+ };
+ vector<unique_ptr<Unit> > units;
+ int ret;
+
+ for(const auto& p : packets) {
+ count++;
+
+ Unit u;
+
+ fillMSGHdr(&u.msgh, &u.iov, u.cbuf, 0, (char*)&(*p)[0], p->size(), &dest);
+ if((ret=sendmsg((*sockets)[count % sockets->size()]->getHandle(),
+ &u.msgh, 0)))
+ if(ret < 0)
+ unixDie("sendmmsg");
+
+
+ if(!(count%burst))
+ nanosleep(&nsec, 0);
+ }
+}
+
+void usage() {
+ cerr<<"Syntax: calidns QUERY_FILE DESTINATION INITIAL_QPS HITRATE"<<endl;
+}
+
+/*
+ New plan. Set cache hit percentage, which we achieve on a per second basis.
+ So we start with 10000 qps for example, and for 90% cache hit ratio means
+ we take 1000 unique queries and each send them 10 times.
+
+ We then move the 1000 unique queries to the 'known' pool.
+
+ For the next second, say 20000 qps, we know we are going to need 2000 new queries,
+ so we take 2000 from the unknown pool. Then we need 18000 cache hits. We can get 1000 from
+ the known pool, leaving us down 17000. Or, we have 3000 in total now and we need 2000. We simply
+ repeat the 3000 mix we have ~7 times. The 2000 can now go to the known pool too.
+
+ For the next second, say 30000 qps, we'll need 3000 cache misses, which we get from
+ the unknown pool. To this we add 3000 queries from the known pool. Next up we repeat this batch 5
+ times.
+
+ In general the algorithm therefore is:
+
+ 1) Calculate number of cache misses required, get them from the unknown pool
+ 2) Move those to the known pool
+ 3) Fill up to amount of queries we need with random picks from the known pool
+
+*/
+
+int main(int argc, char** argv)
+try
+{
+ struct sched_param param;
+ param.sched_priority=99;
+
+ if (argc == 1 || (argc > 1 && argc <5)) {
+ for(int i = 1; i<argc; i++) {
+ string opt(argv[i]);
+
+ if(opt == "--help") {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+
+ if(opt == "--version") {
+ cerr<<"calidns "<<VERSION<<endl;
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ usage();
+ if (argc == 1)
+ exit(EXIT_SUCCESS);
+ exit(EXIT_FAILURE);
+ }
+
+ if(sched_setscheduler(0, SCHED_FIFO, ¶m) < 0)
+ cerr<<"Unable to set SCHED_FIFO: "<<strerror(errno)<<endl;
+
+ double hitrate=atof(argv[4])/100.0;
+ int qpsstart=atoi(argv[3]);
+ ifstream ifs(argv[1]);
+ string line;
+ reportAllTypes();
+ vector<std::shared_ptr<vector<uint8_t> > > unknown, known;
+ while(getline(ifs, line)) {
+ vector<uint8_t> packet;
+ boost::trim(line);
+ auto p = splitField(line, ' ');
+ DNSPacketWriter pw(packet, DNSName(p.first), DNSRecordContent::TypeToNumber(p.second));
+ pw.getHeader()->rd=1;
+ pw.getHeader()->id=random();
+ unknown.emplace_back(std::make_shared<vector<uint8_t>>(packet));
+ }
+ random_shuffle(unknown.begin(), unknown.end());
+ cout<<"Generated "<<unknown.size()<<" ready to use queries"<<endl;
+
+ vector<Socket*> sockets;
+ ComboAddress dest(argv[2], 53);
+ for(int i=0; i < 24; ++i) {
+ Socket *sock = new Socket(dest.sin4.sin_family, SOCK_DGRAM);
+ // sock->connect(dest);
+ setSocketSendBuffer(sock->getHandle(), 2000000);
+ setSocketReceiveBuffer(sock->getHandle(), 2000000);
+ sockets.push_back(sock);
+ }
+ new thread(recvThread, &sockets);
+ int qps;
+
+ ofstream plot("plot");
+ for(qps=qpsstart;;qps *= 1.1) {
+ double seconds=1;
+ cout<<"Aiming at "<<qps<< "qps for "<<seconds<<" seconds at cache hitrate "<<100.0*hitrate<<"%";
+ unsigned int misses=(1-hitrate)*qps*seconds;
+ unsigned int total=qps*seconds;
+ if (misses == 0) {
+ misses = 1;
+ }
+ cout<<", need "<<misses<<" misses, "<<total<<" queries, have "<<unknown.size()<<" unknown left!"<<endl;
+
+ if (misses > unknown.size()) {
+ cerr<<"Not enough queries remaining (need at least "<<misses<<" and got "<<unknown.size()<<", please add more to the query file), exiting."<<endl;
+ exit(1);
+ }
+ vector<vector<uint8_t>*> toSend;
+ unsigned int n;
+ for(n=0; n < misses; ++n) {
+ auto ptr=unknown.back();
+ unknown.pop_back();
+ toSend.push_back(ptr.get());
+ known.push_back(ptr);
+ }
+ for(;n < total; ++n) {
+ toSend.push_back(known[random()%known.size()].get());
+ }
+ random_shuffle(toSend.begin(), toSend.end());
+ g_recvcounter.store(0);
+ DTime dt;
+ dt.set();
+
+ sendPackets(&sockets, toSend, qps, dest);
+
+ auto udiff = dt.udiff();
+ auto realqps=toSend.size()/(udiff/1000000.0);
+ cout<<"Achieved "<<realqps<<"qps"<< " over "<< udiff/1000000.0<<" seconds"<<endl;
+
+ usleep(50000);
+ double perc=g_recvcounter.load()*100.0/toSend.size();
+ cout<<"Received "<<g_recvcounter.load()<<" packets ("<<perc<<"%)"<<endl;
+ plot<<qps<<" "<<realqps<<" "<<perc<<" "<<g_recvcounter.load()/(udiff/1000000.0)<<endl;
+ }
+ plot.flush();
+ // t1.detach();
+}
+ catch(std::exception& e)
+{
+ cerr<<"Fatal error: "<<e.what()<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "statbag.hh"
+#include "zoneparser-tng.hh"
+#include "namespaces.hh"
+#include "dnsrecords.hh"
+#include <fstream>
+#include <atomic>
+#include <thread>
+#include <unordered_set>
+#include "inflighter.cc"
+//#include "malloctrace.hh"
+StatBag S;
+bool g_quiet;
+std::unique_ptr<ofstream> g_powerdns;
+std::atomic<unsigned int> g_count;
+std::atomic<bool> g_stop;
+
+
+struct namecount {
+ set<DNSName> names;
+ unsigned int count;
+ bool isPowerDNS{false};
+};
+
+struct DNSResult
+{
+ string content;
+ int ttl{0};
+ uint16_t qclass;
+};
+
+struct NSQuery
+{
+ ComboAddress a;
+ set<DNSName> nsnames;
+ DNSName qname;
+ unsigned int count;
+};
+
+struct SendReceive
+{
+ typedef int Identifier;
+ typedef DNSResult Answer; // ip
+ int d_socket;
+ deque<uint16_t> d_idqueue;
+
+ SendReceive(map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan>& res) : d_res(res)
+ {
+ d_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ int val=1;
+ setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+
+ for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
+ d_idqueue.push_back(id);
+ }
+
+ ~SendReceive()
+ {
+ close(d_socket);
+ }
+
+ Identifier send(NSQuery& domain)
+ {
+ //cerr<<"Sending query for '"<<domain<<"'"<<endl;
+
+ // send it, copy code from 'sdig'
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, domain.qname, QType::TXT, 3);
+
+ if(d_idqueue.empty()) {
+ cerr<<"Exhausted ids!"<<endl;
+ exit(1);
+ }
+ pw.getHeader()->id = d_idqueue.front();
+ d_idqueue.pop_front();
+ pw.getHeader()->rd = 0;
+ pw.getHeader()->qr = 0;
+
+ if(::sendto(d_socket, &*packet.begin(), packet.size(), 0, (struct sockaddr*)&domain.a, domain.a.getSocklen()) < 0)
+ d_senderrors++;
+
+ return pw.getHeader()->id;
+ }
+
+ bool receive(Identifier& id, DNSResult& dr)
+ {
+ if(waitForData(d_socket, 0, 500000) > 0) {
+ char buf[512];
+ ComboAddress from;
+ from.sin4.sin_family = AF_INET;
+ socklen_t socklen=from.getSocklen();
+ int len = recvfrom(d_socket, buf, sizeof(buf),0, (struct sockaddr*)&from, &socklen);
+ if(len < 0) {
+ d_receiveerrors++;
+ return 0;
+ }
+ else {
+ d_receiveds++;
+ }
+ // parse packet, set 'id', fill out 'ip'
+
+ MOADNSParser mdp(false, string(buf, len));
+ if(!g_quiet) {
+ cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+ }
+ id = mdp.d_header.id;
+ d_idqueue.push_back(id);
+ dr.qclass = mdp.d_qclass;
+ dr.content.clear();
+ dr.ttl=0;
+ for(const auto& a : mdp.d_answers) {
+ if(a.first.d_type == QType::TXT) {
+ dr.content=a.first.d_content->getZoneRepresentation();
+ dr.ttl=a.first.d_ttl;
+ }
+ }
+ if(dr.content.empty())
+ dr.content="RCode: "+RCode::to_s(mdp.d_header.rcode);
+ return 1;
+ }
+ return 0;
+ }
+
+ void deliverTimeout(const Identifier& id)
+ {
+ if(!g_quiet) {
+ cout<<"Timeout for id "<<id<<endl;
+ }
+ d_idqueue.push_back(id);
+ }
+
+ void deliverAnswer(NSQuery& domain, const DNSResult& dr, unsigned int usec)
+ {
+ cout<<domain.a.toString()<<"\t"<<domain.qname<<"\t";
+ for(const auto& n : domain.nsnames)
+ cout<<n<<",";
+ cout<<"\t"<<domain.count<<"\t"<<dr.qclass<<'\t'<<dr.ttl<<": "<<dr.content<<endl;
+
+ if(dr.qclass==1 || toLower(dr.content).find("powerdns") != string::npos || dr.ttl==5) {
+ auto f = d_res.find(domain.a);
+ if(!f->second.isPowerDNS) {
+ (*g_powerdns)<<domain.a.toString()<<'\t'<<domain.count<<'\t';
+ for(const auto& n : domain.nsnames)
+ (*g_powerdns)<<n<<'\t';
+ (*g_powerdns)<<"\n";
+ f->second.isPowerDNS=true;
+ }
+
+ }
+
+ }
+ unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
+ unsigned int d_receiveds, d_receiveerrors, d_senderrors;
+ map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan>& d_res;
+};
+
+
+struct RESResult
+{
+ vector<ComboAddress> addrs;
+ uint16_t rcode;
+};
+
+typedef DNSName RESQuery;
+
+struct SendReceiveRes
+{
+ typedef int Identifier;
+ typedef RESResult Answer; // ip
+ int d_socket;
+ deque<uint16_t> d_idqueue;
+ map<DNSName, vector<ComboAddress>>& d_out;
+ SendReceiveRes(const ComboAddress& remote, map<DNSName,vector<ComboAddress>>& out) : d_out(out)
+ {
+ d_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ int val=1;
+ setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+ connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen());
+ for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
+ d_idqueue.push_back(id);
+ }
+
+ ~SendReceiveRes()
+ {
+ close(d_socket);
+ }
+
+ Identifier send(RESQuery& domain)
+ {
+ //cerr<<"Sending query for '"<<domain<<"'"<<endl;
+
+ // send it, copy code from 'sdig'
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, domain, QType::A);
+
+ if(d_idqueue.empty()) {
+ cerr<<"Exhausted ids!"<<endl;
+ exit(1);
+ }
+ pw.getHeader()->id = d_idqueue.front();
+ d_idqueue.pop_front();
+ pw.getHeader()->rd = 1;
+ pw.getHeader()->qr = 0;
+
+ if(::send(d_socket, &*packet.begin(), packet.size(), 0) < 0) {
+ cout<<"Error sending: "<<strerror(errno)<<endl;
+ d_senderrors++;
+ }
+
+ return pw.getHeader()->id;
+ }
+
+ bool receive(Identifier& id, RESResult& dr)
+ {
+ if(waitForData(d_socket, 0, 500000) > 0) {
+ char buf[512];
+ ComboAddress from;
+ from.sin4.sin_family = AF_INET;
+ socklen_t socklen=from.getSocklen();
+ int len = recvfrom(d_socket, buf, sizeof(buf),0, (struct sockaddr*)&from, &socklen);
+ if(len < 0) {
+ d_receiveerrors++;
+ return 0;
+ }
+ else {
+ d_receiveds++;
+ }
+ // parse packet, set 'id', fill out 'ip'
+
+ MOADNSParser mdp(false, string(buf, len));
+ if(!g_quiet) {
+ cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr<<", answers: "<<mdp.d_answers.size();
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+ }
+ id = mdp.d_header.id;
+ d_idqueue.push_back(id);
+ dr.rcode = mdp.d_header.rcode;
+ dr.addrs.clear();
+ for(const auto& a : mdp.d_answers) {
+ if(a.first.d_name != mdp.d_qname)
+ continue;
+ if(a.first.d_type == QType::A || a.first.d_type == QType::AAAA) {
+ if(!g_quiet)
+ cout<<a.first.d_content->getZoneRepresentation()<<endl;
+ dr.addrs.push_back(getAddr(a.first));
+ }
+ }
+ ++g_count;
+ return 1;
+ }
+ return 0;
+ }
+
+ void deliverTimeout(const Identifier& id)
+ {
+ if(!g_quiet) {
+ cout<<"Timeout for id "<<id<<endl;
+ }
+ ++g_count;
+ d_idqueue.push_back(id);
+ }
+
+ void deliverAnswer(DNSName& domain, const RESResult& dr, unsigned int usec)
+ {
+ d_out[domain]=dr.addrs;
+ cout<<domain<<"\t"<<dr.rcode<<'\t';
+ for(const auto& a : dr.addrs)
+ cout<<a.toString()<<'\t';
+ cout<<'\n';
+ }
+ unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
+ unsigned int d_receiveds, d_receiveerrors, d_senderrors;
+};
+
+
+void printStats()
+{
+ while(!g_stop) {
+ sleep(1);
+ cerr<<"\r"<<g_count;
+ cerr.flush();
+ }
+ cerr<<"\n";
+}
+
+int parseZone(const std::string& str, unsigned int limit)
+{
+ ZoneParserTNG zpt(str);
+ DNSResourceRecord rr;
+
+ std::thread stats(printStats);
+
+ map<DNSName,unsigned int> nsnames;
+ map<DNSName,set<ComboAddress,ComboAddress::addressOnlyLessThan> > addresses;
+
+
+ while(zpt.get(rr)) {
+ if(rr.qtype.getCode() == QType::NS)
+ nsnames[DNSName(rr.content)]++;
+ else if(rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) {
+ DNSRecord dr(rr);
+ addresses[rr.qname].insert(getAddr(dr, 53));
+ }
+ ++g_count;
+ if(g_count == limit)
+ break;
+ }
+ g_stop=true;
+ stats.join();
+
+ cout<<"Got "<<nsnames.size()<<" different nameserver names"<<endl;
+ cout<<"Got at least one address for "<<addresses.size()<<" names"<<endl;
+
+ ofstream ns(str+".nameservers");
+ ofstream needres(str+".needres");
+ for(const auto& a: nsnames) {
+ ns<<a.first<<"\t"<<a.second<<"\t";
+ if(auto hit=rplookup(addresses, a.first)) {
+ for(const auto& b : *hit)
+ ns<<b.toString()<<"\t";
+ }
+ else
+ needres<<a.first<<"\n";
+ ns<<"\n";
+ }
+ return 0;
+}
+
+int resolveNS(const std::string& fname)
+{
+ string line;
+ ifstream needres(fname);
+ if(!needres)
+ unixDie("Unable to open file "+fname);
+ vector<DNSName> tores;
+ while(getline(needres,line)) {
+ tores.push_back(DNSName(line));
+ }
+ cerr<<"Going to resolve "<<tores.size()<<" names"<<endl;
+ std::thread stats(printStats);
+ map<DNSName, vector<ComboAddress>> output;
+ SendReceiveRes sr(ComboAddress("192.168.1.2", 53), output);
+ Inflighter<vector<DNSName>, SendReceiveRes> inflighter(tores, sr);
+ inflighter.d_maxInFlight = 1000;
+ inflighter.d_timeoutSeconds = 3;
+ inflighter.d_burst = 100;
+ for(;;) {
+ try {
+ inflighter.run();
+ break;
+ }
+ catch(std::exception& e) {
+ cerr<<"Caught exception: "<<e.what()<<endl;
+ }
+ }
+ g_stop=true;
+ stats.join();
+ return EXIT_SUCCESS;
+}
+
+void readRESNames(const std::string& fname, map<DNSName, vector<ComboAddress>>& addrs)
+{
+ ifstream ifs(fname);
+ if(!ifs)
+ unixDie("Reading resolved names from "+fname+": "+string(strerror(errno)));
+ vector<string> parts;
+ string line;
+ addrs.clear();
+ while(getline(ifs, line)) {
+ parts.clear();
+ stringtok(parts, line,"\t");
+ for(unsigned int n=2; n < parts.size(); ++n)
+ addrs[DNSName(parts[0])].push_back(ComboAddress(parts[n], 53));
+ }
+ //EARTH.DOMAINS.SHELTEK.CA. 0 67.15.253.219 67.15.47.188 67.15.253.252 67.15.253.251 67.15.47.189 67.15.253.220
+ cerr<<"Got "<<addrs.size()<<" resolved nameserver names from file"<<endl;
+
+}
+
+int main(int argc, char**argv)
+try
+{
+ g_quiet=true;
+ reportAllTypes();
+ string mode=argv[1];
+ if(mode == "parse-zone") {
+ unsigned int limit = 0;
+ if(argc > 3)
+ limit = atoi(argv[3]);
+
+ return parseZone(argv[2], limit);
+ }
+ else if(mode=="resolve-ns") {
+ return resolveNS(string(argv[2])+".needres");
+ }
+ else if(mode=="scan-ns") {
+ ifstream ns(string(argv[2])+".nameservers");
+ g_powerdns = make_unique<ofstream>(string(argv[2])+".powerdns");
+ string line;
+ int count=0;
+ vector<string> parts;
+
+ struct NSCount
+ {
+ unsigned int count{0};
+ vector<ComboAddress> addrs;
+ };
+ map<DNSName, NSCount> stats;
+ NSCount nscount;
+ // NS1.IHOST2000.COM. 9 162.251.82.122 162.251.82.123 162.251.82.250 162.251.82.251
+ while(getline(ns, line)) {
+ ++count;
+ parts.clear();
+ stringtok(parts, line,"\t");
+ nscount.count=atoi(parts[1].c_str());
+ nscount.addrs.clear();
+ for(unsigned int n = 2; n < parts.size(); ++n)
+ nscount.addrs.push_back(ComboAddress(parts[n], 53));
+ stats.insert({DNSName(parts[0]), nscount});
+ }
+ cerr<<"Had "<<count<<" lines from summary"<<endl;
+
+ map<DNSName, vector<ComboAddress>> lookedup;
+ readRESNames(argv[2]+string(".resolved"), lookedup);
+
+ map<ComboAddress, namecount, ComboAddress::addressOnlyLessThan> pure;
+
+ unsigned int noaddrs=0;
+ for(const auto& s : stats) {
+ auto ptr = &s.second.addrs;
+ if(ptr->empty()) {
+ if(lookedup.count(s.first)) {
+ ptr = &lookedup[s.first];
+ }
+ else {
+ //cout<<"Have no address for "<<s.first.toString()<<endl;
+ noaddrs++;
+ }
+ }
+
+ for(const auto& a : *ptr) {
+ pure[a].count += s.second.count;
+ pure[a].names.insert(s.first);
+ }
+ }
+
+ cerr<<"Have "<<pure.size()<<" IP addresses to query, "<<noaddrs<<" names w/o address"<<endl;
+ SendReceive sr(pure);
+ vector<NSQuery> domains;
+
+ Inflighter<vector<NSQuery>, SendReceive> inflighter(domains, sr);
+ inflighter.d_maxInFlight = 1000;
+ inflighter.d_timeoutSeconds = 3;
+ inflighter.d_burst = 100;
+
+ for(const auto& p : pure) {
+ NSQuery nsq;
+ nsq.a=p.first;
+ nsq.nsnames = p.second.names;
+ nsq.count = p.second.count;
+
+ nsq.qname=DNSName("version.bind");
+ domains.push_back(nsq);
+ nsq.qname=DNSName("id.server");
+ domains.push_back(nsq);
+ nsq.qname=DNSName("bind.version");
+ domains.push_back(nsq);
+ }
+
+ sort(domains.begin(), domains.end(), [](const NSQuery& a, const NSQuery& b) { return b.count < a.count; });
+ for(;;) {
+ try {
+ inflighter.run();
+ break;
+ }
+ catch(std::exception& e) {
+ cerr<<"Caught exception: "<<e.what()<<endl;
+ }
+ }
+ }
+ else if(mode=="score-ns") {
+ std::unordered_set<DNSName> powerdns;
+ ifstream ifs(string(argv[2])+".powerdns");
+ string line;
+ vector<string> parts;
+ while(getline(ifs,line)) {
+ // 64.96.240.53 1234 NS1.UNIREGISTRYMARKET.LINK. NS1.INTERNETTRAFFIC.COM. BUY.INTERNETTRAFFIC.COM. NS3.SECUREDOFFERS.COM. NS3.GI.NET. NS3.IT.GI.NET. NS3.EASILY.NET.
+ parts.clear();
+ stringtok(parts, line);
+ for(unsigned int n=2; n < parts.size(); ++n)
+ powerdns.insert(DNSName(parts[n]));
+ }
+ cerr<<"Have "<<powerdns.size()<<" known NS names that are PowerDNS"<<endl;
+ ZoneParserTNG zpt(argv[2]);
+ DNSResourceRecord rr;
+
+ unsigned int pdnscount=0;
+ set<DNSName> seen, pdnsdomains;
+ int count=0;
+ while(zpt.get(rr)) {
+ if(!seen.count(rr.qname)) {
+ seen.insert(rr.qname);
+ }
+ if(rr.qtype.getCode() == QType::NS && powerdns.count(DNSName(rr.content)) && !pdnsdomains.count(DNSName(rr.qname))) {
+ pdnscount++;
+ pdnsdomains.insert(DNSName(rr.qname));
+ }
+ if(!(count%100000)) {
+ cerr<<"\rUnique domains: "<<seen.size()<<", PowerDNS domains: "<<pdnsdomains.size()<<" ("<<(pdnsdomains.size()*100.0/seen.size())<<"%)";
+ }
+ count++;
+ }
+ cerr<<"\n";
+ }
+ else {
+ cerr<<"Unknown mode "<<argv[1]<<endl;
+ }
+ // cout<<g_mtracer->topAllocatorsString(20)<<endl;
+}
+catch(PDNSException& pe) {
+ cerr<<"Fatal error: "<<pe.reason<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_COMMENT_HH
+#define PDNS_COMMENT_HH
+
+#include "utility.hh"
+#include "qtype.hh"
+#include <sys/types.h>
+
+class Comment
+{
+public:
+ Comment() : modified_at(0), domain_id(0) {};
+ ~Comment() {};
+
+ // data
+ DNSName qname; //!< the name of the associated RRset, for example: www.powerdns.com
+ time_t modified_at;
+ string account; //!< account last updating this comment
+ string content; //!< The actual comment. Example: blah blah
+
+ int domain_id;
+ QType qtype; //!< qtype of the associated RRset, ie A, CNAME, MX etc
+};
+
+#endif /* PDNS_COMMENT_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "common_startup.hh"
+#include "ws-auth.hh"
+#include "secpoll-auth.hh"
+#include <sys/time.h>
+#include <sys/resource.h>
+#include "dynhandler.hh"
+
+#ifdef HAVE_SYSTEMD
+#include <systemd/sd-daemon.h>
+#endif
+
+bool g_anyToTcp;
+bool g_8bitDNS;
+typedef Distributor<DNSPacket,DNSPacket,PacketHandler> DNSDistributor;
+
+ArgvMap theArg;
+StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
+PacketCache PC; //!< This is the main PacketCache, shared across all threads
+DNSProxy *DP;
+DynListener *dl;
+CommunicatorClass Communicator;
+shared_ptr<UDPNameserver> N;
+int avg_latency;
+TCPNameserver *TN;
+static vector<DNSDistributor*> g_distributors;
+vector<std::shared_ptr<UDPNameserver> > g_udpReceivers;
+AuthLua *LPE;
+
+ArgvMap &arg()
+{
+ return theArg;
+}
+
+void declareArguments()
+{
+ ::arg().set("local-port","The port on which we listen")="53";
+ ::arg().setSwitch("dnsupdate","Enable/Disable DNS update (RFC2136) support. Default is no.")="no";
+ ::arg().setSwitch("write-pid","Write a PID file")="yes";
+ ::arg().set("allow-dnsupdate-from","A global setting to allow DNS updates from these IP ranges.")="127.0.0.0/8,::1";
+ ::arg().set("allow-unsigned-notify","Allow unsigned notifications for TSIG secured domains")="yes"; //FIXME: change to 'no' later
+ ::arg().set("allow-unsigned-supermaster", "Allow supermasters to create zones without TSIG signed NOTIFY")="yes";
+ ::arg().setSwitch("forward-dnsupdate","A global setting to allow DNS update packages that are for a Slave domain, to be forwarded to the master.")="yes";
+ ::arg().setSwitch("log-dns-details","If PDNS should log DNS non-erroneous details")="no";
+ ::arg().setSwitch("log-dns-queries","If PDNS should log all incoming DNS queries")="no";
+ ::arg().set("local-address","Local IP addresses to which we bind")="0.0.0.0";
+ ::arg().setSwitch("local-address-nonexist-fail","Fail to start if one or more of the local-address's do not exist on this server")="yes";
+ ::arg().setSwitch("non-local-bind", "Enable binding to non-local addresses by using FREEBIND / BINDANY socket options")="no";
+ ::arg().set("local-ipv6","Local IP address to which we bind")="::";
+ ::arg().setSwitch("reuseport","Enable higher performance on compliant kernels by using SO_REUSEPORT allowing each receiver thread to open its own socket")="no";
+ ::arg().setSwitch("local-ipv6-nonexist-fail","Fail to start if one or more of the local-ipv6 addresses do not exist on this server")="yes";
+ ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
+ ::arg().set("query-local-address6","Source IPv6 address for sending queries")="::";
+ ::arg().set("overload-queue-length","Maximum queuelength moving to packetcache only")="0";
+ ::arg().set("max-queue-length","Maximum queuelength before considering situation lost")="5000";
+
+ ::arg().set("retrieval-threads", "Number of AXFR-retrieval threads for slave operation")="2";
+ ::arg().setSwitch("api", "Enable/disable the REST API")="no";
+ ::arg().set("api-key", "Static pre-shared authentication key for access to the REST API")="";
+ ::arg().set("api-logfile", "Location of the server logfile (used by the REST API)")="/var/log/pdns.log";
+ ::arg().setSwitch("api-readonly", "Disallow data modification through the REST API when set")="no";
+ ::arg().setSwitch("dname-processing", "If we should support DNAME records")="no";
+
+ ::arg().setCmd("help","Provide a helpful message");
+ ::arg().setCmd("version","Output version and compilation date");
+ ::arg().setCmd("config","Provide configuration file on standard output");
+ ::arg().setCmd("list-modules","Lists all modules available");
+ ::arg().setCmd("no-config","Don't parse configuration file");
+
+ ::arg().set("version-string","PowerDNS version in packets - full, anonymous, powerdns or custom")="full";
+ ::arg().set("control-console","Debugging switch - don't use")="no"; // but I know you will!
+ ::arg().set("loglevel","Amount of logging. Higher is more. Do not set below 3")="4";
+ ::arg().set("disable-syslog","Disable logging to syslog, useful when running inside a supervisor that logs stdout")="no";
+ ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
+ ::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
+ ::arg().set("distributor-threads","Default number of Distributor (backend) threads to start")="3";
+ ::arg().set("signing-threads","Default number of signer threads to start")="3";
+ ::arg().set("receiver-threads","Default number of receiver threads to start")="1";
+ ::arg().set("queue-limit","Maximum number of milliseconds to queue a query")="1500";
+ ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
+ ::arg().set("allow-recursion","List of subnets that are allowed to recurse")="0.0.0.0/0";
+ ::arg().set("udp-truncation-threshold", "Maximum UDP response size before we truncate")="1680";
+ ::arg().set("disable-tcp","Do not listen to TCP queries")="no";
+
+ ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
+
+ ::arg().set("load-modules","Load this module - supply absolute or relative path")="";
+ ::arg().set("launch","Which backends to launch and order to query them in")="";
+ ::arg().setSwitch("disable-axfr","Disable zonetransfers but do allow TCP queries")="no";
+ ::arg().set("allow-axfr-ips","Allow zonetransfers only to these subnets")="127.0.0.0/8,::1";
+ ::arg().set("only-notify", "Only send AXFR NOTIFY to these IP addresses or netmasks")="0.0.0.0/0,::/0";
+ ::arg().set("also-notify", "When notifying a domain, also notify these nameservers")="";
+ ::arg().set("allow-notify-from","Allow AXFR NOTIFY from these IP ranges. If empty, drop all incoming notifies.")="0.0.0.0/0,::/0";
+ ::arg().set("slave-cycle-interval","Schedule slave freshness checks once every .. seconds")="60";
+
+ ::arg().set("tcp-control-address","If set, PowerDNS can be controlled over TCP on this address")="";
+ ::arg().set("tcp-control-port","If set, PowerDNS can be controlled over TCP on this address")="53000";
+ ::arg().set("tcp-control-secret","If set, PowerDNS can be controlled over TCP after passing this secret")="";
+ ::arg().set("tcp-control-range","If set, remote control of PowerDNS is possible over these networks only")="127.0.0.0/8, 10.0.0.0/8, 192.168.0.0/16, 172.16.0.0/12, ::1/128, fe80::/10";
+
+ ::arg().setSwitch("slave","Act as a slave")="no";
+ ::arg().setSwitch("master","Act as a master")="no";
+ ::arg().setSwitch("disable-axfr-rectify","Disable the rectify step during an outgoing AXFR. Only required for regression testing.")="no";
+ ::arg().setSwitch("guardian","Run within a guardian process")="no";
+ ::arg().setSwitch("prevent-self-notification","Don't send notifications to what we think is ourself")="yes";
+ ::arg().setSwitch("webserver","Start a webserver for monitoring")="no";
+ ::arg().setSwitch("webserver-print-arguments","If the webserver should print arguments")="no";
+ ::arg().setSwitch("edns-subnet-processing","If we should act on EDNS Subnet options")="no";
+ ::arg().setSwitch("any-to-tcp","Answer ANY queries with tc=1, shunting to TCP")="yes";
+ ::arg().set("webserver-address","IP Address of webserver to listen on")="127.0.0.1";
+ ::arg().set("webserver-port","Port of webserver to listen on")="8081";
+ ::arg().set("webserver-password","Password required for accessing the webserver")="";
+ ::arg().set("webserver-allow-from","Webserver access is only allowed from these subnets")="0.0.0.0/0,::/0";
+
+ ::arg().setSwitch("out-of-zone-additional-processing","Do out of zone additional processing")="yes";
+ ::arg().setSwitch("do-ipv6-additional-processing", "Do AAAA additional processing")="yes";
+ ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
+
+ ::arg().set("carbon-ourname", "If set, overrides our reported hostname for carbon stats")="";
+ ::arg().set("carbon-server", "If set, send metrics in carbon (graphite) format to this server IP address")="";
+ ::arg().set("carbon-interval", "Number of seconds between carbon (graphite) updates")="30";
+
+ ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
+ ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
+ ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
+ ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
+ ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
+ ::arg().set("server-id", "Returned when queried for 'server.id' TXT or NSID, defaults to hostname - disabled or custom")="";
+ ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
+ ::arg().set("soa-retry-default","Default SOA retry")="3600";
+ ::arg().set("soa-expire-default","Default SOA expire")="604800";
+ ::arg().set("default-soa-edit","Default SOA-EDIT value")="";
+ ::arg().set("default-soa-edit-signed","Default SOA-EDIT value for signed zones")="";
+ ::arg().set("dnssec-key-cache-ttl","Seconds to cache DNSSEC keys from the database")="30";
+ ::arg().set("domain-metadata-cache-ttl","Seconds to cache domain metadata from the database")="60";
+
+ ::arg().set("trusted-notification-proxy", "IP address of incoming notification proxy")="";
+ ::arg().set("slave-renotify", "If we should send out notifications for slaved updates")="no";
+
+ ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
+ ::arg().set("max-tcp-connections","Maximum number of TCP connections")="20";
+ ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
+
+ ::arg().set("setuid","If set, change user id to this uid for more security")="";
+ ::arg().set("setgid","If set, change group id to this gid for more security")="";
+
+ ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
+ ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
+ ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
+ ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
+
+ ::arg().set("lua-prequery-script", "Lua script with prequery handler (DO NOT USE)")="";
+ ::arg().set("experimental-lua-policy-script", "Lua script for the policy engine")="";
+
+ ::arg().setSwitch("traceback-handler","Enable the traceback handler (Linux only)")="yes";
+ ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
+ ::arg().set("default-ksk-algorithms","Default KSK algorithms")="ecdsa256";
+ ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
+ ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="";
+ ::arg().set("default-zsk-size","Default ZSK size (0 means default)")="0";
+ ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
+
+ ::arg().set("include-dir","Include *.conf files from this directory");
+ ::arg().set("security-poll-suffix","Domain name from which to query security update notifications")="secpoll.powerdns.com.";
+
+ ::arg().setSwitch("outgoing-axfr-expand-alias", "Expand ALIAS records during outgoing AXFR")="no";
+ ::arg().setSwitch("8bit-dns", "Allow 8bit dns queries")="no";
+ ::arg().setSwitch("axfr-lower-serial", "Also AXFR a zone from a master with a lower serial")="no";
+
+ ::arg().set("lua-axfr-script", "Script to be used to edit incoming AXFRs")="";
+ ::arg().set("xfr-max-received-mbytes", "Maximum number of megabytes received from an incoming XFR")="100";
+}
+
+static time_t s_start=time(0);
+static uint64_t uptimeOfProcess(const std::string& str)
+{
+ return time(0) - s_start;
+}
+
+static uint64_t getSysUserTimeMsec(const std::string& str)
+{
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+
+ if(str=="sys-msec") {
+ return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
+ }
+ else
+ return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
+
+}
+
+static uint64_t getQCount(const std::string& str)
+try
+{
+ int totcount=0;
+ for(DNSDistributor* d : g_distributors) {
+ if(!d)
+ continue;
+ totcount += d->getQueueSize(); // this does locking and other things, so don't get smart
+ }
+ return totcount;
+}
+catch(std::exception& e)
+{
+ L<<Logger::Error<<"Had error retrieving queue sizes: "<<e.what()<<endl;
+ return 0;
+}
+catch(PDNSException& e)
+{
+ L<<Logger::Error<<"Had error retrieving queue sizes: "<<e.reason<<endl;
+ return 0;
+}
+
+static uint64_t getLatency(const std::string& str)
+{
+ return avg_latency;
+}
+
+void declareStats(void)
+{
+ S.declare("udp-queries","Number of UDP queries received");
+ S.declare("udp-do-queries","Number of UDP queries received with DO bit");
+ S.declare("udp-answers","Number of answers sent out over UDP");
+ S.declare("udp-answers-bytes","Total size of answers sent out over UDP");
+ S.declare("udp4-answers-bytes","Total size of answers sent out over UDPv4");
+ S.declare("udp6-answers-bytes","Total size of answers sent out over UDPv6");
+
+ S.declare("udp4-answers","Number of IPv4 answers sent out over UDP");
+ S.declare("udp4-queries","Number of IPv4 UDP queries received");
+ S.declare("udp6-answers","Number of IPv6 answers sent out over UDP");
+ S.declare("udp6-queries","Number of IPv6 UDP queries received");
+ S.declare("overload-drops","Queries dropped because backends overloaded");
+
+ S.declare("rd-queries", "Number of recursion desired questions");
+ S.declare("recursion-unanswered", "Number of packets unanswered by configured recursor");
+ S.declare("recursing-answers","Number of recursive answers sent out");
+ S.declare("recursing-questions","Number of questions sent to recursor");
+ S.declare("corrupt-packets","Number of corrupt packets received");
+ S.declare("signatures", "Number of DNSSEC signatures made");
+ S.declare("tcp-queries","Number of TCP queries received");
+ S.declare("tcp-answers","Number of answers sent out over TCP");
+ S.declare("tcp-answers-bytes","Total size of answers sent out over TCP");
+ S.declare("tcp4-answers-bytes","Total size of answers sent out over TCPv4");
+ S.declare("tcp6-answers-bytes","Total size of answers sent out over TCPv6");
+
+ S.declare("tcp4-queries","Number of IPv4 TCP queries received");
+ S.declare("tcp4-answers","Number of IPv4 answers sent out over TCP");
+
+ S.declare("tcp6-queries","Number of IPv6 TCP queries received");
+ S.declare("tcp6-answers","Number of IPv6 answers sent out over TCP");
+
+
+ S.declare("qsize-q","Number of questions waiting for database attention", getQCount);
+
+ S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
+ S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
+
+ S.declare("query-cache-hit","Number of hits on the query cache");
+ S.declare("query-cache-miss","Number of misses on the query cache");
+
+ S.declare("dnsupdate-queries", "DNS update packets received.");
+ S.declare("dnsupdate-answers", "DNS update packets successfully answered.");
+ S.declare("dnsupdate-refused", "DNS update packets that are refused.");
+ S.declare("dnsupdate-changes", "DNS update changes to records in total.");
+
+ S.declare("incoming-notifications", "NOTIFY packets received.");
+
+ S.declare("uptime", "Uptime of process in seconds", uptimeOfProcess);
+ S.declare("real-memory-usage", "Actual unique use of memory in bytes (approx)", getRealMemoryUsage);
+ S.declare("fd-usage", "Number of open filedescriptors", getOpenFileDescriptors);
+#ifdef __linux__
+ S.declare("udp-recvbuf-errors", "UDP 'recvbuf' errors", udpErrorStats);
+ S.declare("udp-sndbuf-errors", "UDP 'sndbuf' errors", udpErrorStats);
+ S.declare("udp-noport-errors", "UDP 'noport' errors", udpErrorStats);
+ S.declare("udp-in-errors", "UDP 'in' errors", udpErrorStats);
+#endif
+
+ S.declare("sys-msec", "Number of msec spent in system time", getSysUserTimeMsec);
+ S.declare("user-msec", "Number of msec spent in user time", getSysUserTimeMsec);
+ S.declare("meta-cache-size", "Number of entries in the metadata cache", DNSSECKeeper::dbdnssecCacheSizes);
+ S.declare("key-cache-size", "Number of entries in the key cache", DNSSECKeeper::dbdnssecCacheSizes);
+ S.declare("signature-cache-size", "Number of entries in the signature cache", signatureCacheSize);
+
+ S.declare("servfail-packets","Number of times a server-failed packet was sent out");
+ S.declare("latency","Average number of microseconds needed to answer a question", getLatency);
+ S.declare("timedout-packets","Number of packets which weren't answered within timeout set");
+ S.declare("security-status", "Security status based on regular polling");
+ S.declareRing("queries","UDP Queries Received");
+ S.declareRing("nxdomain-queries","Queries for non-existent records within existent domains");
+ S.declareRing("noerror-queries","Queries for existing records, but for type we don't have");
+ S.declareRing("servfail-queries","Queries that could not be answered due to backend errors");
+ S.declareRing("unauth-queries","Queries for domains that we are not authoritative for");
+ S.declareRing("logmessages","Log Messages");
+ S.declareComboRing("remotes","Remote server IP addresses");
+ S.declareComboRing("remotes-unauth","Remote hosts querying domains for which we are not auth");
+ S.declareComboRing("remotes-corrupt","Remote hosts sending corrupt packets");
+}
+
+int isGuarded(char **argv)
+{
+ char *p=strstr(argv[0],"-instance");
+
+ return !!p;
+}
+
+void sendout(DNSPacket* a)
+{
+ if(!a)
+ return;
+
+ N->send(a);
+
+ int diff=a->d_dt.udiff();
+ avg_latency=(int)(0.999*avg_latency+0.001*diff);
+ delete a;
+}
+
+//! The qthread receives questions over the internet via the Nameserver class, and hands them to the Distributor for further processing
+void *qthread(void *number)
+{
+ DNSPacket *P;
+ DNSDistributor *distributor = DNSDistributor::Create(::arg().asNum("distributor-threads", 1)); // the big dispatcher!
+ int num = (int)(unsigned long)number;
+ g_distributors[num] = distributor;
+ DNSPacket question(true);
+ DNSPacket cached(false);
+
+ AtomicCounter &numreceived=*S.getPointer("udp-queries");
+ AtomicCounter &numreceiveddo=*S.getPointer("udp-do-queries");
+
+ AtomicCounter &numreceived4=*S.getPointer("udp4-queries");
+
+ AtomicCounter &numreceived6=*S.getPointer("udp6-queries");
+ AtomicCounter &overloadDrops=*S.getPointer("overload-drops");
+
+ int diff;
+ bool logDNSQueries = ::arg().mustDo("log-dns-queries");
+ bool doRecursion = ::arg().mustDo("recursor");
+ shared_ptr<UDPNameserver> NS;
+
+ // If we have SO_REUSEPORT then create a new port for all receiver threads
+ // other than the first one.
+ if( number != NULL && N->canReusePort() ) {
+ NS = g_udpReceivers[num];
+ if (NS == nullptr) {
+ NS = N;
+ }
+ } else {
+ NS = N;
+ }
+
+ for(;;) {
+ if(!(P=NS->receive(&question))) { // receive a packet inline
+ continue; // packet was broken, try again
+ }
+
+ numreceived++;
+
+ if(P->d_remote.getSocklen()==sizeof(sockaddr_in))
+ numreceived4++;
+ else
+ numreceived6++;
+
+ if(P->d_dnssecOk)
+ numreceiveddo++;
+
+ if(P->d.qr)
+ continue;
+
+ S.ringAccount("queries", P->qdomain.toLogString()+"/"+P->qtype.getName());
+ S.ringAccount("remotes",P->d_remote);
+ if(logDNSQueries) {
+ string remote;
+ if(P->hasEDNSSubnet())
+ remote = P->getRemote().toString() + "<-" + P->getRealRemote().toString();
+ else
+ remote = P->getRemote().toString();
+ L << Logger::Notice<<"Remote "<< remote <<" wants '" << P->qdomain<<"|"<<P->qtype.getName() <<
+ "', do = " <<P->d_dnssecOk <<", bufsize = "<< P->getMaxReplyLen()<<": ";
+ }
+
+ if((P->d.opcode != Opcode::Notify && P->d.opcode != Opcode::Update) && P->couldBeCached()) {
+ bool haveSomething = false;
+ if (doRecursion && P->d.rd && DP->recurseFor(P))
+ haveSomething=PC.get(P, &cached, true); // does the PacketCache recognize this ruestion (recursive)?
+ if (!haveSomething)
+ haveSomething=PC.get(P, &cached, false); // does the PacketCache recognize this question?
+ if (haveSomething) {
+ if(logDNSQueries)
+ L<<"packetcache HIT"<<endl;
+ cached.setRemote(&P->d_remote); // inlined
+ cached.setSocket(P->getSocket()); // inlined
+ cached.d_anyLocal = P->d_anyLocal;
+ cached.setMaxReplyLen(P->getMaxReplyLen());
+ cached.d.rd=P->d.rd; // copy in recursion desired bit
+ cached.d.id=P->d.id;
+ cached.commitD(); // commit d to the packet inlined
+
+ int policyres = PolicyDecision::PASS;
+ if(LPE)
+ {
+ // FIXME: cached does not have qdomainwild/qdomainzone because packetcache entries
+ // go through tostring/noparse
+ policyres = LPE->police(&question, &cached);
+ }
+
+ if (policyres == PolicyDecision::PASS) {
+ NS->send(&cached); // answer it then inlined
+ diff=P->d_dt.udiff();
+ avg_latency=(int)(0.999*avg_latency+0.001*diff); // 'EWMA'
+ }
+ // FIXME implement truncate
+
+ continue;
+ }
+ }
+
+ if(distributor->isOverloaded()) {
+ if(logDNSQueries)
+ L<<"Dropped query, backends are overloaded"<<endl;
+ overloadDrops++;
+ continue;
+ }
+
+ if(logDNSQueries)
+ L<<"packetcache MISS"<<endl;
+
+ try {
+ distributor->question(P, &sendout); // otherwise, give to the distributor
+ }
+ catch(DistributorFatal& df) { // when this happens, we have leaked loads of memory. Bailing out time.
+ _exit(1);
+ }
+ }
+ return 0;
+}
+
+static void* dummyThread(void *)
+{
+ void* ignore=0;
+ pthread_exit(ignore);
+}
+
+static void triggerLoadOfLibraries()
+{
+ pthread_t tid;
+ pthread_create(&tid, 0, dummyThread, 0);
+ void* res;
+ pthread_join(tid, &res);
+}
+
+void mainthread()
+{
+ Utility::srandom(time(0) ^ getpid());
+
+ int newgid=0;
+ if(!::arg()["setgid"].empty())
+ newgid=Utility::makeGidNumeric(::arg()["setgid"]);
+ int newuid=0;
+ if(!::arg()["setuid"].empty())
+ newuid=Utility::makeUidNumeric(::arg()["setuid"]);
+
+ g_anyToTcp = ::arg().mustDo("any-to-tcp");
+ g_8bitDNS = ::arg().mustDo("8bit-dns");
+
+ DNSPacket::s_udpTruncationThreshold = std::max(512, ::arg().asNum("udp-truncation-threshold"));
+ DNSPacket::s_doEDNSSubnetProcessing = ::arg().mustDo("edns-subnet-processing");
+
+ stubParseResolveConf();
+
+ if(!::arg()["chroot"].empty()) {
+ triggerLoadOfLibraries();
+ if(::arg().mustDo("master") || ::arg().mustDo("slave"))
+ gethostbyname("a.root-servers.net"); // this forces all lookup libraries to be loaded
+ Utility::dropGroupPrivs(newuid, newgid);
+ if(chroot(::arg()["chroot"].c_str())<0 || chdir("/")<0) {
+ L<<Logger::Error<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror(errno)<<", exiting"<<endl;
+ exit(1);
+ }
+ else
+ L<<Logger::Error<<"Chrooted to '"<<::arg()["chroot"]<<"'"<<endl;
+ } else {
+ Utility::dropGroupPrivs(newuid, newgid);
+ }
+
+ AuthWebServer webserver;
+ Utility::dropUserPrivs(newuid);
+
+ // We need to start the Recursor Proxy before doing secpoll, see issue #2453
+ if(::arg().mustDo("recursor")){
+ DP=new DNSProxy(::arg()["recursor"]);
+ DP->onlyFrom(::arg()["allow-recursion"]);
+ DP->go();
+ }
+
+ try {
+ doSecPoll(true);
+ }
+ catch(...) {}
+
+ // NOW SAFE TO CREATE THREADS!
+ dl->go();
+
+ pthread_t qtid;
+
+ if(::arg().mustDo("webserver"))
+ webserver.go();
+
+ if(::arg().mustDo("slave") || ::arg().mustDo("master"))
+ Communicator.go();
+
+ if(!::arg()["experimental-lua-policy-script"].empty()){
+ LPE=new AuthLua(::arg()["experimental-lua-policy-script"]);
+ L<<Logger::Warning<<"Loaded Lua policy script "<<::arg()["experimental-lua-policy-script"]<<endl;
+ }
+
+ if(TN)
+ TN->go(); // tcp nameserver launch
+
+ // fork(); (this worked :-))
+ unsigned int max_rthreads= ::arg().asNum("receiver-threads", 1);
+ g_distributors.resize(max_rthreads);
+ for(unsigned int n=0; n < max_rthreads; ++n)
+ pthread_create(&qtid,0,qthread, reinterpret_cast<void *>(n)); // receives packets
+
+ pthread_create(&qtid,0,carbonDumpThread, 0); // runs even w/o carbon, might change @ runtime
+
+#ifdef HAVE_SYSTEMD
+ /* If we are here, notify systemd that we are ay-ok! This might have some
+ * timing issues with the backend-threads. e.g. if the initial MySQL connection
+ * is slow and times out (leading to process termination through the backend)
+ * We probably have told systemd already that we have started correctly.
+ */
+ sd_notify(0, "READY=1");
+#endif
+
+ for(;;) {
+ sleep(1800);
+ try {
+ doSecPoll(false);
+ }
+ catch(...){}
+ }
+
+ L<<Logger::Error<<"Mainthread exiting - should never happen"<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef COMMON_STARTUP_HH
+#define COMMON_STARTUP_HH
+
+#include "packetcache.hh"
+#include "utility.hh"
+#include "arguments.hh"
+#include "communicator.hh"
+#include "distributor.hh"
+#include "dnspacket.hh"
+#include "dnsproxy.hh"
+#include "dynlistener.hh"
+#include "nameserver.hh"
+#include "statbag.hh"
+#include "tcpreceiver.hh"
+
+extern ArgvMap theArg;
+extern StatBag S; //!< Statistics are gathered across PDNS via the StatBag class S
+extern PacketCache PC; //!< This is the main PacketCache, shared across all threads
+extern DNSProxy *DP;
+extern DynListener *dl;
+extern CommunicatorClass Communicator;
+extern std::shared_ptr<UDPNameserver> N;
+extern vector<std::shared_ptr<UDPNameserver> > g_udpReceivers;
+extern int avg_latency;
+extern TCPNameserver *TN;
+extern AuthLua *LPE;
+extern ArgvMap & arg( void );
+extern void declareArguments();
+extern void declareStats();
+extern void mainthread();
+extern int isGuarded( char ** );
+void* carbonDumpThread(void*);
+extern bool g_anyToTcp;
+extern bool g_8bitDNS;
+
+#endif // COMMON_STARTUP_HH
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include <errno.h>
+#include "communicator.hh"
+#include <set>
+#include <boost/utility.hpp>
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "packethandler.hh"
+#include "resolver.hh"
+#include "logger.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include "packetcache.hh"
+
+// there can be MANY OF THESE
+void CommunicatorClass::retrievalLoopThread(void)
+{
+ for(;;) {
+ d_suck_sem.wait();
+ SuckRequest sr;
+ {
+ Lock l(&d_lock);
+ if(d_suckdomains.empty())
+ continue;
+
+ sr=d_suckdomains.front();
+ d_suckdomains.pop_front();
+ }
+ suck(sr.domain, sr.master);
+ }
+}
+
+void CommunicatorClass::go()
+{
+ try {
+ PacketHandler::s_allowNotifyFrom.toMasks(::arg()["allow-notify-from"] );
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"Unparseable IP in allow-notify-from. Error: "<<e.reason<<endl;
+ exit(1);
+ }
+
+ pthread_t tid;
+ pthread_create(&tid,0,&launchhelper,this); // Starts CommunicatorClass::mainloop()
+ for(int n=0; n < ::arg().asNum("retrieval-threads", 1); ++n)
+ pthread_create(&tid, 0, &retrieveLaunchhelper, this); // Starts CommunicatorClass::retrievalLoopThread()
+
+ d_preventSelfNotification = ::arg().mustDo("prevent-self-notification");
+
+ try {
+ d_onlyNotify.toMasks(::arg()["only-notify"]);
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"Unparseable IP in only-notify. Error: "<<e.reason<<endl;
+ exit(1);
+ }
+
+ vector<string> parts;
+ stringtok(parts, ::arg()["also-notify"], ", \t");
+ for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter) {
+ try {
+ ComboAddress caIp(*iter, 53);
+ d_alsoNotify.insert(caIp.toStringWithPort());
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"Unparseable IP in also-notify. Error: "<<e.reason<<endl;
+ exit(1);
+ }
+ }
+}
+
+void CommunicatorClass::mainloop(void)
+{
+ try {
+ signal(SIGPIPE,SIG_IGN);
+ L<<Logger::Error<<"Master/slave communicator launching"<<endl;
+ PacketHandler P;
+ d_tickinterval=::arg().asNum("slave-cycle-interval");
+ makeNotifySockets();
+
+ int rc;
+ time_t next, tick;
+
+ for(;;) {
+ slaveRefresh(&P);
+ masterUpdateCheck(&P);
+ tick=doNotifications(); // this processes any notification acknowledgements and actually send out our own notifications
+
+ tick = min (tick, d_tickinterval);
+
+ next=time(0)+tick;
+
+ while(time(0) < next) {
+ rc=d_any_sem.tryWait();
+
+ if(rc)
+ Utility::sleep(1);
+ else {
+ break; // something happened
+ }
+ // this gets executed at least once every second
+ doNotifications();
+ }
+ }
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"Exiting because communicator thread died with error: "<<ae.reason<<endl;
+ Utility::sleep(1);
+ exit(1);
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"Exiting because communicator thread died with STL error: "<<e.what()<<endl;
+ exit(1);
+ }
+ catch( ... )
+ {
+ L << Logger::Error << "Exiting because communicator caught unknown exception." << endl;
+ exit(1);
+ }
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_COMMUNICATOR_HH
+#define PDNS_COMMUNICATOR_HH
+
+#include <pthread.h>
+#include <string>
+#include <semaphore.h>
+#include <queue>
+#include <list>
+#include <limits>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/identity.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/scoped_ptr.hpp>
+using namespace boost::multi_index;
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <netdb.h>
+
+#include "lock.hh"
+#include "packethandler.hh"
+
+#include "namespaces.hh"
+#include "dns_random.hh"
+
+struct SuckRequest
+{
+ DNSName domain;
+ string master;
+ bool operator<(const SuckRequest& b) const
+ {
+ return tie(domain, master) < tie(b.domain, b.master);
+ }
+};
+
+struct IDTag{};
+
+typedef multi_index_container<
+ SuckRequest,
+ indexed_by<
+ sequenced<>,
+ ordered_unique<tag<IDTag>, identity<SuckRequest> >
+ >
+> UniQueue;
+typedef UniQueue::index<IDTag>::type domains_by_name_t;
+
+class NotificationQueue
+{
+public:
+ void add(const DNSName &domain, const string &ip)
+ {
+ const ComboAddress caIp(ip);
+
+ NotificationRequest nr;
+ nr.domain = domain;
+ nr.ip = caIp.toStringWithPort();
+ nr.attempts = 0;
+ nr.id = dns_random(0xffff);
+ nr.next = time(0);
+
+ d_nqueue.push_back(nr);
+ }
+
+ bool removeIf(const string &remote, uint16_t id, const DNSName &domain)
+ {
+ ServiceTuple stRemote, stQueued;
+ parseService(remote, stRemote);
+
+ for(d_nqueue_t::iterator i=d_nqueue.begin(); i!=d_nqueue.end(); ++i) {
+ parseService(i->ip, stQueued);
+ if(i->id==id && stQueued.host == stRemote.host && i->domain==domain) {
+ d_nqueue.erase(i);
+ return true;
+ }
+ }
+ return false;
+ }
+
+ bool getOne(DNSName &domain, string &ip, uint16_t *id, bool &purged)
+ {
+ for(d_nqueue_t::iterator i=d_nqueue.begin();i!=d_nqueue.end();++i)
+ if(i->next <= time(0)) {
+ i->attempts++;
+ purged=false;
+ i->next=time(0)+1+(1<<i->attempts);
+ domain=i->domain;
+ ip=i->ip;
+ *id=i->id;
+ purged=false;
+ if(i->attempts>4) {
+ purged=true;
+ d_nqueue.erase(i);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ time_t earliest()
+ {
+ time_t early=std::numeric_limits<time_t>::max() - 1;
+ for(d_nqueue_t::const_iterator i=d_nqueue.begin();i!=d_nqueue.end();++i)
+ early=min(early,i->next);
+ return early-time(0);
+ }
+
+ void dump();
+
+private:
+ struct NotificationRequest
+ {
+ DNSName domain;
+ string ip;
+ time_t next;
+ int attempts;
+ uint16_t id;
+ };
+
+ typedef std::list<NotificationRequest> d_nqueue_t;
+ d_nqueue_t d_nqueue;
+
+};
+
+struct ZoneStatus;
+
+/** this class contains a thread that communicates with other nameserver and does housekeeping.
+ Initially, it is notified only of zones that need to be pulled in because they have been updated. */
+
+class CommunicatorClass
+{
+public:
+ CommunicatorClass()
+ {
+ pthread_mutex_init(&d_lock,0);
+ pthread_mutex_init(&d_holelock,0);
+
+ d_tickinterval=60;
+ d_masterschanged=d_slaveschanged=true;
+ d_nsock4 = -1;
+ d_nsock6 = -1;
+ d_havepriosuckrequest = false;
+ d_preventSelfNotification = false;
+ }
+ time_t doNotifications();
+ void go();
+
+
+ void drillHole(const DNSName &domain, const string &ip);
+ bool justNotified(const DNSName &domain, const string &ip);
+ void addSuckRequest(const DNSName &domain, const string &master);
+ void addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote);
+ void addTrySuperMasterRequest(DNSPacket *p);
+ void notify(const DNSName &domain, const string &ip);
+ void mainloop();
+ void retrievalLoopThread();
+ void sendNotification(int sock, const DNSName &domain, const ComboAddress& remote, uint16_t id);
+
+ static void *launchhelper(void *p)
+ {
+ static_cast<CommunicatorClass *>(p)->mainloop();
+ return 0;
+ }
+ static void *retrieveLaunchhelper(void *p)
+ {
+ static_cast<CommunicatorClass *>(p)->retrievalLoopThread();
+ return 0;
+ }
+ bool notifyDomain(const DNSName &domain);
+private:
+ void makeNotifySockets();
+ void queueNotifyDomain(const DNSName &domain, UeberBackend *B);
+ int d_nsock4, d_nsock6;
+ map<pair<DNSName,string>,time_t>d_holes;
+ pthread_mutex_t d_holelock;
+ void launchRetrievalThreads();
+ void suck(const DNSName &domain, const string &remote);
+ void ixfrSuck(const DNSName &domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, boost::scoped_ptr<AuthLua>& pdl,
+ ZoneStatus& zs, vector<DNSRecord>* axfr);
+
+ void slaveRefresh(PacketHandler *P);
+ void masterUpdateCheck(PacketHandler *P);
+ pthread_mutex_t d_lock;
+
+ UniQueue d_suckdomains;
+ set<DNSName> d_inprogress;
+
+ Semaphore d_suck_sem;
+ Semaphore d_any_sem;
+ time_t d_tickinterval;
+ set<DomainInfo> d_tocheck;
+ vector<DNSPacket> d_potentialsupermasters;
+ set<string> d_alsoNotify;
+ NotificationQueue d_nq;
+ NetmaskGroup d_onlyNotify;
+ bool d_havepriosuckrequest;
+ bool d_masterschanged, d_slaveschanged;
+ bool d_preventSelfNotification;
+
+ struct RemoveSentinel
+ {
+ explicit RemoveSentinel(const DNSName& dn, CommunicatorClass* cc) : d_dn(dn), d_cc(cc)
+ {}
+
+ ~RemoveSentinel()
+ {
+ try {
+ Lock l(&d_cc->d_lock);
+ d_cc->d_inprogress.erase(d_dn);
+ }
+ catch(...) {
+ }
+ }
+ DNSName d_dn;
+ CommunicatorClass* d_cc;
+};
+
+};
+
+// class that one day might be more than a function to help you get IP addresses for a nameserver
+class FindNS
+{
+public:
+ vector<string> lookup(const DNSName &name, DNSBackend *b)
+ {
+ vector<string> addresses;
+
+ this->resolve_name(&addresses, name);
+
+ if(b) {
+ b->lookup(QType(QType::ANY),name);
+ DNSResourceRecord rr;
+ while(b->get(rr))
+ if(rr.qtype.getCode() == QType::A || rr.qtype.getCode()==QType::AAAA)
+ addresses.push_back(rr.content); // SOL if you have a CNAME for an NS
+ }
+ return addresses;
+ }
+
+ vector<string> lookup(const DNSName &name, UeberBackend *b)
+ {
+ vector<string> addresses;
+
+ this->resolve_name(&addresses, name);
+
+ if(b) {
+ b->lookup(QType(QType::ANY),name);
+ DNSResourceRecord rr;
+ while(b->get(rr))
+ if(rr.qtype.getCode() == QType::A || rr.qtype.getCode()==QType::AAAA)
+ addresses.push_back(rr.content); // SOL if you have a CNAME for an NS
+ }
+ return addresses;
+ }
+
+private:
+ void resolve_name(vector<string>* addresses, const DNSName& name)
+ {
+ struct addrinfo* res;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+
+ for(int n = 0; n < 2; ++n) {
+ hints.ai_family = n ? AF_INET : AF_INET6;
+ ComboAddress remote;
+ remote.sin4.sin_family = AF_INET6;
+ if(!getaddrinfo(name.toString().c_str(), 0, &hints, &res)) {
+ struct addrinfo* address = res;
+ do {
+ if (address->ai_addrlen <= sizeof(remote)) {
+ memcpy(&remote, address->ai_addr, address->ai_addrlen);
+ addresses->push_back(remote.toString());
+ }
+ } while((address = address->ai_next));
+ freeaddrinfo(res);
+ }
+ }
+ }
+};
+
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsseckeeper.hh"
+#include "dnssecinfra.hh"
+#include "ueberbackend.hh"
+#include "statbag.hh"
+#include <iostream>
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <fstream>
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+#include <boost/assign/std/vector.hpp> // for 'operator+=()'
+#include <boost/assign/list_inserter.hpp>
+#include "base64.hh"
+#include "cachecleaner.hh"
+#include "arguments.hh"
+
+
+using namespace boost::assign;
+#include "namespaces.hh"
+
+
+DNSSECKeeper::keycache_t DNSSECKeeper::s_keycache;
+DNSSECKeeper::metacache_t DNSSECKeeper::s_metacache;
+pthread_rwlock_t DNSSECKeeper::s_metacachelock = PTHREAD_RWLOCK_INITIALIZER;
+pthread_rwlock_t DNSSECKeeper::s_keycachelock = PTHREAD_RWLOCK_INITIALIZER;
+AtomicCounter DNSSECKeeper::s_ops;
+time_t DNSSECKeeper::s_last_prune;
+
+bool DNSSECKeeper::doesDNSSEC()
+{
+ return d_keymetadb->doesDNSSEC();
+}
+
+bool DNSSECKeeper::isSecuredZone(const DNSName& zone)
+{
+ if(isPresigned(zone))
+ return true;
+
+ keyset_t keys = getKeys(zone); // does the cache
+
+ for(keyset_t::value_type& val : keys) {
+ if(val.second.active) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool DNSSECKeeper::isPresigned(const DNSName& name)
+{
+ string meta;
+ getFromMeta(name, "PRESIGNED", meta);
+ return meta=="1";
+}
+
+bool DNSSECKeeper::addKey(const DNSName& name, bool setSEPBit, int algorithm, int bits, bool active)
+{
+ if(!bits) {
+ if(algorithm <= 10)
+ throw runtime_error("Creating an algorithm " +std::to_string(algorithm)+" ("+algorithm2name(algorithm)+") key requires the size (in bits) to be passed");
+ else {
+ if(algorithm == 12 || algorithm == 13 || algorithm == 15) // GOST, ECDSAP256SHA256, ED25519
+ bits = 256;
+ else if(algorithm == 14) // ECDSAP384SHA384
+ bits = 384;
+ else if(algorithm == 16) // ED448
+ bits = 456;
+ else {
+ throw runtime_error("Can't guess key size for algorithm "+std::to_string(algorithm));
+ }
+ }
+ }
+ DNSSECPrivateKey dspk;
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm));
+ dpk->create(bits);
+ dspk.setKey(dpk);
+ dspk.d_algorithm = algorithm;
+ dspk.d_flags = setSEPBit ? 257 : 256;
+ return addKey(name, dspk, active);
+}
+
+void DNSSECKeeper::clearAllCaches() {
+ {
+ WriteLock l(&s_keycachelock);
+ s_keycache.clear();
+ }
+ WriteLock l(&s_metacachelock);
+ s_metacache.clear();
+}
+
+void DNSSECKeeper::clearCaches(const DNSName& name)
+{
+ {
+ WriteLock l(&s_keycachelock);
+ s_keycache.erase(name);
+ }
+ WriteLock l(&s_metacachelock);
+ pair<metacache_t::iterator, metacache_t::iterator> range = s_metacache.equal_range(tie(name));
+ while(range.first != range.second)
+ s_metacache.erase(range.first++);
+}
+
+
+bool DNSSECKeeper::addKey(const DNSName& name, const DNSSECPrivateKey& dpk, bool active)
+{
+ clearCaches(name);
+ DNSBackend::KeyData kd;
+ kd.flags = dpk.d_flags; // the dpk doesn't get stored, only they key part
+ kd.active = active;
+ kd.content = dpk.getKey()->convertToISC();
+ // now store it
+ return d_keymetadb->addDomainKey(name, kd) >= 0; // >= 0 == s
+}
+
+
+static bool keyCompareByKindAndID(const DNSSECKeeper::keyset_t::value_type& a, const DNSSECKeeper::keyset_t::value_type& b)
+{
+ return make_pair(!a.second.keyType, a.second.id) <
+ make_pair(!b.second.keyType, b.second.id);
+}
+
+DNSSECPrivateKey DNSSECKeeper::getKeyById(const DNSName& zname, unsigned int id)
+{
+ vector<DNSBackend::KeyData> keys;
+ d_keymetadb->getDomainKeys(zname, 0, keys);
+ for(const DNSBackend::KeyData& kd : keys) {
+ if(kd.id != id)
+ continue;
+
+ DNSSECPrivateKey dpk;
+ DNSKEYRecordContent dkrc;
+ dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
+ dpk.d_flags = kd.flags;
+ dpk.d_algorithm = dkrc.d_algorithm;
+
+ if(dpk.d_algorithm == 5 && getNSEC3PARAM(zname)) {
+ dpk.d_algorithm += 2;
+ }
+
+ return dpk;
+ }
+ throw runtime_error("Can't find a key with id "+std::to_string(id)+" for zone '"+zname.toString()+"'");
+}
+
+
+bool DNSSECKeeper::removeKey(const DNSName& zname, unsigned int id)
+{
+ clearCaches(zname);
+ return d_keymetadb->removeDomainKey(zname, id);
+}
+
+bool DNSSECKeeper::deactivateKey(const DNSName& zname, unsigned int id)
+{
+ clearCaches(zname);
+ return d_keymetadb->deactivateDomainKey(zname, id);
+}
+
+bool DNSSECKeeper::activateKey(const DNSName& zname, unsigned int id)
+{
+ clearCaches(zname);
+ return d_keymetadb->activateDomainKey(zname, id);
+}
+
+
+void DNSSECKeeper::getFromMeta(const DNSName& zname, const std::string& key, std::string& value)
+{
+ static int ttl = ::arg().asNum("domain-metadata-cache-ttl");
+ value.clear();
+ unsigned int now = time(0);
+
+ if(!((++s_ops) % 100000)) {
+ cleanup();
+ }
+
+ if (ttl > 0) {
+ ReadLock l(&s_metacachelock);
+
+ metacache_t::const_iterator iter = s_metacache.find(tie(zname, key));
+ if(iter != s_metacache.end() && iter->d_ttd > now) {
+ value = iter->d_value;
+ return;
+ }
+ }
+ vector<string> meta;
+ d_keymetadb->getDomainMetadata(zname, key, meta);
+ if(!meta.empty())
+ value=*meta.begin();
+
+ if (ttl > 0) {
+ METACacheEntry nce;
+ nce.d_domain=zname;
+ nce.d_ttd = now + ttl;
+ nce.d_key= key;
+ nce.d_value = value;
+ {
+ WriteLock l(&s_metacachelock);
+ replacing_insert(s_metacache, nce);
+ }
+ }
+}
+
+void DNSSECKeeper::getSoaEdit(const DNSName& zname, std::string& value)
+{
+ static const string soaEdit(::arg()["default-soa-edit"]);
+ static const string soaEditSigned(::arg()["default-soa-edit-signed"]);
+
+ getFromMeta(zname, "SOA-EDIT", value);
+
+ if ((!soaEdit.empty() || !soaEditSigned.empty()) && value.empty() && !isPresigned(zname)) {
+ if (!soaEditSigned.empty() && isSecuredZone(zname))
+ value=soaEditSigned;
+ if (value.empty())
+ value=soaEdit;
+ }
+
+ return;
+}
+
+uint64_t DNSSECKeeper::dbdnssecCacheSizes(const std::string& str)
+{
+ if(str=="meta-cache-size") {
+ ReadLock l(&s_metacachelock);
+ return s_metacache.size();
+ }
+ else if(str=="key-cache-size") {
+ ReadLock l(&s_keycachelock);
+ return s_keycache.size();
+ }
+ return (uint64_t)-1;
+}
+
+bool DNSSECKeeper::getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* ns3p, bool* narrow)
+{
+ string value;
+ getFromMeta(zname, "NSEC3PARAM", value);
+ if(value.empty()) { // "no NSEC3"
+ return false;
+ }
+
+ static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
+ if(ns3p) {
+ *ns3p = NSEC3PARAMRecordContent(value);
+ if (ns3p->d_iterations > maxNSEC3Iterations) {
+ ns3p->d_iterations = maxNSEC3Iterations;
+ L<<Logger::Error<<"Number of NSEC3 iterations for zone '"<<zname<<"' is above 'max-nsec3-iterations'. Value adjusted to: "<<maxNSEC3Iterations<<endl;
+ }
+ if (ns3p->d_algorithm != 1) {
+ L<<Logger::Error<<"Invalid hash algorithm for NSEC3: '"<<std::to_string(ns3p->d_algorithm)<<"', setting to 1 for zone '"<<zname<<"'."<<endl;
+ ns3p->d_algorithm = 1;
+ }
+ }
+ if(narrow) {
+ getFromMeta(zname, "NSEC3NARROW", value);
+ *narrow = (value=="1");
+ }
+ return true;
+}
+
+bool DNSSECKeeper::setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& ns3p, const bool& narrow)
+{
+ static int maxNSEC3Iterations=::arg().asNum("max-nsec3-iterations");
+ if (ns3p.d_iterations > maxNSEC3Iterations)
+ throw runtime_error("Can't set NSEC3PARAM for zone '"+zname.toString()+"': number of NSEC3 iterations is above 'max-nsec3-iterations'");
+
+ if (ns3p.d_algorithm != 1)
+ throw runtime_error("Invalid hash algorithm for NSEC3: '"+std::to_string(ns3p.d_algorithm)+"' for zone '"+zname.toString()+"'. The only valid value is '1'");
+
+ clearCaches(zname);
+ string descr = ns3p.getZoneRepresentation();
+ vector<string> meta;
+ meta.push_back(descr);
+ if (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", meta)) {
+ meta.clear();
+
+ if(narrow)
+ meta.push_back("1");
+
+ return d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", meta);
+ }
+ return false;
+}
+
+bool DNSSECKeeper::unsetNSEC3PARAM(const DNSName& zname)
+{
+ clearCaches(zname);
+ return (d_keymetadb->setDomainMetadata(zname, "NSEC3PARAM", vector<string>()) && d_keymetadb->setDomainMetadata(zname, "NSEC3NARROW", vector<string>()));
+}
+
+
+bool DNSSECKeeper::setPresigned(const DNSName& zname)
+{
+ clearCaches(zname);
+ vector<string> meta;
+ meta.push_back("1");
+ return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", meta);
+}
+
+bool DNSSECKeeper::unsetPresigned(const DNSName& zname)
+{
+ clearCaches(zname);
+ return d_keymetadb->setDomainMetadata(zname, "PRESIGNED", vector<string>());
+}
+
+/**
+ * Add domainmetadata to allow publishing CDS records for zone zname
+ *
+ * @param zname DNSName of the zone
+ * @param digestAlgos string with comma-separated numbers that describe the
+ * used digest algorithms. This is copied to the database
+ * verbatim
+ * @return true if the data was inserted, false otherwise
+ */
+bool DNSSECKeeper::setPublishCDS(const DNSName& zname, const string& digestAlgos)
+{
+ clearCaches(zname);
+ vector<string> meta;
+ meta.push_back(digestAlgos);
+ return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", meta);
+}
+
+/**
+ * Remove domainmetadata to stop publishing CDS records for zone zname
+ *
+ * @param zname DNSName of the zone
+ * @return true if the operation was successful, false otherwise
+ */
+bool DNSSECKeeper::unsetPublishCDS(const DNSName& zname)
+{
+ clearCaches(zname);
+ return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDS", vector<string>());
+}
+
+/**
+ * Add domainmetadata to allow publishing CDNSKEY records.for zone zname
+ *
+ * @param zname DNSName of the zone
+ * @return true if the data was inserted, false otherwise
+ */
+bool DNSSECKeeper::setPublishCDNSKEY(const DNSName& zname)
+{
+ clearCaches(zname);
+ vector<string> meta;
+ meta.push_back("1");
+ return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", meta);
+}
+
+/**
+ * Remove domainmetadata to stop publishing CDNSKEY records for zone zname
+ *
+ * @param zname DNSName of the zone
+ * @return true if the operation was successful, false otherwise
+ */
+bool DNSSECKeeper::unsetPublishCDNSKEY(const DNSName& zname)
+{
+ clearCaches(zname);
+ return d_keymetadb->setDomainMetadata(zname, "PUBLISH-CDNSKEY", vector<string>());
+}
+
+/**
+ * Returns all keys that are used to sign the DNSKEY RRSet in a zone
+ *
+ * @param zname DNSName of the zone
+ * @return a keyset_t with all keys that are used to sign the DNSKEY
+ * RRSet (these are the entrypoint(s) to the zone)
+ */
+DNSSECKeeper::keyset_t DNSSECKeeper::getEntryPoints(const DNSName& zname)
+{
+ DNSSECKeeper::keyset_t ret;
+ DNSSECKeeper::keyset_t keys = getKeys(zname);
+
+ for(auto const &keymeta : keys)
+ if(keymeta.second.active && (keymeta.second.keyType == KSK || keymeta.second.keyType == CSK))
+ ret.push_back(keymeta);
+ return ret;
+}
+
+DNSSECKeeper::keyset_t DNSSECKeeper::getKeys(const DNSName& zone, bool useCache)
+{
+ static int ttl = ::arg().asNum("dnssec-key-cache-ttl");
+ unsigned int now = time(0);
+
+ if(!((++s_ops) % 100000)) {
+ cleanup();
+ }
+
+ if (useCache && ttl > 0) {
+ ReadLock l(&s_keycachelock);
+ keycache_t::const_iterator iter = s_keycache.find(zone);
+
+ if(iter != s_keycache.end() && iter->d_ttd > now) {
+ keyset_t ret;
+ for(const keyset_t::value_type& value : iter->d_keys)
+ ret.push_back(value);
+ return ret;
+ }
+ }
+
+ keyset_t retkeyset;
+ vector<DNSBackend::KeyData> dbkeyset;
+
+ d_keymetadb->getDomainKeys(zone, 0, dbkeyset);
+
+ // Determine the algorithms that have a KSK/ZSK split
+ set<uint8_t> algoSEP, algoNoSEP;
+ vector<uint8_t> algoHasSeparateKSK;
+ for(const DNSBackend::KeyData &keydata : dbkeyset) {
+ DNSSECPrivateKey dpk;
+ DNSKEYRecordContent dkrc;
+
+ dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content)));
+
+ if(keydata.active) {
+ if(keydata.flags == 257)
+ algoSEP.insert(dkrc.d_algorithm);
+ else
+ algoNoSEP.insert(dkrc.d_algorithm);
+ }
+ }
+ set_intersection(algoSEP.begin(), algoSEP.end(), algoNoSEP.begin(), algoNoSEP.end(), std::back_inserter(algoHasSeparateKSK));
+
+ for(DNSBackend::KeyData& kd : dbkeyset)
+ {
+ DNSSECPrivateKey dpk;
+ DNSKEYRecordContent dkrc;
+
+ dpk.setKey(shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content)));
+
+ dpk.d_flags = kd.flags;
+ dpk.d_algorithm = dkrc.d_algorithm;
+ if(dpk.d_algorithm == 5 && getNSEC3PARAM(zone))
+ dpk.d_algorithm+=2;
+
+ KeyMetaData kmd;
+
+ kmd.active = kd.active;
+ kmd.hasSEPBit = (kd.flags == 257);
+ kmd.id = kd.id;
+
+ if (find(algoHasSeparateKSK.begin(), algoHasSeparateKSK.end(), dpk.d_algorithm) == algoHasSeparateKSK.end())
+ kmd.keyType = CSK;
+ else if(kmd.hasSEPBit)
+ kmd.keyType = KSK;
+ else
+ kmd.keyType = ZSK;
+
+ retkeyset.push_back(make_pair(dpk, kmd));
+ }
+ sort(retkeyset.begin(), retkeyset.end(), keyCompareByKindAndID);
+
+ if (ttl > 0) {
+ KeyCacheEntry kce;
+ kce.d_domain=zone;
+ kce.d_keys = retkeyset;
+ kce.d_ttd = now + ttl;
+ {
+ WriteLock l(&s_keycachelock);
+ replacing_insert(s_keycache, kce);
+ }
+ }
+
+ return retkeyset;
+}
+
+bool DNSSECKeeper::checkKeys(const DNSName& zone)
+{
+ vector<DNSBackend::KeyData> dbkeyset;
+ d_keymetadb->getDomainKeys(zone, 0, dbkeyset);
+
+ for(const DNSBackend::KeyData &keydata : dbkeyset) {
+ DNSKEYRecordContent dkrc;
+ shared_ptr<DNSCryptoKeyEngine> dke(DNSCryptoKeyEngine::makeFromISCString(dkrc, keydata.content));
+ if (!dke->checkKey()) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DNSSECKeeper::getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname,
+ const DNSName& wildcardname, const QType& qtype,
+ DNSResourceRecord::Place signPlace, vector<DNSResourceRecord>& rrsigs, uint32_t signTTL)
+{
+ // cerr<<"Doing DB lookup for precomputed RRSIGs for '"<<(wildcardname.empty() ? qname : wildcardname)<<"'"<<endl;
+ SOAData sd;
+ if(!db.getSOAUncached(signer, sd)) {
+ DLOG(L<<"Could not get SOA for domain"<<endl);
+ return false;
+ }
+ db.lookup(QType(QType::RRSIG), wildcardname.countLabels() ? wildcardname : qname, NULL, sd.domain_id);
+ DNSResourceRecord rr;
+ while(db.get(rr)) {
+ // cerr<<"Considering for '"<<qtype.getName()<<"' RRSIG '"<<rr.content<<"'\n";
+ vector<string> parts;
+ stringtok(parts, rr.content);
+ if(parts[0] == qtype.getName() && DNSName(parts[7])==signer) {
+ // cerr<<"Got it"<<endl;
+ if (wildcardname.countLabels())
+ rr.qname = qname;
+ rr.d_place = signPlace;
+ rr.ttl = signTTL;
+ rrsigs.push_back(rr);
+ }
+ // else cerr<<"Skipping!"<<endl;
+ }
+ return true;
+}
+
+bool DNSSECKeeper::TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname)
+{
+ vector<string> allowed;
+
+ d_keymetadb->getDomainMetadata(zone, "TSIG-ALLOW-AXFR", allowed);
+
+ for(const string& dbkey : allowed) {
+ if(DNSName(dbkey)==keyname)
+ return true;
+ }
+ return false;
+}
+
+bool DNSSECKeeper::getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname)
+{
+ vector<string> keynames;
+ d_keymetadb->getDomainMetadata(zone, "AXFR-MASTER-TSIG", keynames);
+ keyname->trimToLabels(0);
+
+ // XXX FIXME this should check for a specific master!
+ for(const string& dbkey : keynames) {
+ *keyname=DNSName(dbkey);
+ return true;
+ }
+ return false;
+}
+
+void DNSSECKeeper::cleanup()
+{
+ struct timeval now;
+ Utility::gettimeofday(&now, 0);
+
+ if(now.tv_sec - s_last_prune > (time_t)(30)) {
+ {
+ WriteLock l(&s_metacachelock);
+ pruneCollection(s_metacache, ::arg().asNum("max-cache-entries"));
+ }
+ {
+ WriteLock l(&s_keycachelock);
+ pruneCollection(s_keycache, ::arg().asNum("max-cache-entries"));
+ }
+ s_last_prune=time(0);
+ }
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <decaf.hxx>
+#include <decaf/eddsa.hxx>
+#include <decaf/spongerng.hxx>
+
+#include "dnssecinfra.hh"
+
+using namespace decaf;
+
+class DecafED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit DecafED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+
+ }
+ string getName() const override { return "Decaf ED25519"; }
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& msg) const override;
+ bool verify(const std::string& msg, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<DecafED25519DNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned char d_pubkey[DECAF_EDDSA_25519_PUBLIC_BYTES];
+ unsigned char d_seckey[DECAF_EDDSA_25519_PRIVATE_BYTES];
+};
+
+void DecafED25519DNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if(bits != (unsigned int)getBits()) {
+ throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED25519 class");
+ }
+
+ SpongeRng rng("/dev/urandom");
+
+ typename EdDSA<IsoEd25519>::PrivateKey priv(rng);
+ typename EdDSA<IsoEd25519>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+int DecafED25519DNSCryptoKeyEngine::getBits() const
+{
+ return DECAF_EDDSA_25519_PRIVATE_BYTES << 3;
+}
+
+DNSCryptoKeyEngine::storvector_t DecafED25519DNSCryptoKeyEngine::convertToISCVector() const
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+ */
+
+ storvector_t storvector;
+
+ storvector.push_back(make_pair("Algorithm", "15 (ED25519)"));
+ storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES)));
+
+ return storvector;
+}
+
+void DecafED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=
+ */
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey = stormap["privatekey"];
+
+ if (privateKey.length() != DECAF_EDDSA_25519_PRIVATE_BYTES)
+ throw runtime_error("Private key size mismatch in ISCMap, DecafED25519 class");
+
+ typename EdDSA<IsoEd25519>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_25519_PRIVATE_BYTES));
+ typename EdDSA<IsoEd25519>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::getPubKeyHash() const
+{
+ return this->getPublicKeyString();
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::getPublicKeyString() const
+{
+ return string((char*)d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES);
+}
+
+void DecafED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ if (input.length() != DECAF_EDDSA_25519_PUBLIC_BYTES)
+ throw runtime_error("Public key size mismatch, DecafED25519 class");
+
+ memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_25519_PUBLIC_BYTES);
+}
+
+std::string DecafED25519DNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ typename EdDSA<IsoEd25519>::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_25519_PRIVATE_BYTES));
+
+ SecureBuffer message(msg.begin(), msg.end());
+
+ SecureBuffer sig = priv.sign(message);
+
+ return string(sig.begin(), sig.end());
+}
+
+bool DecafED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != DECAF_EDDSA_25519_SIGNATURE_BYTES)
+ return false;
+
+ typename EdDSA<IsoEd25519>::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_25519_PUBLIC_BYTES));
+
+ SecureBuffer sig(signature.begin(), signature.end());
+ SecureBuffer message(msg.begin(), msg.end());
+
+ try {
+ pub.verify(sig, message);
+ } catch(CryptoException) {
+ return false;
+ }
+
+ return true;
+}
+
+
+class DecafED448DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit DecafED448DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+
+ }
+ string getName() const override { return "Decaf ED448"; }
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& msg) const override;
+ bool verify(const std::string& msg, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<DecafED448DNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned char d_pubkey[DECAF_EDDSA_448_PUBLIC_BYTES];
+ unsigned char d_seckey[DECAF_EDDSA_448_PRIVATE_BYTES];
+};
+
+void DecafED448DNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if(bits != (unsigned int)getBits()) {
+ throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, DecafED448 class");
+ }
+
+ SpongeRng rng("/dev/urandom");
+
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(rng);
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+int DecafED448DNSCryptoKeyEngine::getBits() const
+{
+ return DECAF_EDDSA_448_PRIVATE_BYTES << 3;
+}
+
+DNSCryptoKeyEngine::storvector_t DecafED448DNSCryptoKeyEngine::convertToISCVector() const
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 16 (ED448)
+ PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
+ */
+
+ storvector_t storvector;
+
+ storvector.push_back(make_pair("Algorithm", "16 (ED448)"));
+ storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES)));
+
+ return storvector;
+}
+
+void DecafED448DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 16 (ED448)
+ PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA
+ */
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey = stormap["privatekey"];
+
+ if (privateKey.length() != DECAF_EDDSA_448_PRIVATE_BYTES)
+ throw runtime_error("Private key size mismatch in ISCMap, DecafED448 class");
+
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(Block((const unsigned char*)privateKey.c_str(), DECAF_EDDSA_448_PRIVATE_BYTES));
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(priv);
+
+ priv.serialize_into(d_seckey);
+ pub.serialize_into(d_pubkey);
+}
+
+std::string DecafED448DNSCryptoKeyEngine::getPubKeyHash() const
+{
+ return this->getPublicKeyString();
+}
+
+std::string DecafED448DNSCryptoKeyEngine::getPublicKeyString() const
+{
+ return string((char*)d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES);
+}
+
+void DecafED448DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ if (input.length() != DECAF_EDDSA_448_PUBLIC_BYTES)
+ throw runtime_error("Public key size mismatch, DecafED448 class");
+
+ memcpy(d_pubkey, input.c_str(), DECAF_EDDSA_448_PUBLIC_BYTES);
+}
+
+std::string DecafED448DNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ typename EdDSA<Ed448Goldilocks>::PrivateKey priv(Block(d_seckey, DECAF_EDDSA_448_PRIVATE_BYTES));
+
+ SecureBuffer message(msg.begin(), msg.end());
+
+ SecureBuffer sig = priv.sign(message);
+
+ return string(sig.begin(), sig.end());
+}
+
+bool DecafED448DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != DECAF_EDDSA_448_SIGNATURE_BYTES)
+ return false;
+
+ typename EdDSA<Ed448Goldilocks>::PublicKey pub(Block(d_pubkey, DECAF_EDDSA_448_PUBLIC_BYTES));
+
+ SecureBuffer sig(signature.begin(), signature.end());
+ SecureBuffer message(msg.begin(), msg.end());
+
+ try {
+ pub.verify(sig, message);
+ } catch(CryptoException) {
+ return false;
+ }
+
+ return true;
+}
+
+
+namespace {
+struct LoaderDecafStruct
+{
+ LoaderDecafStruct()
+ {
+ DNSCryptoKeyEngine::report(15, &DecafED25519DNSCryptoKeyEngine::maker, true);
+ DNSCryptoKeyEngine::report(16, &DecafED448DNSCryptoKeyEngine::maker);
+ }
+} loaderdecaf;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "delaypipe.hh"
+#include "misc.hh"
+#include "gettime.hh"
+#include <thread>
+
+template<class T>
+ObjectPipe<T>::ObjectPipe()
+{
+ if(pipe(d_fds))
+ unixDie("pipe");
+}
+
+template<class T>
+ObjectPipe<T>::~ObjectPipe()
+{
+ ::close(d_fds[0]);
+ if(d_fds[1] >= 0)
+ ::close(d_fds[1]);
+}
+
+template<class T>
+void ObjectPipe<T>::close()
+{
+ if(d_fds[1] < 0)
+ return;
+ ::close(d_fds[1]); // the writing side
+ d_fds[1]=-1;
+}
+
+template<class T>
+void ObjectPipe<T>::write(T& t)
+{
+ auto ptr = new T(t);
+ if(::write(d_fds[1], &ptr, sizeof(ptr)) != sizeof(ptr)) {
+ delete ptr;
+ unixDie("write");
+ }
+}
+
+template<class T>
+bool ObjectPipe<T>::read(T* t)
+{
+ T* ptr;
+ int ret = ::read(d_fds[0], &ptr, sizeof(ptr));
+
+ if(ret < 0)
+ unixDie("read");
+ if(ret==0)
+ return false;
+ if(ret != sizeof(ptr))
+ throw std::runtime_error("Partial read, should not happen");
+ *t=*ptr;
+ delete ptr;
+ return true;
+}
+
+template<class T>
+int ObjectPipe<T>::readTimeout(T* t, double msec)
+{
+ T* ptr;
+
+ int ret = waitForData(d_fds[0], 0, 1000*msec);
+ if(ret < 0)
+ unixDie("waiting for data in object pipe");
+ if(ret == 0)
+ return -1;
+
+ ret = ::read(d_fds[0], &ptr, sizeof(ptr)); // this is BLOCKING!
+
+ if(ret < 0)
+ unixDie("read");
+ if(ret==0)
+ return false;
+ if(ret != sizeof(ptr))
+ throw std::runtime_error("Partial read, should not happen 2");
+ *t=*ptr;
+ delete ptr;
+ return 1;
+}
+
+
+template<class T>
+DelayPipe<T>::DelayPipe() : d_thread(&DelayPipe<T>::worker, this)
+{
+}
+
+template<class T>
+void DelayPipe<T>::gettime(struct timespec* ts)
+{
+ ::gettime(ts);
+}
+
+
+template<class T>
+void DelayPipe<T>::submit(T& t, int msec)
+{
+ struct timespec now;
+ gettime(&now);
+ now.tv_nsec += msec*1e6;
+ while(now.tv_nsec > 1e9) {
+ now.tv_sec++;
+ now.tv_nsec-=1e9;
+ }
+ Combo c{t, now};
+ d_pipe.write(c);
+}
+
+template<class T>
+DelayPipe<T>::~DelayPipe()
+{
+ d_pipe.close();
+ d_thread.join();
+}
+
+
+
+template<class T>
+void DelayPipe<T>::worker()
+{
+ Combo c;
+ for(;;) {
+ /* this code is slightly too subtle, but I don't see how it could be any simpler.
+ So we have a set of work to do, and we need to wait until the time arrives to do it.
+ Simultaneously new work might come in. So we try to combine both of these things by
+ setting a timeout on listening to the pipe over which new work comes in. This timeout
+ is equal to the wait until the first thing that needs to be done.
+
+ Two additional cases exist: we have no work to wait for, so we can wait infinitely long.
+ The other special case is that the first we have to do.. is in the past, so we need to do it
+ immediately. */
+
+
+ double delay=-1; // infinite
+ struct timespec now;
+ if(!d_work.empty()) {
+ gettime(&now);
+ delay=1000*tsdelta(d_work.begin()->first, now);
+ if(delay < 0) {
+ delay=0; // don't wait - we have work that is late already!
+ }
+ }
+ if(delay != 0 ) {
+ int ret = d_pipe.readTimeout(&c, delay);
+ if(ret > 0) { // we got an object
+ d_work.insert(make_pair(c.when, c.what));
+ }
+ else if(ret==0) { // EOF
+ break;
+ }
+ else {
+ ;
+ }
+ gettime(&now);
+ }
+
+ tscomp cmp;
+
+ for(auto iter = d_work.begin() ; iter != d_work.end(); ) { // do the needful
+ if(cmp(iter->first, now)) {
+ iter->second();
+ d_work.erase(iter++);
+ }
+ else {
+ break;
+ }
+ }
+ }
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <map>
+#include <time.h>
+#include <thread>
+
+/**
+ General idea: many threads submit work to this class, but only one executes it. The work should therefore be entirely trivial.
+ The implementatin is that submitter threads create an object that represents the work, and it gets sent over a pipe
+ to the worker thread.
+
+ The worker thread meanwhile listens on this pipe (non-blocking), with a delay set to the next object that needs to be executed.
+ If meanwhile new work comes in, all objects who's time has come are executed, a new sleep time is calculated.
+*/
+
+
+/* ObjectPipe facilitates the type-safe passing of types over a pipe */
+
+template<class T>
+class ObjectPipe
+{
+public:
+ ObjectPipe();
+ ~ObjectPipe();
+ void write(T& t);
+ bool read(T* t); // returns false on EOF
+ int readTimeout(T* t, double msec); //!< -1 is timeout, 0 is no data, 1 is data. msec<0 waits infinitely wrong. msec==0 = undefined
+ void close();
+private:
+ int d_fds[2];
+};
+
+template<class T>
+class DelayPipe
+{
+public:
+ DelayPipe();
+ ~DelayPipe();
+ void submit(T& t, int msec); //!< don't try for more than 4294 msec
+
+private:
+ void worker();
+ struct Combo
+ {
+ T what;
+ struct timespec when;
+ };
+
+ double tsdelta(const struct timespec& a, const struct timespec& b) // read as a-b
+ {
+ return 1.0*(a.tv_sec-b.tv_sec)+1.0*(a.tv_nsec-b.tv_nsec)/1000000000.0;
+ }
+
+ ObjectPipe<Combo> d_pipe;
+ struct tscomp {
+ bool operator()(const struct timespec& a, const struct timespec& b) const
+ {
+ return std::tie(a.tv_sec, a.tv_nsec) < std::tie(b.tv_sec, b.tv_nsec);
+ }
+ };
+ std::multimap<struct timespec, T, tscomp> d_work;
+ void gettime(struct timespec* ts);
+ std::thread d_thread;
+};
+
+#include "delaypipe.cc"
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef DISTRIBUTOR_HH
+#define DISTRIBUTOR_HH
+
+#include <string>
+#include <deque>
+#include <queue>
+#include <vector>
+#include <pthread.h>
+#include <unistd.h>
+#include "logger.hh"
+#include "dns.hh"
+#include "dnsbackend.hh"
+#include "pdnsexception.hh"
+#include "arguments.hh"
+#include <atomic>
+#include "statbag.hh"
+
+extern StatBag S;
+
+/** the Distributor template class enables you to multithread slow question/answer
+ processes.
+
+ Questions are posed to the Distributor, which returns the answer via a callback.
+
+ The Distributor spawns sufficient backends, and if they thrown an exception,
+ it will cycle the backend but drop the query that was active during the exception.
+*/
+
+template<class Answer, class Question, class Backend> class Distributor
+{
+public:
+ static Distributor *Create(int n=1); //!< Create a new Distributor with \param n threads
+ typedef std::function<void(Answer*)> callback_t;
+ virtual int question(Question *, callback_t callback) =0; //!< Submit a question to the Distributor
+ virtual int getQueueSize() =0; //!< Returns length of question queue
+ virtual bool isOverloaded() =0;
+};
+
+template<class Answer, class Question, class Backend> class SingleThreadDistributor
+ : public Distributor<Answer, Question, Backend>
+{
+public:
+ SingleThreadDistributor();
+ typedef std::function<void(Answer*)> callback_t;
+ int question(Question *, callback_t callback) override; //!< Submit a question to the Distributor
+ int getQueueSize() override {
+ return 0;
+ }
+
+ bool isOverloaded() override
+ {
+ return false;
+ }
+
+ ~SingleThreadDistributor() {
+ if (b) delete b;
+ }
+private:
+ Backend *b{0};
+};
+
+template<class Answer, class Question, class Backend> class MultiThreadDistributor
+ : public Distributor<Answer, Question, Backend>
+{
+public:
+ MultiThreadDistributor(int n);
+ typedef std::function<void(Answer*)> callback_t;
+ int question(Question *, callback_t callback) override; //!< Submit a question to the Distributor
+ static void* makeThread(void *); //!< helper function to create our n threads
+ int getQueueSize() override {
+ return d_queued;
+ }
+
+ struct QuestionData
+ {
+ Question *Q;
+ callback_t callback;
+ int id;
+ };
+
+ bool isOverloaded() override
+ {
+ return d_overloadQueueLength && (d_queued > d_overloadQueueLength);
+ }
+
+private:
+ int nextid;
+ time_t d_last_started;
+ unsigned int d_overloadQueueLength, d_maxQueueLength;
+ int d_num_threads;
+ std::atomic<unsigned int> d_queued{0}, d_running{0};
+ std::vector<std::pair<int,int>> d_pipes;
+};
+
+//template<class Answer, class Question, class Backend>::nextid;
+template<class Answer, class Question, class Backend>Distributor<Answer,Question,Backend>* Distributor<Answer,Question,Backend>::Create(int n)
+{
+ if( n == 1 )
+ return new SingleThreadDistributor<Answer,Question,Backend>();
+ else
+ return new MultiThreadDistributor<Answer,Question,Backend>( n );
+}
+
+template<class Answer, class Question, class Backend>SingleThreadDistributor<Answer,Question,Backend>::SingleThreadDistributor()
+{
+ L<<Logger::Error<<"Only asked for 1 backend thread - operating unthreaded"<<endl;
+ try {
+ b=new Backend;
+ }
+ catch(const PDNSException &AE) {
+ L<<Logger::Error<<"Distributor caught fatal exception: "<<AE.reason<<endl;
+ exit(1);
+ }
+ catch(...) {
+ L<<Logger::Error<<"Caught an unknown exception when creating backend, probably"<<endl;
+ exit(1);
+ }
+}
+
+template<class Answer, class Question, class Backend>MultiThreadDistributor<Answer,Question,Backend>::MultiThreadDistributor(int n)
+{
+ d_num_threads=n;
+ d_overloadQueueLength=::arg().asNum("overload-queue-length");
+ d_maxQueueLength=::arg().asNum("max-queue-length");
+ nextid=0;
+ d_last_started=time(0);
+
+ pthread_t tid;
+
+
+ for(int i=0; i < n; ++i) {
+ int fds[2];
+ if(pipe(fds) < 0)
+ unixDie("Creating pipe");
+ d_pipes.push_back({fds[0],fds[1]});
+ }
+
+ if (n<1) {
+ L<<Logger::Error<<"Asked for fewer than 1 threads, nothing to do"<<endl;
+ exit(1);
+ }
+
+ L<<Logger::Warning<<"About to create "<<n<<" backend threads for UDP"<<endl;
+ for(int i=0;i<n;i++) {
+ pthread_create(&tid,0,&makeThread,static_cast<void *>(this));
+ Utility::usleep(50000); // we've overloaded mysql in the past :-)
+ }
+ L<<Logger::Warning<<"Done launching threads, ready to distribute questions"<<endl;
+}
+
+
+// start of a new thread
+template<class Answer, class Question, class Backend>void *MultiThreadDistributor<Answer,Question,Backend>::makeThread(void *p)
+{
+ pthread_detach(pthread_self());
+ MultiThreadDistributor *us=static_cast<MultiThreadDistributor *>(p);
+ int ournum=us->d_running++;
+
+ try {
+ Backend *b=new Backend(); // this will answer our questions
+ int queuetimeout=::arg().asNum("queue-limit");
+
+ for(;;) {
+
+ QuestionData* QD;
+ if(read(us->d_pipes[ournum].first, &QD, sizeof(QD)) != sizeof(QD))
+ unixDie("read");
+ --us->d_queued;
+ Answer *a;
+
+ if(queuetimeout && QD->Q->d_dt.udiff()>queuetimeout*1000) {
+ delete QD->Q;
+ delete QD;
+ S.inc("timedout-packets");
+ continue;
+ }
+
+ bool allowRetry=true;
+retry:
+ // this is the only point where we interact with the backend (synchronous)
+ try {
+ if (!b) {
+ allowRetry=false;
+ b=new Backend();
+ }
+ a=b->question(QD->Q);
+ delete QD->Q;
+ }
+ catch(const PDNSException &e) {
+ delete b;
+ b=NULL;
+ if (!allowRetry) {
+ L<<Logger::Error<<"Backend error: "<<e.reason<<endl;
+ a=QD->Q->replyPacket();
+
+ a->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",QD->Q->qdomain.toLogString());
+
+ delete QD->Q;
+ } else {
+ L<<Logger::Error<<"Backend error (retry once): "<<e.reason<<endl;
+ goto retry;
+ }
+ }
+ catch(...) {
+ delete b;
+ b=NULL;
+ if (!allowRetry) {
+ L<<Logger::Error<<"Caught unknown exception in Distributor thread "<<(long)pthread_self()<<endl;
+ a=QD->Q->replyPacket();
+
+ a->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",QD->Q->qdomain.toLogString());
+
+ delete QD->Q;
+ } else {
+ L<<Logger::Error<<"Caught unknown exception in Distributor thread "<<(long)pthread_self()<<" (retry once)"<<endl;
+ goto retry;
+ }
+ }
+
+ QD->callback(a);
+ delete QD;
+ }
+
+ delete b;
+ }
+ catch(const PDNSException &AE) {
+ L<<Logger::Error<<"Distributor caught fatal exception: "<<AE.reason<<endl;
+ exit(1);
+ }
+ catch(...) {
+ L<<Logger::Error<<"Caught an unknown exception when creating backend, probably"<<endl;
+ exit(1);
+ }
+ return 0;
+}
+
+template<class Answer, class Question, class Backend>int SingleThreadDistributor<Answer,Question,Backend>::question(Question* q, callback_t callback)
+{
+ Answer *a;
+ bool allowRetry=true;
+retry:
+ try {
+ if (!b) {
+ allowRetry=false;
+ b=new Backend;
+ }
+ a=b->question(q); // a can be NULL!
+ }
+ catch(const PDNSException &e) {
+ delete b;
+ b=NULL;
+ if (!allowRetry) {
+ L<<Logger::Error<<"Backend error: "<<e.reason<<endl;
+ a=q->replyPacket();
+
+ a->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",q->qdomain.toLogString());
+ } else {
+ L<<Logger::Error<<"Backend error (retry once): "<<e.reason<<endl;
+ goto retry;
+ }
+ }
+ catch(...) {
+ delete b;
+ b=NULL;
+ if (!allowRetry) {
+ L<<Logger::Error<<"Caught unknown exception in Distributor thread "<<(unsigned long)pthread_self()<<endl;
+ a=q->replyPacket();
+
+ a->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",q->qdomain.toLogString());
+ } else {
+ L<<Logger::Error<<"Caught unknown exception in Distributor thread "<<(unsigned long)pthread_self()<<" (retry once)"<<endl;
+ goto retry;
+ }
+ }
+ callback(a);
+ return 0;
+}
+
+struct DistributorFatal{};
+
+template<class Answer, class Question, class Backend>int MultiThreadDistributor<Answer,Question,Backend>::question(Question* q, callback_t callback)
+{
+ q=new Question(*q);
+
+ // this is passed to other process over pipe and released there
+ auto QD=new QuestionData();
+ QD->Q=q;
+ auto ret = QD->id = nextid++; // might be deleted after write!
+ QD->callback=callback;
+
+ if(write(d_pipes[QD->id % d_pipes.size()].second, &QD, sizeof(QD)) != sizeof(QD))
+ unixDie("write");
+
+ d_queued++;
+
+
+
+ if(d_queued > d_maxQueueLength) {
+ L<<Logger::Error<< d_queued <<" questions waiting for database/backend attention. Limit is "<<::arg().asNum("max-queue-length")<<", respawning"<<endl;
+ // this will leak the entire contents of all pipes, nothing will be freed. Respawn when this happens!
+ throw DistributorFatal();
+ }
+
+ return ret;
+}
+
+#endif // DISTRIBUTOR_HH
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dns.hh"
+#include "misc.hh"
+#include <stdexcept>
+#include <iostream>
+#include <boost/algorithm/string.hpp>
+#include <boost/assign/list_of.hpp>
+#include "dnsparser.hh"
+
+std::vector<std::string> RCode::rcodes_s = boost::assign::list_of
+ ("No Error")
+ ("Form Error")
+ ("Server Failure")
+ ("Non-Existent domain")
+ ("Not Implemented")
+ ("Query Refused")
+ ("Name Exists when it should not")
+ ("RR Set Exists when it should not")
+ ("RR Set that should exist does not")
+ ("Server Not Authoritative for zone / Not Authorized")
+ ("Name not contained in zone")
+ ("Err#11")
+ ("Err#12")
+ ("Err#13")
+ ("Err#14")
+ ("Err#15")
+ ("Bad OPT Version / TSIG Signature Failure")
+ ("Key not recognized")
+ ("Signature out of time window")
+ ("Bad TKEY Mode")
+ ("Duplicate key name")
+ ("Algorithm not supported")
+ ("Bad Truncation")
+;
+
+std::string RCode::to_s(unsigned short rcode) {
+ if (rcode > RCode::rcodes_s.size()-1 )
+ return std::string("Err#")+std::to_string(rcode);
+ return RCode::rcodes_s[rcode];
+}
+
+class BoundsCheckingPointer
+{
+public:
+ explicit BoundsCheckingPointer(const char* a, size_t length)
+ : d_ptr(a), d_length(length)
+ {}
+
+ explicit BoundsCheckingPointer(const std::string& str)
+ : d_ptr(str.c_str()), d_length(str.size())
+ {}
+
+
+ char operator[](size_t offset) const
+ {
+ if(offset < d_length)
+ return d_ptr[offset];
+ throw runtime_error("out of bounds: "+std::to_string(offset)+" >= " + std::to_string(d_length));
+ }
+private:
+ const char* d_ptr;
+ const size_t d_length;
+};
+
+
+// goal is to hash based purely on the question name, and turn error into 'default'
+uint32_t hashQuestion(const char* packet, uint16_t len, uint32_t init)
+{
+ if(len < 12)
+ return init;
+
+ uint32_t ret=init;
+ const unsigned char* end = (const unsigned char*)packet+len;
+ const unsigned char* pos = (const unsigned char*)packet+12;
+
+ unsigned char labellen;
+ while((labellen=*pos++) && pos < end) {
+ if(pos + labellen + 1 > end) // include length field in hash
+ return 0;
+ ret=burtleCI(pos, labellen+1, ret);
+ pos += labellen;
+ }
+ return ret;
+}
+
+
+string& attodot(string &str)
+{
+ if(str.find_first_of("@")==string::npos)
+ return str;
+
+ for (unsigned int i = 0; i < str.length(); i++)
+ {
+ if (str[i] == '@') {
+ str[i] = '.';
+ break;
+ } else if (str[i] == '.') {
+ str.insert(i++, "\\");
+ }
+ }
+ return str;
+}
+
+vector<DNSResourceRecord> convertRRS(const vector<DNSRecord>& in)
+{
+ vector<DNSResourceRecord> out;
+ for(const auto& d : in) {
+ DNSResourceRecord rr;
+ rr.qname = d.d_name;
+ rr.qtype = QType(d.d_type);
+ rr.ttl = d.d_ttl;
+ rr.content = d.d_content->getZoneRepresentation();
+ rr.auth = false;
+ rr.qclass = d.d_class;
+ out.push_back(rr);
+ }
+ return out;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include "qtype.hh"
+#include "dnsname.hh"
+#include <time.h>
+#include <sys/types.h>
+class DNSBackend;
+
+struct SOAData
+{
+ SOAData() : ttl(0), serial(0), refresh(0), retry(0), expire(0), default_ttl(0), db(0), domain_id(-1), scopeMask(0) {};
+
+ DNSName qname;
+ DNSName nameserver;
+ DNSName hostmaster;
+ uint32_t ttl;
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t default_ttl;
+ DNSBackend *db;
+ int domain_id;
+ uint8_t scopeMask;
+};
+
+class RCode
+{
+public:
+ enum rcodes_ { NoError=0, FormErr=1, ServFail=2, NXDomain=3, NotImp=4, Refused=5, YXDomain=6, YXRRSet=7, NXRRSet=8, NotAuth=9, NotZone=10};
+ static std::string to_s(unsigned short rcode);
+ static std::vector<std::string> rcodes_s;
+};
+
+class Opcode
+{
+public:
+ enum { Query=0, IQuery=1, Status=2, Notify=4, Update=5 };
+};
+
+// enum for policy decisions, used by both auth and recursor. Not all values supported everywhere.
+namespace PolicyDecision { enum returnTypes { PASS=-1, DROP=-2, TRUNCATE=-3 }; };
+
+//! This class represents a resource record
+class DNSResourceRecord
+{
+public:
+ DNSResourceRecord() : last_modified(0), ttl(0), signttl(0), domain_id(-1), qclass(1), d_place(ANSWER), scopeMask(0), auth(1), disabled(0) {};
+ explicit DNSResourceRecord(const struct DNSRecord&);
+ ~DNSResourceRecord(){};
+
+ enum Place : uint8_t {QUESTION=0, ANSWER=1, AUTHORITY=2, ADDITIONAL=3}; //!< Type describing the positioning of a DNSResourceRecord within, say, a DNSPacket
+
+ void setContent(const string& content);
+ string getZoneRepresentation(bool noDot=false) const;
+
+ // data
+ DNSName qname; //!< the name of this record, for example: www.powerdns.com
+ DNSName wildcardname;
+ string content; //!< what this record points to. Example: 10.1.2.3
+
+ // Aligned on 8-byte boundries on systems where time_t is 8 bytes and int
+ // is 4 bytes, aka modern linux on x86_64
+ time_t last_modified; //!< For autocalculating SOA serial numbers - the backend needs to fill this in
+
+ uint32_t ttl; //!< Time To Live of this record
+ uint32_t signttl; //!< If non-zero, use this TTL as original TTL in the RRSIG
+
+ int domain_id; //!< If a backend implements this, the domain_id of the zone this record is in
+ QType qtype; //!< qtype of this record, ie A, CNAME, MX etc
+ uint16_t qclass; //!< class of this record
+
+ Place d_place; //!< This specifies where a record goes within the packet
+ uint8_t scopeMask;
+ bool auth;
+ bool disabled;
+
+ template<class Archive>
+ void serialize(Archive & ar, const unsigned int version)
+ {
+ ar & qtype;
+ ar & qclass;
+ ar & qname;
+ ar & wildcardname;
+ ar & content;
+ ar & ttl;
+ ar & domain_id;
+ ar & last_modified;
+ ar & d_place;
+ ar & auth;
+ ar & disabled;
+ }
+
+ bool operator==(const DNSResourceRecord& rhs);
+
+ bool operator<(const DNSResourceRecord &b) const
+ {
+ if(qname < b.qname)
+ return true;
+ if(qname == b.qname)
+ return(content < b.content);
+ return false;
+ }
+};
+
+#define GCCPACKATTRIBUTE __attribute__((packed))
+
+struct dnsrecordheader
+{
+ uint16_t d_type;
+ uint16_t d_class;
+ uint32_t d_ttl;
+ uint16_t d_clen;
+} GCCPACKATTRIBUTE;
+
+struct EDNS0Record
+{
+ uint8_t extRCode, version;
+ uint16_t Z;
+} GCCPACKATTRIBUTE;
+
+static_assert(sizeof(EDNS0Record) == 4, "EDNS0Record size must be 4");
+
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__DragonFly__) || defined(__FreeBSD_kernel__)
+#include <machine/endian.h>
+#elif __linux__ || __GNU__
+# include <endian.h>
+
+#else // with thanks to <arpa/nameser.h>
+
+# define LITTLE_ENDIAN 1234 /* least-significant byte first (vax, pc) */
+# define BIG_ENDIAN 4321 /* most-significant byte first (IBM, net) */
+# define PDP_ENDIAN 3412 /* LSB first in word, MSW first in long (pdp) */
+
+#if defined(vax) || defined(ns32000) || defined(sun386) || defined(i386) || \
+ defined(__i386) || defined(__ia64) || defined(__amd64) || \
+ defined(MIPSEL) || defined(_MIPSEL) || defined(BIT_ZERO_ON_RIGHT) || \
+ defined(__alpha__) || defined(__alpha) || \
+ (defined(__Lynx__) && defined(__x86__))
+# define BYTE_ORDER LITTLE_ENDIAN
+#endif
+
+#if defined(sel) || defined(pyr) || defined(mc68000) || defined(sparc) || \
+ defined(__sparc) || \
+ defined(is68k) || defined(tahoe) || defined(ibm032) || defined(ibm370) || \
+ defined(MIPSEB) || defined(_MIPSEB) || defined(_IBMR2) || defined(DGUX) ||\
+ defined(apollo) || defined(__convex__) || defined(_CRAY) || \
+ defined(__hppa) || defined(__hp9000) || \
+ defined(__hp9000s300) || defined(__hp9000s700) || \
+ defined(__hp3000s900) || defined(MPE) || \
+ defined(BIT_ZERO_ON_LEFT) || defined(m68k) || \
+ (defined(__Lynx__) && \
+ (defined(__68k__) || defined(__sparc__) || defined(__powerpc__)))
+# define BYTE_ORDER BIG_ENDIAN
+#endif
+
+#endif
+
+struct dnsheader {
+ unsigned id :16; /* query identification number */
+#if BYTE_ORDER == BIG_ENDIAN
+ /* fields in third byte */
+ unsigned qr: 1; /* response flag */
+ unsigned opcode: 4; /* purpose of message */
+ unsigned aa: 1; /* authoritative answer */
+ unsigned tc: 1; /* truncated message */
+ unsigned rd: 1; /* recursion desired */
+ /* fields in fourth byte */
+ unsigned ra: 1; /* recursion available */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned rcode :4; /* response code */
+#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+ /* fields in third byte */
+ unsigned rd :1; /* recursion desired */
+ unsigned tc :1; /* truncated message */
+ unsigned aa :1; /* authoritative answer */
+ unsigned opcode :4; /* purpose of message */
+ unsigned qr :1; /* response flag */
+ /* fields in fourth byte */
+ unsigned rcode :4; /* response code */
+ unsigned cd: 1; /* checking disabled by resolver */
+ unsigned ad: 1; /* authentic data from named */
+ unsigned unused :1; /* unused bits (MBZ as of 4.9.3a3) */
+ unsigned ra :1; /* recursion available */
+#endif
+ /* remaining bytes */
+ unsigned qdcount :16; /* number of question entries */
+ unsigned ancount :16; /* number of answer entries */
+ unsigned nscount :16; /* number of authority entries */
+ unsigned arcount :16; /* number of resource entries */
+};
+
+static_assert(sizeof(dnsheader) == 12, "dnsheader size must be 12");
+
+inline uint16_t * getFlagsFromDNSHeader(struct dnsheader * dh)
+{
+ return (uint16_t*) (((char *) dh) + sizeof(uint16_t));
+}
+
+#define DNS_TYPE_SIZE (2)
+#define DNS_CLASS_SIZE (2)
+#define DNS_TTL_SIZE (4)
+#define DNS_RDLENGTH_SIZE (2)
+#define EDNS_EXTENDED_RCODE_SIZE (1)
+#define EDNS_VERSION_SIZE (1)
+#define EDNS_OPTION_CODE_SIZE (2)
+#define EDNS_OPTION_LENGTH_SIZE (2)
+
+#if BYTE_ORDER == BIG_ENDIAN
+#define FLAGS_RD_OFFSET (8)
+#define FLAGS_CD_OFFSET (12)
+#elif BYTE_ORDER == LITTLE_ENDIAN || BYTE_ORDER == PDP_ENDIAN
+#define FLAGS_RD_OFFSET (0)
+#define FLAGS_CD_OFFSET (12)
+#endif
+
+#define L theL()
+extern time_t s_starttime;
+
+uint32_t hashQuestion(const char* packet, uint16_t len, uint32_t init);
+
+struct TSIGTriplet
+{
+ DNSName name, algo;
+ string secret;
+};
+
+/** for use by DNSPacket, converts a SOAData class to a ascii line again */
+string serializeSOAData(const SOAData &data);
+string &attodot(string &str); //!< for when you need to insert an email address in the SOA
+
+vector<DNSResourceRecord> convertRRS(const vector<DNSRecord>& in);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <openssl/aes.h>
+#include <openssl/opensslv.h>
+#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER
+// Older OpenSSL does not have CRYPTO_ctr128_encrypt. Before 1.1.0 the header
+// file did not have the necessary extern "C" wrapper. In 1.1.0, AES_ctr128_encrypt
+// was removed.
+#include <openssl/modes.h>
+#endif
+#include <iostream>
+#include <cstdlib>
+#include <cstring>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <limits>
+#include <stdexcept>
+#include <stdint.h>
+#include "dns_random.hh"
+
+using namespace std;
+
+static AES_KEY aes_key;
+static unsigned int g_offset;
+static unsigned char g_counter[16], g_stream[16];
+static uint32_t g_in;
+
+static bool g_initialized;
+
+void dns_random_init(const char data[16])
+{
+ g_offset = 0;
+ memset(&g_stream, 0, sizeof(g_stream));
+ if (AES_set_encrypt_key((const unsigned char*)data, 128, &aes_key) < 0) {
+ throw std::runtime_error("AES_set_encrypt_key failed");
+ }
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ static_assert(sizeof(g_counter) >= (sizeof(now.tv_usec) + sizeof(now.tv_sec)), "g_counter must be large enough to get tv_sec + tv_usec");
+ memcpy(g_counter, &now.tv_usec, sizeof(now.tv_usec));
+ memcpy(g_counter+sizeof(now.tv_usec), &now.tv_sec, sizeof(now.tv_sec));
+ g_in = getpid() | (getppid()<<16);
+
+ g_initialized = true;
+ srandom(dns_random(numeric_limits<uint32_t>::max()));
+}
+
+unsigned int dns_random(unsigned int n)
+{
+ if(!g_initialized)
+ abort();
+ uint32_t out;
+#if OPENSSL_VERSION_NUMBER > 0x1010000fL && !defined LIBRESSL_VERSION_NUMBER
+ CRYPTO_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset, (block128_f) AES_encrypt);
+#else
+ AES_ctr128_encrypt((const unsigned char*)&g_in, (unsigned char*) &out, sizeof(g_in), &aes_key, g_counter, g_stream, &g_offset);
+#endif
+ return out % n;
+}
+
+#if 0
+int main()
+{
+ dns_random_init("0123456789abcdef");
+
+ for(int n = 0; n < 16; n++)
+ cerr<<dns_random(16384)<<endl;
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNS_RANDOM
+#define PDNS_DNS_RANDOM
+
+void dns_random_init(const char data[16]);
+unsigned int dns_random(unsigned int n);
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "dnsbackend.hh"
+#include "arguments.hh"
+#include "ueberbackend.hh"
+#include "logger.hh"
+
+#include <sys/types.h>
+#include "pdns/packetcache.hh"
+#include "dnspacket.hh"
+#include "dns.hh"
+
+bool DNSBackend::getAuth(DNSPacket *p, SOAData *sd, const DNSName &target)
+{
+ return this->getSOA(target, *sd, p);
+}
+
+void DNSBackend::setArgPrefix(const string &prefix)
+{
+ d_prefix=prefix;
+}
+
+bool DNSBackend::mustDo(const string &key)
+{
+ return arg().mustDo(d_prefix+"-"+key);
+}
+
+const string &DNSBackend::getArg(const string &key)
+{
+ return arg()[d_prefix+"-"+key];
+}
+
+int DNSBackend::getArgAsNum(const string &key)
+{
+ return arg().asNum(d_prefix+"-"+key);
+}
+
+void BackendFactory::declare(const string &suffix, const string ¶m, const string &help, const string &value)
+{
+ string fullname=d_name+suffix+"-"+param;
+ arg().set(fullname,help)=value;
+}
+
+const string &BackendFactory::getName() const
+{
+ return d_name;
+}
+
+BackendMakerClass &BackendMakers()
+{
+ static BackendMakerClass bmc;
+ return bmc;
+}
+
+void BackendMakerClass::report(BackendFactory *bf)
+{
+ d_repository[bf->getName()]=bf;
+}
+
+
+vector<string> BackendMakerClass::getModules()
+{
+ load_all();
+ vector<string> ret;
+ // copy(d_repository.begin(), d_repository.end(),back_inserter(ret));
+ for(d_repository_t::const_iterator i=d_repository.begin();i!=d_repository.end();++i)
+ ret.push_back(i->first);
+ return ret;
+}
+
+void BackendMakerClass::load_all()
+{
+ // TODO: Implement this?
+ DIR *dir=opendir(arg()["module-dir"].c_str());
+ if(!dir) {
+ L<<Logger::Error<<"Unable to open module directory '"<<arg()["module-dir"]<<"'"<<endl;
+ return;
+ }
+ struct dirent *entry;
+ while((entry=readdir(dir))) {
+ if(!strncmp(entry->d_name,"lib",3) &&
+ strlen(entry->d_name)>13 &&
+ !strcmp(entry->d_name+strlen(entry->d_name)-10,"backend.so"))
+ load(entry->d_name);
+ }
+ closedir(dir);
+}
+
+void BackendMakerClass::load(const string &module)
+{
+ bool res;
+
+ if(module.find(".")==string::npos)
+ res=UeberBackend::loadmodule(arg()["module-dir"]+"/lib"+module+"backend.so");
+ else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path
+ res=UeberBackend::loadmodule(module);
+ else
+ res=UeberBackend::loadmodule(arg()["module-dir"]+"/"+module);
+
+ if(res==false) {
+ L<<Logger::Error<<"DNSBackend unable to load module in "<<module<<endl;
+ exit(1);
+ }
+}
+
+void BackendMakerClass::launch(const string &instr)
+{
+ // if(instr.empty())
+ // throw ArgException("Not launching any backends - nameserver won't function");
+
+ vector<string> parts;
+ stringtok(parts,instr,", ");
+
+ for (const auto part : parts)
+ if (count(parts.begin(), parts.end(), part) > 1)
+ throw ArgException("Refusing to launch multiple backends with the same name '" + part + "', verify all 'launch' statements in your configuration");
+
+ for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
+ const string &part=*i;
+
+ string module, name;
+ vector<string>pparts;
+ stringtok(pparts,part,": ");
+ module=pparts[0];
+ if(pparts.size()>1)
+ name="-"+pparts[1];
+
+ if(d_repository.find(module)==d_repository.end()) {
+ // this is *so* userfriendly
+ load(module);
+ if(d_repository.find(module)==d_repository.end())
+ throw ArgException("Trying to launch unknown backend '"+module+"'");
+ }
+ d_repository[module]->declareArguments(name);
+ d_instances.push_back(make_pair(module,name));
+ }
+}
+
+int BackendMakerClass::numLauncheable()
+{
+ return d_instances.size();
+}
+
+vector<DNSBackend *>BackendMakerClass::all(bool metadataOnly)
+{
+ vector<DNSBackend *>ret;
+ if(d_instances.empty())
+ throw PDNSException("No database backends configured for launch, unable to function");
+
+ try {
+ for(vector<pair<string,string> >::const_iterator i=d_instances.begin();i!=d_instances.end();++i) {
+ DNSBackend *made;
+ if(metadataOnly)
+ made = d_repository[i->first]->makeMetadataOnly(i->second);
+ else
+ made = d_repository[i->first]->make(i->second);
+ if(!made)
+ throw PDNSException("Unable to launch backend '"+i->first+"'");
+
+ ret.push_back(made);
+ }
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"Caught an exception instantiating a backend: "<<ae.reason<<endl;
+ L<<Logger::Error<<"Cleaning up"<<endl;
+ for(vector<DNSBackend *>::const_iterator i=ret.begin();i!=ret.end();++i)
+ delete *i;
+ throw;
+ } catch(...) {
+ // and cleanup
+ L<<Logger::Error<<"Caught an exception instantiating a backend, cleaning up"<<endl;
+ for(vector<DNSBackend *>::const_iterator i=ret.begin();i!=ret.end();++i)
+ delete *i;
+ throw;
+ }
+
+ return ret;
+}
+
+/** getSOA() is a function that is called to get the SOA of a domain. Callers should ONLY
+ use getSOA() and not perform a lookup() themselves as backends may decide to special case
+ the SOA record.
+
+ Returns false if there is definitely no SOA for the domain. May throw a DBException
+ to indicate that the backend is currently unable to supply an answer.
+
+ WARNING: This function *may* fill out the db attribute of the SOAData, but then again,
+ it may not! If you find a zero in there, you may have been handed a non-live and cached
+ answer, in which case you need to perform a getDomainInfo call!
+
+ \param domain Domain we want to get the SOA details of
+ \param sd SOAData which is filled with the SOA details
+*/
+bool DNSBackend::getSOA(const DNSName &domain, SOAData &sd, DNSPacket *p)
+{
+ this->lookup(QType(QType::SOA),domain,p);
+
+ DNSResourceRecord rr;
+ rr.auth = true;
+
+ int hits=0;
+
+ while(this->get(rr)) {
+ if (rr.qtype != QType::SOA) throw PDNSException("Got non-SOA record when asking for SOA");
+ hits++;
+ fillSOAData(rr.content, sd);
+ sd.domain_id=rr.domain_id;
+ sd.ttl=rr.ttl;
+ sd.scopeMask = rr.scopeMask;
+ }
+
+ if(!hits)
+ return false;
+ sd.qname = domain;
+ if(!sd.nameserver.countLabels())
+ sd.nameserver= DNSName(arg()["default-soa-name"]);
+
+ if(!sd.hostmaster.countLabels()) {
+ if (!arg().isEmpty("default-soa-mail")) {
+ sd.hostmaster= DNSName(arg()["default-soa-mail"]);
+ // attodot(sd.hostmaster); FIXME400
+ }
+ else
+ sd.hostmaster=DNSName("hostmaster")+domain;
+ }
+
+ if(!sd.serial) { // magic time!
+ DLOG(L<<Logger::Warning<<"Doing SOA serial number autocalculation for "<<rr.qname<<endl);
+
+ time_t serial;
+ if (calculateSOASerial(domain, sd, serial)) {
+ sd.serial = serial;
+ //DLOG(L<<"autocalculated soa serialnumber for "<<rr.qname<<" is "<<newest<<endl);
+ } else {
+ DLOG(L<<"soa serialnumber calculation failed for "<<rr.qname<<endl);
+ }
+
+ }
+ sd.db=this;
+ return true;
+}
+
+bool DNSBackend::getBeforeAndAfterNames(uint32_t id, const DNSName& zonename, const DNSName& qname, DNSName& before, DNSName& after)
+{
+ DNSName unhashed;
+ string sbefore, safter;
+ string srelqname=qname.makeRelative(zonename).makeLowerCase().labelReverse().toString(" ", false);
+
+ bool ret = this->getBeforeAndAfterNamesAbsolute(id, srelqname, unhashed, sbefore, safter);
+ before = (DNSName(labelReverse(sbefore)) + zonename).makeLowerCase();
+ after = (DNSName(labelReverse(safter)) + zonename).makeLowerCase();
+ return ret;
+}
+
+/**
+ * Calculates a SOA serial for the zone and stores it in the third
+ * argument. Returns false if calculation is not possible for some
+ * reason (in this case, the third argument is not inspected). If it
+ * returns true, the value returned in the third argument will be set
+ * as the SOA serial.
+ *
+ * \param domain The name of the domain
+ * \param sd Information about the SOA record already available
+ * \param serial Output parameter. Only inspected when we return true
+ */
+bool DNSBackend::calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial)
+{
+ // we do this by listing the domain and taking the maximum last modified timestamp
+
+ DNSResourceRecord i;
+ time_t newest=0;
+
+ if(!(this->list(domain, sd.domain_id))) {
+ DLOG(L<<Logger::Warning<<"Backend error trying to determine magic serial number of zone '"<<domain<<"'"<<endl);
+ return false;
+ }
+
+ while(this->get(i)) {
+ if(i.last_modified>newest)
+ newest=i.last_modified;
+ }
+
+ serial=newest;
+
+ return true;
+}
+
+void fillSOAData(const string &content, SOAData &data)
+{
+ // content consists of fields separated by spaces:
+ // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
+
+ // fill out data with some plausible defaults:
+ // 10800 3600 604800 3600
+ vector<string>parts;
+ stringtok(parts,content);
+ int pleft=parts.size();
+
+ // cout<<"'"<<content<<"'"<<endl;
+
+ if(pleft)
+ data.nameserver=DNSName(parts[0]);
+
+ if(pleft>1)
+ data.hostmaster=DNSName(attodot(parts[1])); // ahu@ds9a.nl -> ahu.ds9a.nl, piet.puk@ds9a.nl -> piet\.puk.ds9a.nl
+
+ try {
+ data.serial = pleft > 2 ? pdns_stou(parts[2]) : 0;
+
+ data.refresh = pleft > 3 ? pdns_stou(parts[3])
+ : ::arg().asNum("soa-refresh-default");
+
+ data.retry = pleft > 4 ? pdns_stou(parts[4].c_str())
+ : ::arg().asNum("soa-retry-default");
+
+ data.expire = pleft > 5 ? pdns_stou(parts[5].c_str())
+ : ::arg().asNum("soa-expire-default");
+
+ data.default_ttl = pleft > 6 ? pdns_stou(parts[6].c_str())
+ : ::arg().asNum("soa-minimum-ttl");
+ }
+ catch(const std::out_of_range& oor) {
+ throw PDNSException("Out of range exception parsing "+content);
+ }
+}
+
+string serializeSOAData(const SOAData &d)
+{
+ ostringstream o;
+ // nameservername hostmaster serial-number [refresh [retry [expire [ minimum] ] ] ]
+ o<<d.nameserver.toString()<<" "<< d.hostmaster.toString() <<" "<< d.serial <<" "<< d.refresh << " "<< d.retry << " "<< d.expire << " "<< d.default_ttl;
+
+ return o.str();
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef DNSBACKEND_HH
+#define DNSBACKEND_HH
+
+class DNSPacket;
+
+#include "utility.hh"
+#include <string>
+#include <vector>
+#include <map>
+#include <sys/types.h>
+#include "pdnsexception.hh"
+#include <set>
+#include <iostream>
+#include <sys/socket.h>
+#include <dirent.h>
+#include "misc.hh"
+#include "qtype.hh"
+#include "dns.hh"
+#include <vector>
+#include "namespaces.hh"
+#include "comment.hh"
+#include "dnsname.hh"
+#include "dnsrecords.hh"
+
+class DNSBackend;
+struct DomainInfo
+{
+ DomainInfo() : last_check(0), backend(NULL), id(0), notified_serial(0), serial(0), kind(DomainInfo::Native) {}
+
+ DNSName zone;
+ time_t last_check;
+ string account;
+ vector<string> masters;
+ DNSBackend *backend;
+
+ uint32_t id;
+ uint32_t notified_serial;
+
+ uint32_t serial;
+ enum DomainKind : uint8_t { Master, Slave, Native } kind;
+
+ bool operator<(const DomainInfo& rhs) const
+ {
+ return zone < rhs.zone;
+ }
+
+ const char *getKindString() const
+ {
+ return DomainInfo::getKindString(kind);
+ }
+
+ static const char *getKindString(enum DomainKind kind)
+ {
+ const char *kinds[]={"Master", "Slave", "Native"};
+ return kinds[kind];
+ }
+
+ static DomainKind stringToKind(const string& kind)
+ {
+ if(pdns_iequals(kind,"SLAVE"))
+ return DomainInfo::Slave;
+ else if(pdns_iequals(kind,"MASTER"))
+ return DomainInfo::Master;
+ else
+ return DomainInfo::Native;
+ }
+
+};
+
+struct TSIGKey {
+ DNSName name;
+ DNSName algorithm;
+ std::string key;
+};
+
+class DNSPacket;
+
+//! This virtual base class defines the interface for backends for the ahudns.
+/** To create a backend, inherit from this class and implement functions for all virtual methods.
+ Methods should not throw an exception if they are sure they did not find the requested data. However,
+ if an error occurred which prevented them temporarily from performing a lockup, they should throw a DBException,
+ which will cause the nameserver to send out a ServFail or take other evasive action. Probably only locking
+ issues should lead to DBExceptions.
+
+ More serious errors, which may indicate that the database connection is hosed, or a configuration error occurred, should
+ lead to the throwing of an PDNSException. This exception will fall straight through the UeberBackend and the PacketHandler
+ and be caught by the Distributor, which will delete your DNSBackend instance and spawn a new one.
+*/
+class DNSBackend
+{
+public:
+ //! lookup() initiates a lookup. A lookup without results should not throw!
+ virtual void lookup(const QType &qtype, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1)=0;
+ virtual bool get(DNSResourceRecord &)=0; //!< retrieves one DNSResource record, returns false if no more were available
+
+ //! Initiates a list of the specified domain
+ /** Once initiated, DNSResourceRecord objects can be retrieved using get(). Should return false
+ if the backend does not consider itself responsible for the id passed.
+ \param domain_id ID of which a list is requested
+ */
+ virtual bool list(const DNSName &target, int domain_id, bool include_disabled=false)=0;
+
+ virtual ~DNSBackend(){};
+
+ //! fills the soadata struct with the SOA details. Returns false if there is no SOA.
+ virtual bool getSOA(const DNSName &name, SOAData &soadata, DNSPacket *p=0);
+
+ //! Calculates a SOA serial for the zone and stores it in the third argument.
+ virtual bool calculateSOASerial(const DNSName& domain, const SOAData& sd, time_t& serial);
+
+ virtual bool replaceRRSet(uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<DNSResourceRecord>& rrset)
+ {
+ return false;
+ }
+
+ virtual bool listSubZone(const DNSName &zone, int domain_id)
+ {
+ return false;
+ }
+
+ // the DNSSEC related (getDomainMetadata has broader uses too)
+ bool isDnssecDomainMetadata (const string& name) {
+ return (name == "PRESIGNED" || name == "NSEC3PARAM" || name == "NSEC3NARROW");
+ }
+ virtual bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta) { return false; };
+ virtual bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta) { return false; }
+ virtual bool getDomainMetadataOne(const DNSName& name, const std::string& kind, std::string& value)
+ {
+ std::vector<std::string> meta;
+ if (getDomainMetadata(name, kind, meta)) {
+ if(!meta.empty()) {
+ value = *meta.begin();
+ return true;
+ }
+ }
+ return false;
+ }
+
+ virtual bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta) {return false;}
+ virtual bool setDomainMetadataOne(const DNSName& name, const std::string& kind, const std::string& value)
+ {
+ const std::vector<std::string> meta(1, value);
+ return setDomainMetadata(name, kind, meta);
+ }
+
+
+ virtual void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false) { }
+
+ /** Determines if we are authoritative for a zone, and at what level */
+ virtual bool getAuth(DNSPacket *p, SOAData *sd, const DNSName &target);
+
+ struct KeyData {
+ std::string content;
+ unsigned int id;
+ unsigned int flags;
+ bool active;
+ };
+
+ virtual bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<KeyData>& keys) { return false;}
+ virtual bool removeDomainKey(const DNSName& name, unsigned int id) { return false; }
+ virtual int addDomainKey(const DNSName& name, const KeyData& key){ return -1; }
+ virtual bool activateDomainKey(const DNSName& name, unsigned int id) { return false; }
+ virtual bool deactivateDomainKey(const DNSName& name, unsigned int id) { return false; }
+
+ virtual bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content) { return false; }
+ virtual bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content) { return false; }
+ virtual bool deleteTSIGKey(const DNSName& name) { return false; }
+ virtual bool getTSIGKeys(std::vector< struct TSIGKey > &keys) { return false; }
+
+ virtual bool getBeforeAndAfterNamesAbsolute(uint32_t id, const string& qname, DNSName& unhashed, string& before, string& after)
+ {
+ std::cerr<<"Default beforeAndAfterAbsolute called!"<<std::endl;
+ abort();
+ return false;
+ }
+
+ virtual bool getBeforeAndAfterNames(uint32_t id, const DNSName& zonename, const DNSName& qname, DNSName& before, DNSName& after);
+
+ virtual bool updateDNSSECOrderNameAndAuth(uint32_t domain_id, const DNSName& zonename, const DNSName& qname, const DNSName& ordername, bool auth, const uint16_t qtype=QType::ANY)
+ {
+ return false;
+ }
+
+ virtual bool updateEmptyNonTerminals(uint32_t domain_id, const DNSName& zonename, set<DNSName>& insert, set<DNSName>& erase, bool remove)
+ {
+ return false;
+ }
+
+ virtual bool doesDNSSEC()
+ {
+ return false;
+ }
+
+ // end DNSSEC
+
+ // comments support
+ virtual bool listComments(uint32_t domain_id)
+ {
+ return false; // unsupported by this backend
+ }
+
+ virtual bool getComment(Comment& comment)
+ {
+ return false;
+ }
+
+ virtual void feedComment(const Comment& comment)
+ {
+ }
+
+ virtual bool replaceComments(const uint32_t domain_id, const DNSName& qname, const QType& qt, const vector<Comment>& comments)
+ {
+ return false;
+ }
+
+ //! returns true if master ip is master for domain name.
+ virtual bool isMaster(const DNSName &name, const string &ip)
+ {
+ return false;
+ }
+
+ //! starts the transaction for updating domain qname (FIXME: what is id?)
+ virtual bool startTransaction(const DNSName &qname, int id=-1)
+ {
+ return false;
+ }
+
+ //! commits the transaction started by startTransaction
+ virtual bool commitTransaction()
+ {
+ return false;
+ }
+
+ //! aborts the transaction started by strartTransaction, should leave state unaltered
+ virtual bool abortTransaction()
+ {
+ return false;
+ }
+
+ virtual void reload()
+ {
+ }
+
+ virtual void rediscover(string* status=0)
+ {
+ }
+
+ //! feeds a record to a zone, needs a call to startTransaction first
+ virtual bool feedRecord(const DNSResourceRecord &rr, string *ordername=0)
+ {
+ return false; // no problem!
+ }
+ virtual bool feedEnts(int domain_id, map<DNSName,bool> &nonterm)
+ {
+ return false;
+ }
+ virtual bool feedEnts3(int domain_id, const DNSName &domain, map<DNSName,bool> &nonterm, const NSEC3PARAMRecordContent& ns3prc, bool narrow)
+ {
+ return false;
+ }
+
+ //! if this returns true, DomainInfo di contains information about the domain
+ virtual bool getDomainInfo(const DNSName &domain, DomainInfo &di)
+ {
+ return false;
+ }
+ //! slave capable backends should return a list of slaves that should be rechecked for staleness
+ virtual void getUnfreshSlaveInfos(vector<DomainInfo>* domains)
+ {
+ }
+
+ //! get a list of IP addresses that should also be notified for a domain
+ virtual void alsoNotifies(const DNSName &domain, set<string> *ips)
+ {
+ }
+
+ //! get list of domains that have been changed since their last notification to slaves
+ virtual void getUpdatedMasters(vector<DomainInfo>* domains)
+ {
+ }
+
+ //! Called by PowerDNS to inform a backend that a domain has been checked for freshness
+ virtual void setFresh(uint32_t domain_id)
+ {
+
+ }
+ //! Called by PowerDNS to inform a backend that the changes in the domain have been reported to slaves
+ virtual void setNotified(uint32_t id, uint32_t serial)
+ {
+ }
+
+ //! Called when the Master of a domain should be changed
+ virtual bool setMaster(const DNSName &domain, const string &ip)
+ {
+ return false;
+ }
+
+ //! Called when the Kind of a domain should be changed (master -> native and similar)
+ virtual bool setKind(const DNSName &domain, const DomainInfo::DomainKind kind)
+ {
+ return false;
+ }
+
+ //! Called when the Account of a domain should be changed
+ virtual bool setAccount(const DNSName &domain, const string &account)
+ {
+ return false;
+ }
+
+ //! Can be called to seed the getArg() function with a prefix
+ void setArgPrefix(const string &prefix);
+
+ //! determine if ip is a supermaster or a domain
+ virtual bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
+ {
+ return false;
+ }
+
+ //! called by PowerDNS to create a new domain
+ virtual bool createDomain(const DNSName &domain)
+ {
+ return false;
+ }
+
+ //! called by PowerDNS to create a slave record for a superMaster
+ virtual bool createSlaveDomain(const string &ip, const DNSName &domain, const string &nameserver, const string &account)
+ {
+ return false;
+ }
+
+ //! called to delete a domain, incl. all metadata, zone contents, etc.
+ virtual bool deleteDomain(const DNSName &domain)
+ {
+ return false;
+ }
+
+ virtual string directBackendCmd(const string &query)
+ {
+ return "directBackendCmd not supported for this backend\n";
+ }
+
+ //! Search for records, returns true if search was done successfully.
+ virtual bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result)
+ {
+ return false;
+ }
+
+ //! Search for comments, returns true if search was done successfully.
+ virtual bool searchComments(const string &pattern, int maxResults, vector<Comment>& result)
+ {
+ return false;
+ }
+
+ const string& getPrefix() { return d_prefix; };
+protected:
+ bool mustDo(const string &key);
+ const string &getArg(const string &key);
+ int getArgAsNum(const string &key);
+
+private:
+ string d_prefix;
+};
+
+class BackendFactory
+{
+public:
+ BackendFactory(const string &name) : d_name(name) {}
+ virtual ~BackendFactory(){}
+ virtual DNSBackend *make(const string &suffix)=0;
+ virtual DNSBackend *makeMetadataOnly(const string &suffix)
+ {
+ return this->make(suffix);
+ }
+ virtual void declareArguments(const string &suffix=""){}
+ const string &getName() const;
+
+protected:
+ void declare(const string &suffix, const string ¶m, const string &explanation, const string &value);
+
+private:
+ const string d_name;
+};
+
+class BackendMakerClass
+{
+public:
+ void report(BackendFactory *bf);
+ void launch(const string &instr);
+ vector<DNSBackend *>all(bool skipBIND=false);
+ void load(const string &module);
+ int numLauncheable();
+ vector<string> getModules();
+
+private:
+ void load_all();
+ typedef map<string,BackendFactory *>d_repository_t;
+ d_repository_t d_repository;
+ vector<pair<string,string> >d_instances;
+};
+
+extern BackendMakerClass &BackendMakers();
+
+//! Exception that can be thrown by a DNSBackend to indicate a failure
+class DBException : public PDNSException
+{
+public:
+ DBException(const string &reason) : PDNSException(reason){}
+};
+
+/** helper function for both DNSPacket and addSOARecord() - converts a line into a struct, for easier parsing */
+void fillSOAData(const string &content, SOAData &data);
+
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/accumulators/accumulators.hpp>
+#include <boost/array.hpp>
+#include <boost/accumulators/statistics.hpp>
+#include <boost/program_options.hpp>
+#include "inflighter.cc"
+#include <deque>
+#include "namespaces.hh"
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+
+using namespace boost::accumulators;
+namespace po = boost::program_options;
+
+po::variables_map g_vm;
+
+StatBag S;
+
+bool g_quiet=false;
+bool g_envoutput=false;
+
+struct DNSResult
+{
+ vector<ComboAddress> ips;
+ int rcode;
+ bool seenauthsoa;
+};
+
+struct TypedQuery
+{
+ TypedQuery(const string& name_, uint16_t type_) : name(name_), type(type_){}
+ DNSName name;
+ uint16_t type;
+};
+
+struct SendReceive
+{
+ typedef int Identifier;
+ typedef DNSResult Answer; // ip
+ int d_socket;
+ deque<uint16_t> d_idqueue;
+
+ typedef accumulator_set<
+ double
+ , stats<boost::accumulators::tag::extended_p_square,
+ boost::accumulators::tag::median(with_p_square_quantile),
+ boost::accumulators::tag::mean(immediate)
+ >
+ > acc_t;
+ acc_t* d_acc;
+
+ boost::array<double, 11> d_probs;
+
+ SendReceive(const std::string& remoteAddr, uint16_t port)
+ {
+ boost::array<double, 11> tmp ={{0.001,0.01, 0.025, 0.1, 0.25,0.5,0.75,0.9,0.975, 0.99,0.9999}};
+ d_probs = tmp;
+ d_acc = new acc_t(boost::accumulators::tag::extended_p_square::probabilities=d_probs);
+ //
+ //d_acc = acc_t
+ d_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ int val=1;
+ setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+
+ ComboAddress remote(remoteAddr, port);
+ connect(d_socket, (struct sockaddr*)&remote, remote.getSocklen());
+ d_oks = d_errors = d_nodatas = d_nxdomains = d_unknowns = 0;
+ d_receiveds = d_receiveerrors = d_senderrors = 0;
+ for(unsigned int id =0 ; id < std::numeric_limits<uint16_t>::max(); ++id)
+ d_idqueue.push_back(id);
+ }
+
+ ~SendReceive()
+ {
+ close(d_socket);
+ }
+
+ Identifier send(TypedQuery& domain)
+ {
+ //cerr<<"Sending query for '"<<domain<<"'"<<endl;
+
+ // send it, copy code from 'sdig'
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, domain.name, domain.type);
+
+ if(d_idqueue.empty()) {
+ cerr<<"Exhausted ids!"<<endl;
+ exit(1);
+ }
+ pw.getHeader()->id = d_idqueue.front();
+ d_idqueue.pop_front();
+ pw.getHeader()->rd = 1;
+ pw.getHeader()->qr = 0;
+
+ if(::send(d_socket, &*packet.begin(), packet.size(), 0) < 0)
+ d_senderrors++;
+
+ if(!g_quiet)
+ cout<<"Sent out query for '"<<domain.name<<"' with id "<<pw.getHeader()->id<<endl;
+ return pw.getHeader()->id;
+ }
+
+ bool receive(Identifier& id, DNSResult& dr)
+ {
+ if(waitForData(d_socket, 0, 500000) > 0) {
+ char buf[512];
+
+ int len = recv(d_socket, buf, sizeof(buf), 0);
+ if(len < 0) {
+ d_receiveerrors++;
+ return 0;
+ }
+ else {
+ d_receiveds++;
+ }
+ // parse packet, set 'id', fill out 'ip'
+
+ MOADNSParser mdp(false, string(buf, len));
+ if(!g_quiet) {
+ cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+ }
+ dr.rcode = mdp.d_header.rcode;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if(i->first.d_place == 1 && i->first.d_type == mdp.d_qtype)
+ dr.ips.push_back(ComboAddress(i->first.d_content->getZoneRepresentation()));
+ if(i->first.d_place == 2 && i->first.d_type == QType::SOA) {
+ dr.seenauthsoa = 1;
+ }
+ if(!g_quiet)
+ {
+ cout<<i->first.d_place-1<<"\t"<<i->first.d_name<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+ cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
+ }
+ }
+
+ id = mdp.d_header.id;
+ d_idqueue.push_back(id);
+
+ return 1;
+ }
+ return 0;
+ }
+
+ void deliverTimeout(const Identifier& id)
+ {
+ if(!g_quiet) {
+ cout<<"Timeout for id "<<id<<endl;
+ }
+ d_idqueue.push_back(id);
+ }
+
+ void deliverAnswer(TypedQuery& domain, const DNSResult& dr, unsigned int usec)
+ {
+ (*d_acc)(usec/1000.0);
+// if(usec > 1000000)
+ // cerr<<"Slow: "<<domain<<" ("<<usec/1000.0<<" msec)\n";
+ if(!g_quiet) {
+ cout<<domain.name<<"|"<<DNSRecordContent::NumberToType(domain.type)<<": ("<<usec/1000.0<<"msec) rcode: "<<dr.rcode;
+ for(const ComboAddress& ca : dr.ips) {
+ cout<<", "<<ca.toString();
+ }
+ cout<<endl;
+ }
+ if(dr.rcode == RCode::NXDomain) {
+ d_nxdomains++;
+ }
+ else if(dr.rcode) {
+ d_errors++;
+ }
+ else if(dr.ips.empty() && dr.seenauthsoa)
+ d_nodatas++;
+ else if(!dr.ips.empty())
+ d_oks++;
+ else {
+ if(!g_quiet) cout<<"UNKNOWN!! ^^"<<endl;
+ d_unknowns++;
+ }
+ }
+ unsigned int d_errors, d_nxdomains, d_nodatas, d_oks, d_unknowns;
+ unsigned int d_receiveds, d_receiveerrors, d_senderrors;
+};
+
+void usage(po::options_description &desc) {
+ cerr << "Usage: dnsbulktest [OPTION].. IPADDRESS PORTNUMBER [LIMIT]"<<endl;
+ cerr << desc << "\n";
+}
+
+int main(int argc, char** argv)
+try
+{
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("quiet,q", "be quiet about individual queries")
+ ("type,t", po::value<string>()->default_value("A"), "What type to query for")
+ ("envoutput,e", "write report in shell environment format")
+ ("version", "show the version number")
+ ;
+
+ po::options_description alloptions;
+ po::options_description hidden("hidden options");
+ hidden.add_options()
+ ("ip-address", po::value<string>(), "ip-address")
+ ("portnumber", po::value<uint16_t>(), "portnumber")
+ ("limit", po::value<uint32_t>()->default_value(0), "limit");
+
+ alloptions.add(desc).add(hidden);
+ po::positional_options_description p;
+ p.add("ip-address", 1);
+ p.add("portnumber", 1);
+ p.add("limit", 1);
+
+ po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+ po::notify(g_vm);
+
+ if (g_vm.count("help")) {
+ usage(desc);
+ return EXIT_SUCCESS;
+ }
+
+ if (g_vm.count("version")) {
+ cerr<<"dnsbulktest "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+
+ if(!g_vm.count("portnumber")) {
+ cerr<<"Fatal, need to specify ip-address and portnumber"<<endl;
+ usage(desc);
+ return EXIT_FAILURE;
+ }
+
+ g_quiet = g_vm.count("quiet") > 0;
+ g_envoutput = g_vm.count("envoutput") > 0;
+ uint16_t qtype;
+ reportAllTypes();
+ try {
+ qtype = DNSRecordContent::TypeToNumber(g_vm["type"].as<string>());
+ }
+ catch(std::exception& e) {
+ cerr << e.what() << endl;
+ return EXIT_FAILURE;
+ }
+
+ SendReceive sr(g_vm["ip-address"].as<string>(), g_vm["portnumber"].as<uint16_t>());
+ unsigned int limit = g_vm["limit"].as<unsigned int>();
+
+ vector<TypedQuery> domains;
+
+ Inflighter<vector<TypedQuery>, SendReceive> inflighter(domains, sr);
+ inflighter.d_maxInFlight = 1000;
+ inflighter.d_timeoutSeconds = 3;
+ inflighter.d_burst = 100;
+ string line;
+
+ pair<string, string> split;
+ string::size_type pos;
+ while(stringfgets(stdin, line)) {
+ if(limit && domains.size() >= limit)
+ break;
+
+ trim_right(line);
+ if(line.empty() || line[0] == '#')
+ continue;
+ split=splitField(line,',');
+ if (split.second.empty())
+ split=splitField(line,'\t');
+ if(!split.second.find('.')) // skip 'Hidden profile' in quantcast list.
+ continue;
+ pos=split.second.find('/');
+ if(pos != string::npos) // alexa has whole urls in the list now.
+ split.second.resize(pos);
+ if(find_if(split.second.begin(), split.second.end(), isalpha) == split.second.end())
+ {
+ continue; // this was an IP address
+ }
+ domains.push_back(TypedQuery(split.second, qtype));
+ domains.push_back(TypedQuery("www."+split.second, qtype));
+ }
+ cerr<<"Read "<<domains.size()<<" domains!"<<endl;
+ random_shuffle(domains.begin(), domains.end());
+
+ boost::format datafmt("%s %|20t|%+15s %|40t|%s %|60t|%+15s\n");
+
+ for(;;) {
+ try {
+ inflighter.run();
+ break;
+ }
+ catch(std::exception& e) {
+ cerr<<"Caught exception: "<<e.what()<<endl;
+ }
+ }
+
+ cerr<< datafmt % "Sending" % "" % "Receiving" % "";
+ cerr<< datafmt % " Queued " % domains.size() % " Received" % sr.d_receiveds;
+ cerr<< datafmt % " Error -/-" % sr.d_senderrors % " Timeouts" % inflighter.getTimeouts();
+ cerr<< datafmt % " " % "" % " Unexpected" % inflighter.getUnexpecteds();
+
+ cerr<< datafmt % " Sent" % (domains.size() - sr.d_senderrors) % " Total" % (sr.d_receiveds + inflighter.getTimeouts() + inflighter.getUnexpecteds());
+
+ cerr<<endl;
+ cerr<< datafmt % "DNS Status" % "" % "" % "";
+ cerr<< datafmt % " OK" % sr.d_oks % "" % "";
+ cerr<< datafmt % " Error" % sr.d_errors % "" % "";
+ cerr<< datafmt % " No Data" % sr.d_nodatas % "" % "";
+ cerr<< datafmt % " NXDOMAIN" % sr.d_nxdomains % "" % "";
+ cerr<< datafmt % " Unknowns" % sr.d_unknowns % "" % "";
+ cerr<< datafmt % "Answers" % (sr.d_oks + sr.d_errors + sr.d_nodatas + sr.d_nxdomains + sr.d_unknowns) % "" % "";
+ cerr<< datafmt % " Timeouts " % (inflighter.getTimeouts()) % "" % "";
+ cerr<< datafmt % "Total " % (sr.d_oks + sr.d_errors + sr.d_nodatas + sr.d_nxdomains + sr.d_unknowns + inflighter.getTimeouts()) % "" % "";
+
+ cerr<<"\n";
+ cerr<< "Mean response time: "<<mean(*sr.d_acc) << " msec"<<", median: "<<median(*sr.d_acc)<< " msec\n";
+
+ boost::format statfmt("Time < %6.03f msec %|30t|%6.03f%% cumulative\n");
+
+ for (unsigned int i = 0; i < sr.d_probs.size(); ++i) {
+ cerr << statfmt % extended_p_square(*sr.d_acc)[i] % (100*sr.d_probs[i]);
+ }
+
+ if(g_envoutput) {
+ cout<<"DBT_QUEUED="<<domains.size()<<endl;
+ cout<<"DBT_SENDERRORS="<<sr.d_senderrors<<endl;
+ cout<<"DBT_RECEIVED="<<sr.d_receiveds<<endl;
+ cout<<"DBT_TIMEOUTS="<<inflighter.getTimeouts()<<endl;
+ cout<<"DBT_UNEXPECTEDS="<<inflighter.getUnexpecteds()<<endl;
+ cout<<"DBT_OKPERCENTAGE="<<((float)sr.d_oks/domains.size()*100)<<endl;
+ cout<<"DBT_OKPERCENTAGEINT="<<(int)((float)sr.d_oks/domains.size()*100)<<endl;
+ }
+}
+catch(PDNSException& pe)
+{
+ cerr<<"Fatal error: "<<pe.reason<<endl;
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define __FAVOR_BSD
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "dnsparser.hh"
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <map>
+#include <set>
+#include <fstream>
+#include <algorithm>
+#include "anadns.hh"
+
+#include "namespaces.hh"
+
+StatBag S;
+
+struct Entry
+{
+ ComboAddress ip;
+ uint16_t port;
+ uint16_t id;
+
+ bool operator<(const struct Entry& rhs) const
+ {
+ return tie(ip, port, id) < tie(rhs.ip, rhs.port, rhs.id);
+ }
+};
+
+
+typedef map<Entry, uint32_t> emap_t;
+emap_t ecount;
+
+int main(int argc, char** argv)
+try
+{
+ cout << "begin;";
+ for(int n=1 ; n < argc; ++n) {
+ PcapPacketReader pr(argv[n]);
+
+ Entry entry;
+ while(pr.getUDPPacket()) {
+ if(ntohs(pr.d_udp->uh_dport)==53 && pr.d_len > 12) {
+ try {
+ dnsheader* dh= (dnsheader*) pr.d_payload;
+
+ if(dh->rd || dh->qr)
+ continue;
+
+ MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
+
+ entry.ip = pr.getSource();
+ entry.port = pr.d_udp->uh_sport;
+ entry.id=dh->id;
+
+ cout << "insert into dnsstats (source, port, id, query, qtype, tstampSec, tstampUsec, arcount) values ('" << entry.ip.toString() <<"', "<< ntohs(entry.port) <<", "<< ntohs(dh->id);
+ cout <<", '"<<mdp.d_qname<<"', "<<mdp.d_qtype<<", " << pr.d_pheader.ts.tv_sec <<", " << pr.d_pheader.ts.tv_usec;
+ cout <<", "<< ntohs(dh->arcount) <<");\n";
+
+ }
+ catch(MOADNSException& mde) {
+ // cerr<<"error parsing packet: "<<mde.what()<<endl;
+ continue;
+ }
+ catch(std::exception& e) {
+ cerr << e.what() << endl;
+ continue;
+ }
+ }
+ }
+ }
+ cout <<"commit;";
+ /*
+ for(emap_t::const_iterator i = ecount.begin(); i != ecount.end(); ++i) {
+ if(i->second > 1)
+ cout << U32ToIP(ntohl(i->first.ip)) <<":"<<ntohs(i->first.port)<<" -> "<<i->second <<endl;
+ }
+ */
+
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define __FAVOR_BSD
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "dnsrecords.hh"
+#include "dnsparser.hh"
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <map>
+#include <set>
+#include <fstream>
+#include <algorithm>
+#include "anadns.hh"
+
+#include "namespaces.hh"
+#include "namespaces.hh"
+
+StatBag S;
+
+struct tm* pdns_localtime_r(const uint32_t* then, struct tm* tm)
+{
+ time_t t = *then;
+
+ return localtime_r(&t, tm);
+}
+
+int32_t g_clientQuestions, g_clientResponses, g_serverQuestions, g_serverResponses, g_skipped;
+struct pdns_timeval g_lastanswerTime, g_lastquestionTime;
+void makeReport(const struct pdns_timeval& tv)
+{
+ int64_t clientdiff = g_clientQuestions - g_clientResponses;
+ int64_t serverdiff = g_serverQuestions - g_serverResponses;
+
+ if(clientdiff > 1 && clientdiff > 0.02*g_clientQuestions) {
+ char tmp[80];
+ struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout << tmp << ": Resolver dropped too many questions ("
+ << g_clientQuestions <<" vs " << g_clientResponses << "), diff: " <<clientdiff<<endl;
+
+ tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
+
+ tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
+ }
+
+ if(serverdiff > 1 && serverdiff > 0.02*g_serverQuestions) {
+ char tmp[80];
+ struct tm tm=*pdns_localtime_r(&tv.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout << tmp << ": Auth server dropped too many questions ("
+ << g_serverQuestions <<" vs " << g_serverResponses << "), diff: " <<serverdiff<<endl;
+
+ tm=*pdns_localtime_r(&g_lastanswerTime.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout<<"Last answer: "<<tmp<<"."<<g_lastanswerTime.tv_usec/1000000.0<<endl;
+
+ tm=*pdns_localtime_r(&g_lastquestionTime.tv_sec, &tm);
+ strftime(tmp, sizeof(tmp) - 1, "%F %H:%M:%S", &tm);
+
+ cout<<"Last question: "<<tmp<<"."<<g_lastquestionTime.tv_usec/1000000.0<<endl;
+ }
+// cout <<"Recursive questions: "<<g_clientQuestions<<", recursive responses: " << g_clientResponses<<
+// ", server questions: "<<g_serverQuestions<<", server responses: "<<g_serverResponses<<endl;
+
+
+// cerr << tv.tv_sec << " " <<g_clientQuestions<<" " << g_clientResponses<< " "<<g_serverQuestions<<" "<<g_serverResponses<<" "<<g_skipped<<endl;
+ g_clientQuestions=g_clientResponses=g_serverQuestions=g_serverResponses=0;
+ g_skipped=0;
+}
+
+void usage() {
+ cerr<<"syntax: dnsgram INFILE..."<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ // Parse possible options
+ if (argc == 1) {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ for(int n=1 ; n < argc; ++n) {
+ if ((string) argv[n] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[n] == "--version") {
+ cerr<<"dnsgram "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ reportAllTypes();
+ for(int n=1 ; n < argc; ++n) {
+ cout<<argv[n]<<endl;
+ unsigned int parseErrors=0, totalQueries=0, skipped=0;
+ PcapPacketReader pr(argv[n]);
+ // PcapPacketWriter pw(argv[n]+string(".out"), pr);
+ /* four sorts of packets:
+ "rd": question from a client pc
+ "rd qr": answer to a client pc
+ "": question from the resolver
+ "qr": answer to the resolver */
+
+ /* what are interesting events to note? */
+ /* we measure every 60 seconds, each interval with 10% less answers than questions is interesting */
+ /* report chunked */
+
+ struct pdns_timeval lastreport;
+
+ typedef set<pair<DNSName, uint16_t> > queries_t;
+ queries_t questions, answers;
+
+ // unsigned int count = 50000;
+
+ map<pair<DNSName, uint16_t>, int> counts;
+
+ map<double, int> rdqcounts, rdacounts;
+
+ while(pr.getUDPPacket()) {
+ if((ntohs(pr.d_udp->uh_dport)==5300 || ntohs(pr.d_udp->uh_sport)==5300 ||
+ ntohs(pr.d_udp->uh_dport)==53 || ntohs(pr.d_udp->uh_sport)==53) &&
+ pr.d_len > 12) {
+ try {
+ MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
+
+ if(lastreport.tv_sec == 0) {
+ lastreport = pr.d_pheader.ts;
+ }
+
+ if(mdp.d_header.rd && !mdp.d_header.qr) {
+ rdqcounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++;
+ g_lastquestionTime=pr.d_pheader.ts;
+ g_clientQuestions++;
+ totalQueries++;
+ counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
+ questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
+ }
+ else if(mdp.d_header.rd && mdp.d_header.qr) {
+ rdacounts[pr.d_pheader.ts.tv_sec + 0.01*(pr.d_pheader.ts.tv_usec/10000)]++;
+ g_lastanswerTime=pr.d_pheader.ts;
+ g_clientResponses++;
+ answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
+ }
+ else if(!mdp.d_header.rd && !mdp.d_header.qr) {
+ g_lastquestionTime=pr.d_pheader.ts;
+ g_serverQuestions++;
+ counts[make_pair(mdp.d_qname, mdp.d_qtype)]++;
+ questions.insert(make_pair(mdp.d_qname, mdp.d_qtype));
+ totalQueries++;
+ }
+ else if(!mdp.d_header.rd && mdp.d_header.qr) {
+ answers.insert(make_pair(mdp.d_qname, mdp.d_qtype));
+ g_serverResponses++;
+ }
+
+ if(pr.d_pheader.ts.tv_sec - lastreport.tv_sec >= 1) {
+ makeReport(pr.d_pheader.ts);
+ lastreport = pr.d_pheader.ts;
+ }
+ }
+ catch(MOADNSException& mde) {
+ // cerr<<"error parsing packet: "<<mde.what()<<endl;
+ parseErrors++;
+ continue;
+ }
+ catch(std::exception& e) {
+ cerr << e.what() << endl;
+ continue;
+ }
+ }
+ }
+
+ map<double, pair<int, int>> splot;
+
+ for(auto& a : rdqcounts) {
+ splot[a.first].first = a.second;
+ }
+ for(auto& a : rdacounts) {
+ splot[a.first].second = a.second;
+ }
+
+ cerr<<"Writing out sub-second rd query/response stats to ./rdqaplot"<<endl;
+ ofstream plot("rdqaplot");
+ plot<<std::fixed;
+ for(auto& a : splot) {
+ plot << a.first<<"\t"<<a.second.first<<"\t"<<a.second.second<<endl;
+ }
+ cerr<<"Parse errors: "<<parseErrors<<", total queries: "<<totalQueries<<endl;
+ typedef vector<queries_t::value_type> diff_t;
+ diff_t diff;
+ set_difference(questions.begin(), questions.end(), answers.begin(), answers.end(), back_inserter(diff));
+ cerr<<questions.size()<<" different rd questions, "<< answers.size()<<" different rd answers, diff: "<<diff.size()<<endl;
+ cerr<<skipped<<" skipped\n";
+
+ cerr<<"Generating 'failed' file with failed queries and counts\n";
+ ofstream failed("failed");
+ failed<<"name\ttype\tnumber\n";
+ for(diff_t::const_iterator i = diff.begin(); i != diff.end() ; ++i) {
+ failed << i->first << "\t" << DNSRecordContent::NumberToType(i->second) << "\t"<< counts[make_pair(i->first, i->second)]<<"\n";
+ }
+
+ diff.clear();
+
+ set_difference(answers.begin(), answers.end(), questions.begin(), questions.end(), back_inserter(diff));
+ cerr<<diff.size()<<" answers w/o questions\n";
+
+ cerr<<"Generating 'succeeded' file with all unique answers and counts\n";
+ ofstream succeeded("succeeded");
+ succeeded<<"name\ttype\tnumber\n";
+ for(queries_t::const_iterator i = answers.begin(); i != answers.end() ; ++i) {
+ succeeded << i->first << "\t" <<DNSRecordContent::NumberToType(i->second) << "\t" << counts[make_pair(i->first, i->second)]<<"\n";
+ }
+ }
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+
+#line 1 "dnslabeltext.rl"
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string>
+#include "dnsname.hh"
+#include "namespaces.hh"
+
+namespace {
+void appendSplit(vector<string>& ret, string& segment, char c)
+{
+ if(segment.size()>254) {
+ ret.push_back(segment);
+ segment.clear();
+ }
+ segment.append(1, c);
+}
+
+}
+
+vector<string> segmentDNSText(const string& input )
+{
+ // cerr<<"segmentDNSText("<<input<<")"<<endl;
+
+#line 28 "dnslabeltext.cc"
+static const char _dnstext_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 3, 1, 4, 1, 5, 2, 0, 1,
+ 2, 4, 5
+};
+
+static const char _dnstext_key_offsets[] = {
+ 0, 0, 1, 3, 5, 7, 9, 11,
+ 15
+};
+
+static const unsigned char _dnstext_trans_keys[] = {
+ 34u, 34u, 92u, 48u, 57u, 48u, 57u, 48u,
+ 57u, 34u, 92u, 32u, 34u, 9u, 13u, 34u,
+ 0
+};
+
+static const char _dnstext_single_lengths[] = {
+ 0, 1, 2, 0, 0, 0, 2, 2,
+ 1
+};
+
+static const char _dnstext_range_lengths[] = {
+ 0, 0, 0, 1, 1, 1, 0, 1,
+ 0
+};
+
+static const char _dnstext_index_offsets[] = {
+ 0, 0, 2, 5, 7, 9, 11, 14,
+ 18
+};
+
+static const char _dnstext_trans_targs[] = {
+ 2, 0, 7, 3, 2, 4, 2, 5,
+ 0, 6, 0, 7, 3, 2, 8, 2,
+ 8, 0, 2, 0, 0
+};
+
+static const char _dnstext_trans_actions[] = {
+ 3, 0, 0, 0, 11, 7, 5, 7,
+ 0, 7, 0, 9, 9, 16, 0, 13,
+ 0, 0, 13, 0, 0
+};
+
+static const char _dnstext_eof_actions[] = {
+ 0, 0, 0, 0, 0, 0, 0, 1,
+ 1
+};
+
+static const int dnstext_start = 1;
+static const int dnstext_first_final = 7;
+static const int dnstext_error = 0;
+
+static const int dnstext_en_main = 1;
+
+
+#line 28 "dnslabeltext.rl"
+
+ (void)dnstext_error; // silence warnings
+ (void)dnstext_en_main;
+ const char *p = input.c_str(), *pe = input.c_str() + input.length();
+ const char* eof = pe;
+ int cs;
+ char val = 0;
+
+ string segment;
+ vector<string> ret;
+
+
+#line 98 "dnslabeltext.cc"
+ {
+ cs = dnstext_start;
+ }
+
+#line 103 "dnslabeltext.cc"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const unsigned char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _dnstext_trans_keys + _dnstext_key_offsets[cs];
+ _trans = _dnstext_index_offsets[cs];
+
+ _klen = _dnstext_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const unsigned char *_lower = _keys;
+ const unsigned char *_mid;
+ const unsigned char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _dnstext_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const unsigned char *_lower = _keys;
+ const unsigned char *_mid;
+ const unsigned char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ cs = _dnstext_trans_targs[_trans];
+
+ if ( _dnstext_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _dnstext_actions + _dnstext_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 40 "dnslabeltext.rl"
+ {
+ ret.push_back(segment);
+ segment.clear();
+ }
+ break;
+ case 1:
+#line 44 "dnslabeltext.rl"
+ {
+ segment.clear();
+ }
+ break;
+ case 2:
+#line 48 "dnslabeltext.rl"
+ {
+ char c = *p;
+ appendSplit(ret, segment, c);
+ }
+ break;
+ case 3:
+#line 52 "dnslabeltext.rl"
+ {
+ char c = *p;
+ val *= 10;
+ val += c-'0';
+
+ }
+ break;
+ case 4:
+#line 58 "dnslabeltext.rl"
+ {
+ appendSplit(ret, segment, val);
+ val=0;
+ }
+ break;
+ case 5:
+#line 63 "dnslabeltext.rl"
+ {
+ appendSplit(ret, segment, *(p));
+ }
+ break;
+#line 218 "dnslabeltext.cc"
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const char *__acts = _dnstext_actions + _dnstext_eof_actions[cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 0:
+#line 40 "dnslabeltext.rl"
+ {
+ ret.push_back(segment);
+ segment.clear();
+ }
+ break;
+#line 241 "dnslabeltext.cc"
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+#line 76 "dnslabeltext.rl"
+
+
+ if ( cs < dnstext_first_final ) {
+ throw runtime_error("Unable to parse DNS TXT '"+input+"'");
+ }
+
+ return ret;
+};
+
+
+DNSName::string_t segmentDNSNameRaw(const char* realinput)
+{
+
+#line 263 "dnslabeltext.cc"
+static const char _dnsnameraw_actions[] = {
+ 0, 1, 0, 1, 1, 1, 2, 1,
+ 3, 1, 4, 1, 5, 2, 1, 5,
+ 2, 4, 0, 2, 4, 5
+};
+
+static const char _dnsnameraw_key_offsets[] = {
+ 0, 0, 2, 4, 6, 8, 10, 12
+};
+
+static const unsigned char _dnsnameraw_trans_keys[] = {
+ 46u, 92u, 48u, 57u, 48u, 57u, 48u, 57u,
+ 46u, 92u, 46u, 92u, 46u, 92u, 0
+};
+
+static const char _dnsnameraw_single_lengths[] = {
+ 0, 2, 0, 0, 0, 2, 2, 2
+};
+
+static const char _dnsnameraw_range_lengths[] = {
+ 0, 0, 1, 1, 1, 0, 0, 0
+};
+
+static const char _dnsnameraw_index_offsets[] = {
+ 0, 0, 3, 5, 7, 9, 12, 15
+};
+
+static const char _dnsnameraw_trans_targs[] = {
+ 0, 2, 5, 3, 5, 4, 0, 7,
+ 0, 6, 2, 5, 0, 2, 5, 6,
+ 2, 5, 0
+};
+
+static const char _dnsnameraw_trans_actions[] = {
+ 0, 3, 13, 7, 5, 7, 0, 7,
+ 0, 1, 0, 11, 0, 3, 13, 16,
+ 9, 19, 0
+};
+
+static const char _dnsnameraw_eof_actions[] = {
+ 0, 0, 0, 0, 0, 1, 0, 16
+};
+
+static const int dnsnameraw_start = 1;
+static const int dnsnameraw_first_final = 5;
+static const int dnsnameraw_error = 0;
+
+static const int dnsnameraw_en_main = 1;
+
+
+#line 92 "dnslabeltext.rl"
+
+ (void)dnsnameraw_error; // silence warnings
+ (void)dnsnameraw_en_main;
+
+ DNSName::string_t ret;
+
+ if(!*realinput || *realinput == '.') {
+ ret.append(1, (char)0);
+ return ret;
+ }
+
+ unsigned int inputlen=strlen(realinput);
+ ret.reserve(inputlen+1);
+
+ const char *p = realinput, *pe = realinput + inputlen;
+ const char* eof = pe;
+ int cs;
+ char val = 0;
+ char labellen=0;
+ unsigned int lenpos=0;
+
+#line 336 "dnslabeltext.cc"
+ {
+ cs = dnsnameraw_start;
+ }
+
+#line 341 "dnslabeltext.cc"
+ {
+ int _klen;
+ unsigned int _trans;
+ const char *_acts;
+ unsigned int _nacts;
+ const unsigned char *_keys;
+
+ if ( p == pe )
+ goto _test_eof;
+ if ( cs == 0 )
+ goto _out;
+_resume:
+ _keys = _dnsnameraw_trans_keys + _dnsnameraw_key_offsets[cs];
+ _trans = _dnsnameraw_index_offsets[cs];
+
+ _klen = _dnsnameraw_single_lengths[cs];
+ if ( _klen > 0 ) {
+ const unsigned char *_lower = _keys;
+ const unsigned char *_mid;
+ const unsigned char *_upper = _keys + _klen - 1;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + ((_upper-_lower) >> 1);
+ if ( (*p) < *_mid )
+ _upper = _mid - 1;
+ else if ( (*p) > *_mid )
+ _lower = _mid + 1;
+ else {
+ _trans += (unsigned int)(_mid - _keys);
+ goto _match;
+ }
+ }
+ _keys += _klen;
+ _trans += _klen;
+ }
+
+ _klen = _dnsnameraw_range_lengths[cs];
+ if ( _klen > 0 ) {
+ const unsigned char *_lower = _keys;
+ const unsigned char *_mid;
+ const unsigned char *_upper = _keys + (_klen<<1) - 2;
+ while (1) {
+ if ( _upper < _lower )
+ break;
+
+ _mid = _lower + (((_upper-_lower) >> 1) & ~1);
+ if ( (*p) < _mid[0] )
+ _upper = _mid - 2;
+ else if ( (*p) > _mid[1] )
+ _lower = _mid + 2;
+ else {
+ _trans += (unsigned int)((_mid - _keys)>>1);
+ goto _match;
+ }
+ }
+ _trans += _klen;
+ }
+
+_match:
+ cs = _dnsnameraw_trans_targs[_trans];
+
+ if ( _dnsnameraw_trans_actions[_trans] == 0 )
+ goto _again;
+
+ _acts = _dnsnameraw_actions + _dnsnameraw_trans_actions[_trans];
+ _nacts = (unsigned int) *_acts++;
+ while ( _nacts-- > 0 )
+ {
+ switch ( *_acts++ )
+ {
+ case 0:
+#line 113 "dnslabeltext.rl"
+ {
+ if (labellen < 0 || labellen > 63) {
+ throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
+ }
+ ret[lenpos]=labellen;
+ labellen=0;
+ }
+ break;
+ case 1:
+#line 120 "dnslabeltext.rl"
+ {
+ lenpos=ret.size();
+ ret.append(1, (char)0);
+ labellen=0;
+ }
+ break;
+ case 2:
+#line 126 "dnslabeltext.rl"
+ {
+ char c = *p;
+ ret.append(1, c);
+ labellen++;
+ }
+ break;
+ case 3:
+#line 131 "dnslabeltext.rl"
+ {
+ char c = *p;
+ val *= 10;
+ val += c-'0';
+ }
+ break;
+ case 4:
+#line 136 "dnslabeltext.rl"
+ {
+ ret.append(1, val);
+ labellen++;
+ val=0;
+ }
+ break;
+ case 5:
+#line 142 "dnslabeltext.rl"
+ {
+ ret.append(1, *(p));
+ labellen++;
+ }
+ break;
+#line 463 "dnslabeltext.cc"
+ }
+ }
+
+_again:
+ if ( cs == 0 )
+ goto _out;
+ if ( ++p != pe )
+ goto _resume;
+ _test_eof: {}
+ if ( p == eof )
+ {
+ const char *__acts = _dnsnameraw_actions + _dnsnameraw_eof_actions[cs];
+ unsigned int __nacts = (unsigned int) *__acts++;
+ while ( __nacts-- > 0 ) {
+ switch ( *__acts++ ) {
+ case 0:
+#line 113 "dnslabeltext.rl"
+ {
+ if (labellen < 0 || labellen > 63) {
+ throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
+ }
+ ret[lenpos]=labellen;
+ labellen=0;
+ }
+ break;
+ case 4:
+#line 136 "dnslabeltext.rl"
+ {
+ ret.append(1, val);
+ labellen++;
+ val=0;
+ }
+ break;
+#line 497 "dnslabeltext.cc"
+ }
+ }
+ }
+
+ _out: {}
+ }
+
+#line 163 "dnslabeltext.rl"
+
+
+ if ( cs < dnsnameraw_first_final ) {
+ throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
+ }
+ ret.append(1, (char)0);
+ return ret;
+};
+
+
+
+#if 0
+int main()
+{
+ //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\"";
+ char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\"";
+ //char blah[]="\"abc \\097\\098 def\"";
+ printf("Input: '%s'\n", blah);
+ vector<string> res=dnstext(blah);
+ cerr<<res.size()<<" segments"<<endl;
+ cerr<<res[0]<<endl;
+}
+#endif
--- /dev/null
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <unistd.h>
+#include <string>
+#include "dnsname.hh"
+#include "namespaces.hh"
+
+namespace {
+void appendSplit(vector<string>& ret, string& segment, char c)
+{
+ if(segment.size()>254) {
+ ret.push_back(segment);
+ segment.clear();
+ }
+ segment.append(1, c);
+}
+
+}
+
+vector<string> segmentDNSText(const string& input )
+{
+ // cerr<<"segmentDNSText("<<input<<")"<<endl;
+%%{
+ machine dnstext;
+ write data;
+ alphtype unsigned char;
+}%%
+ (void)dnstext_error; // silence warnings
+ (void)dnstext_en_main;
+ const char *p = input.c_str(), *pe = input.c_str() + input.length();
+ const char* eof = pe;
+ int cs;
+ char val = 0;
+
+ string segment;
+ vector<string> ret;
+
+ %%{
+ action segmentEnd {
+ ret.push_back(segment);
+ segment.clear();
+ }
+ action segmentBegin {
+ segment.clear();
+ }
+
+ action reportEscaped {
+ char c = *fpc;
+ appendSplit(ret, segment, c);
+ }
+ action reportEscapedNumber {
+ char c = *fpc;
+ val *= 10;
+ val += c-'0';
+
+ }
+ action doneEscapedNumber {
+ appendSplit(ret, segment, val);
+ val=0;
+ }
+
+ action reportPlain {
+ appendSplit(ret, segment, *(fpc));
+ }
+
+ escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
+ plain = ((extend-'\\'-'"')|'\n'|'\t') $ reportPlain;
+ txtElement = escaped | plain;
+
+ main := (('"' txtElement* '"' space?) >segmentBegin %segmentEnd)+;
+
+ # Initialize and execute.
+ write init;
+ write exec;
+ }%%
+
+ if ( cs < dnstext_first_final ) {
+ throw runtime_error("Unable to parse DNS TXT '"+input+"'");
+ }
+
+ return ret;
+};
+
+
+DNSName::string_t segmentDNSNameRaw(const char* realinput)
+{
+%%{
+ machine dnsnameraw;
+ write data;
+ alphtype unsigned char;
+}%%
+ (void)dnsnameraw_error; // silence warnings
+ (void)dnsnameraw_en_main;
+
+ DNSName::string_t ret;
+
+ if(!*realinput || *realinput == '.') {
+ ret.append(1, (char)0);
+ return ret;
+ }
+
+ unsigned int inputlen=strlen(realinput);
+ ret.reserve(inputlen+1);
+
+ const char *p = realinput, *pe = realinput + inputlen;
+ const char* eof = pe;
+ int cs;
+ char val = 0;
+ char labellen=0;
+ unsigned int lenpos=0;
+ %%{
+ action labelEnd {
+ if (labellen < 0 || labellen > 63) {
+ throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': invalid label length "+std::to_string(labellen));
+ }
+ ret[lenpos]=labellen;
+ labellen=0;
+ }
+ action labelBegin {
+ lenpos=ret.size();
+ ret.append(1, (char)0);
+ labellen=0;
+ }
+
+ action reportEscaped {
+ char c = *fpc;
+ ret.append(1, c);
+ labellen++;
+ }
+ action reportEscapedNumber {
+ char c = *fpc;
+ val *= 10;
+ val += c-'0';
+ }
+ action doneEscapedNumber {
+ ret.append(1, val);
+ labellen++;
+ val=0;
+ }
+
+ action reportPlain {
+ ret.append(1, *(fpc));
+ labellen++;
+ }
+
+ escaped = '\\' (([^0-9]@reportEscaped) | ([0-9]{3}$reportEscapedNumber%doneEscapedNumber));
+ plain = (extend-'\\'-'.') $ reportPlain;
+ labelElement = escaped | plain;
+
+ label = labelElement+ >labelBegin %labelEnd;
+
+ main:= label ('.' label )* '.'?;
+
+ #main := labelElement((labelElement+ '.') >labelBegin %labelEnd)+;
+
+ # label = (plain | escaped | escdecb)+ >label_init %label_fin;
+ # dnsname := '.'? label ('.' label >label_sep)* '.'?;
+
+ # Initialize and execute.
+ write init;
+ write exec;
+ }%%
+
+ if ( cs < dnsnameraw_first_final ) {
+ throw runtime_error("Unable to parse DNS name '"+string(realinput)+"': cs="+std::to_string(cs));
+ }
+ ret.append(1, (char)0);
+ return ret;
+};
+
+
+
+#if 0
+int main()
+{
+ //char blah[]="\"blah\" \"bleh\" \"bloeh\\\"bleh\" \"\\97enzo\"";
+ char blah[]="\"v=spf1 ip4:67.106.74.128/25 ip4:63.138.42.224/28 ip4:65.204.46.224/27 \\013\\010ip4:66.104.217.176/28 \\013\\010ip4:209.48.147.0/27 ~all\"";
+ //char blah[]="\"abc \\097\\098 def\"";
+ printf("Input: '%s'\n", blah);
+ vector<string> res=dnstext(blah);
+ cerr<<res.size()<<" segments"<<endl;
+ cerr<<res[0]<<endl;
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+syntax = "proto2";
+
+message PBDNSMessage {
+ enum Type {
+ DNSQueryType = 1;
+ DNSResponseType = 2;
+ }
+ enum SocketFamily {
+ INET = 1; // IPv4 (RFC 791)
+ INET6 = 2; // IPv6 (RFC 2460)
+ }
+ enum SocketProtocol {
+ UDP = 1; // User Datagram Protocol (RFC 768)
+ TCP = 2; // Transmission Control Protocol (RFC 793)
+ }
+ required Type type = 1;
+ optional bytes messageId = 2;
+ optional bytes serverIdentity = 3;
+ optional SocketFamily socketFamily = 4;
+ optional SocketProtocol socketProtocol = 5;
+ optional bytes from = 6;
+ optional bytes to = 7;
+ optional uint64 inBytes = 8;
+ optional uint32 timeSec = 9;
+ optional uint32 timeUsec = 10;
+ optional uint32 id = 11;
+
+ message DNSQuestion {
+ optional string qName = 1;
+ optional uint32 qType = 2;
+ optional uint32 qClass = 3;
+ }
+ optional DNSQuestion question = 12;
+
+ message DNSResponse {
+ message DNSRR {
+ optional string name = 1;
+ optional uint32 type = 2;
+ optional uint32 class = 3;
+ optional uint32 ttl = 4;
+ optional bytes rdata = 5;
+ }
+ optional uint32 rcode = 1;
+ repeated DNSRR rrs = 2;
+ optional string appliedPolicy = 3;
+ repeated string tags = 4;
+ optional uint32 queryTimeSec = 5;
+ optional uint32 queryTimeUsec = 6;
+ }
+
+ optional DNSResponse response = 13;
+ optional bytes originalRequestorSubnet = 14;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsname.hh"
+#include <boost/format.hpp>
+#include <string>
+
+#include "dnswriter.hh"
+#include "misc.hh"
+
+#include <boost/functional/hash.hpp>
+
+/* raw storage
+ in DNS label format, with trailing 0. W/o trailing 0, we are 'empty'
+ www.powerdns.com = 3www8powerdns3com0
+*/
+
+std::ostream & operator<<(std::ostream &os, const DNSName& d)
+{
+ return os <<d.toLogString();
+}
+
+DNSName::DNSName(const char* p)
+{
+ if(p[0]==0 || (p[0]=='.' && p[1]==0)) {
+ d_storage.assign(1, (char)0);
+ } else {
+ if(!strchr(p, '\\')) {
+ unsigned char lenpos=0;
+ unsigned char labellen=0;
+ size_t plen=strlen(p);
+ const char* const pbegin=p, *pend=p+plen;
+ d_storage.reserve(plen+1);
+ for(auto iter = pbegin; iter != pend; ) {
+ lenpos = d_storage.size();
+ if(*iter=='.')
+ throw std::runtime_error("Found . in wrong position in DNSName "+string(p));
+ d_storage.append(1, (char)0);
+ labellen=0;
+ auto begiter=iter;
+ for(; iter != pend && *iter!='.'; ++iter) {
+ labellen++;
+ }
+ d_storage.append(begiter,iter);
+ if(iter != pend)
+ ++iter;
+ if(labellen > 63)
+ throw std::range_error("label too long to append");
+
+ if(iter-pbegin > 254) // reserve two bytes, one for length and one for the root label
+ throw std::range_error("name too long to append");
+
+ d_storage[lenpos]=labellen;
+ }
+ d_storage.append(1, (char)0);
+ }
+ else {
+ d_storage=segmentDNSNameRaw(p);
+ if(d_storage.size() > 255) {
+ throw std::range_error("name too long");
+ }
+ }
+ }
+}
+
+
+DNSName::DNSName(const char* pos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, uint16_t minOffset)
+{
+ if (offset >= len)
+ throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
+
+ if(!uncompress) {
+ if(const void * fnd=memchr(pos+offset, 0, len-offset)) {
+ d_storage.reserve(2+(const char*)fnd-(pos+offset));
+ }
+ }
+
+ packetParser(pos, len, offset, uncompress, qtype, qclass, consumed, 0, minOffset);
+}
+
+// this should be the __only__ dns name parser in PowerDNS.
+void DNSName::packetParser(const char* qpos, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset)
+{
+ const unsigned char* pos=(const unsigned char*)qpos;
+ unsigned char labellen;
+ const unsigned char *opos = pos;
+
+ if (offset >= len)
+ throw std::range_error("Trying to read past the end of the buffer ("+std::to_string(offset)+ " >= "+std::to_string(len)+")");
+ if (offset < (int) minOffset)
+ throw std::range_error("Trying to read before the beginning of the buffer ("+std::to_string(offset)+ " < "+std::to_string(minOffset)+")");
+
+ const unsigned char* end = pos + len;
+ pos += offset;
+ while((labellen=*pos++) && pos < end) { // "scan and copy"
+ if(labellen >= 0xc0) {
+ if(!uncompress)
+ throw std::range_error("Found compressed label, instructed not to follow");
+
+ labellen &= (~0xc0);
+ int newpos = (labellen << 8) + *(const unsigned char*)pos;
+
+ if(newpos < offset) {
+ if(newpos < (int) minOffset)
+ throw std::range_error("Invalid label position during decompression ("+std::to_string(newpos)+ " < "+std::to_string(minOffset)+")");
+ if (++depth > 100)
+ throw std::range_error("Abort label decompression after 100 redirects");
+ packetParser((const char*)opos, len, newpos, true, 0, 0, 0, depth, minOffset);
+ } else
+ throw std::range_error("Found a forward reference during label decompression");
+ pos++;
+ break;
+ } else if(labellen & 0xc0) {
+ throw std::range_error("Found an invalid label length in qname (only one of the first two bits is set)");
+ }
+ if (pos + labellen < end) {
+ appendRawLabel((const char*)pos, labellen);
+ }
+ else
+ throw std::range_error("Found an invalid label length in qname");
+ pos+=labellen;
+ }
+ if(d_storage.empty())
+ d_storage.append(1, (char)0); // we just parsed the root
+ if(consumed)
+ *consumed = pos - opos - offset;
+ if(qtype) {
+ if (pos + 2 > end) {
+ throw std::range_error("Trying to read qtype past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")");
+ }
+ *qtype=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1);
+ }
+ pos+=2;
+ if(qclass) {
+ if (pos + 2 > end) {
+ throw std::range_error("Trying to read qclass past the end of the buffer ("+std::to_string((pos - opos) + 2)+ " > "+std::to_string(len)+")");
+ }
+ *qclass=(*(const unsigned char*)pos)*256 + *((const unsigned char*)pos+1);
+ }
+}
+
+std::string DNSName::toString(const std::string& separator, const bool trailing) const
+{
+ if (empty()) {
+ throw std::out_of_range("Attempt to print an unset dnsname");
+ }
+
+ if(isRoot())
+ return trailing ? separator : "";
+
+ std::string ret;
+ for(const auto& s : getRawLabels()) {
+ ret+= escapeLabel(s) + separator;
+ }
+
+ return ret.substr(0, ret.size()-!trailing);
+}
+
+std::string DNSName::toLogString() const
+{
+ if (empty()) {
+ return "(empty)";
+ }
+
+ return toStringRootDot();
+}
+
+std::string DNSName::toDNSString() const
+{
+ if (empty())
+ throw std::out_of_range("Attempt to DNSString an unset dnsname");
+
+ return std::string(d_storage.c_str(), d_storage.length());
+}
+
+std::string DNSName::toDNSStringLC() const
+{
+ return toLower(toDNSString()); // label lengths are always < 'A'
+}
+
+/**
+ * Get the length of the DNSName on the wire
+ *
+ * @return the total wirelength of the DNSName
+ */
+size_t DNSName::wirelength() const {
+ return d_storage.length();
+}
+
+// Are WE part of parent
+bool DNSName::isPartOf(const DNSName& parent) const
+{
+ if(parent.empty() || empty())
+ throw std::out_of_range("empty dnsnames aren't part of anything");
+
+ if(parent.d_storage.size() > d_storage.size())
+ return false;
+
+ // this is slightly complicated since we can't start from the end, since we can't see where a label begins/ends then
+ for(auto us=d_storage.cbegin(); us<d_storage.cend(); us+=*us+1) {
+ auto distance = std::distance(us,d_storage.cend());
+ if (distance < 0 || static_cast<size_t>(distance) < parent.d_storage.size()) {
+ break;
+ }
+ if (static_cast<size_t>(distance) == parent.d_storage.size()) {
+ auto p = parent.d_storage.cbegin();
+ for(; us != d_storage.cend(); ++us, ++p) {
+ if(dns2_tolower(*p) != dns2_tolower(*us))
+ return false;
+ }
+ return true;
+ }
+ if (*us < 0) {
+ throw std::out_of_range("negative label length in dnsname");
+ }
+ }
+ return false;
+}
+
+DNSName DNSName::makeRelative(const DNSName& zone) const
+{
+ DNSName ret(*this);
+ ret.makeUsRelative(zone);
+ return ret.empty() ? zone : ret; // HACK FIXME400
+}
+void DNSName::makeUsRelative(const DNSName& zone)
+{
+ if (isPartOf(zone)) {
+ d_storage.erase(d_storage.size()-zone.d_storage.size());
+ d_storage.append(1, (char)0); // put back the trailing 0
+ }
+ else
+ clear();
+}
+
+DNSName DNSName::labelReverse() const
+{
+ DNSName ret;
+
+ if(isRoot())
+ return *this; // we don't create the root automatically below
+
+ if (!empty()) {
+ vector<string> l=getRawLabels();
+ while(!l.empty()) {
+ ret.appendRawLabel(l.back());
+ l.pop_back();
+ }
+ }
+ return ret;
+}
+
+void DNSName::appendRawLabel(const std::string& label)
+{
+ appendRawLabel(label.c_str(), label.length());
+}
+
+void DNSName::appendRawLabel(const char* start, unsigned int length)
+{
+ if(length==0)
+ throw std::range_error("no such thing as an empty label to append");
+ if(length > 63)
+ throw std::range_error("label too long to append");
+ if(d_storage.size() + length > 254) // reserve one byte for the label length
+ throw std::range_error("name too long to append");
+
+ if(d_storage.empty()) {
+ d_storage.append(1, (char)length);
+ }
+ else {
+ *d_storage.rbegin()=(char)length;
+ }
+ d_storage.append(start, length);
+ d_storage.append(1, (char)0);
+}
+
+void DNSName::prependRawLabel(const std::string& label)
+{
+ if(label.empty())
+ throw std::range_error("no such thing as an empty label to prepend");
+ if(label.size() > 63)
+ throw std::range_error("label too long to prepend");
+ if(d_storage.size() + label.size() > 254) // reserve one byte for the label length
+ throw std::range_error("name too long to prepend");
+
+ if(d_storage.empty())
+ d_storage.append(1, (char)0);
+
+ string_t prep(1, (char)label.size());
+ prep.append(label.c_str(), label.size());
+ d_storage = prep+d_storage;
+}
+
+bool DNSName::slowCanonCompare(const DNSName& rhs) const
+{
+ auto ours=getRawLabels(), rhsLabels = rhs.getRawLabels();
+ return std::lexicographical_compare(ours.rbegin(), ours.rend(), rhsLabels.rbegin(), rhsLabels.rend(), CIStringCompare());
+}
+
+vector<string> DNSName::getRawLabels() const
+{
+ vector<string> ret;
+ ret.reserve(countLabels());
+ // 3www4ds9a2nl0
+ for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1) {
+ ret.push_back({(const char*)p+1, (size_t)*p}); // XXX FIXME
+ }
+ return ret;
+}
+
+
+bool DNSName::chopOff()
+{
+ if(d_storage.empty() || d_storage[0]==0)
+ return false;
+ d_storage.erase(0, (unsigned int)d_storage[0]+1);
+ return true;
+}
+
+bool DNSName::isWildcard() const
+{
+ if(d_storage.size() < 2)
+ return false;
+ auto p = d_storage.begin();
+ return (*p == 0x01 && *++p == '*');
+}
+
+unsigned int DNSName::countLabels() const
+{
+ unsigned int count=0;
+ for(const unsigned char* p = (const unsigned char*) d_storage.c_str(); p < ((const unsigned char*) d_storage.c_str()) + d_storage.size() && *p; p+=*p+1)
+ ++count;
+ return count;
+}
+
+void DNSName::trimToLabels(unsigned int to)
+{
+ while(countLabels() > to && chopOff())
+ ;
+}
+
+bool DNSName::operator==(const DNSName& rhs) const
+{
+ if(rhs.empty() != empty() || rhs.d_storage.size() != d_storage.size())
+ return false;
+
+ auto us = d_storage.crbegin();
+ auto p = rhs.d_storage.crbegin();
+ for(; us != d_storage.crend() && p != rhs.d_storage.crend(); ++us, ++p) { // why does this go backward?
+ if(dns2_tolower(*p) != dns2_tolower(*us))
+ return false;
+ }
+ return true;
+}
+
+size_t hash_value(DNSName const& d)
+{
+ return d.hash();
+}
+
+string DNSName::escapeLabel(const std::string& label)
+{
+ string ret;
+ ret.reserve(label.size()); // saves 15% on bulk .COM load
+ for(uint8_t p : label) {
+ if(p=='.')
+ ret+="\\.";
+ else if(p=='\\')
+ ret+="\\\\";
+ else if(p > 0x21 && p < 0x7e)
+ ret.append(1, (char)p);
+ else {
+ ret+="\\" + (boost::format("%03d") % (unsigned int)p).str();
+ }
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <string>
+#include <vector>
+#include <set>
+#include <deque>
+#include <strings.h>
+#include <stdexcept>
+
+#include <boost/version.hpp>
+
+// it crashes on OSX and doesn't compile on OpenBSD
+#if BOOST_VERSION >= 104800 && ! defined( __APPLE__ ) && ! defined(__OpenBSD__)
+#include <boost/container/string.hpp>
+#endif
+
+uint32_t burtleCI(const unsigned char* k, uint32_t lengh, uint32_t init);
+
+// #include "dns.hh"
+// #include "logger.hh"
+
+//#include <ext/vstring.h>
+
+/* Quest in life:
+ accept escaped ascii presentations of DNS names and store them "natively"
+ accept a DNS packet with an offset, and extract a DNS name from it
+ build up DNSNames with prepend and append of 'raw' unescaped labels
+
+ Be able to turn them into ASCII and "DNS name in a packet" again on request
+
+ Provide some common operators for comparison, detection of being part of another domain
+
+ NOTE: For now, everything MUST be . terminated, otherwise it is an error
+*/
+
+inline char dns2_tolower(char c)
+{
+ if(c>='A' && c<='Z')
+ c+='a'-'A';
+ return c;
+}
+
+class DNSName
+{
+public:
+ DNSName() {} //!< Constructs an *empty* DNSName, NOT the root!
+ explicit DNSName(const char* p); //!< Constructs from a human formatted, escaped presentation
+ explicit DNSName(const std::string& str) : DNSName(str.c_str()) {}; //!< Constructs from a human formatted, escaped presentation
+ DNSName(const char* p, int len, int offset, bool uncompress, uint16_t* qtype=0, uint16_t* qclass=0, unsigned int* consumed=0, uint16_t minOffset=0); //!< Construct from a DNS Packet, taking the first question if offset=12
+
+ bool isPartOf(const DNSName& rhs) const; //!< Are we part of the rhs name?
+ bool operator==(const DNSName& rhs) const; //!< DNS-native comparison (case insensitive) - empty compares to empty
+ bool operator!=(const DNSName& other) const { return !(*this == other); }
+
+ std::string toString(const std::string& separator=".", const bool trailing=true) const; //!< Our human-friendly, escaped, representation
+ std::string toLogString() const; //!< like plain toString, but returns (empty) on empty names
+ std::string toStringNoDot() const { return toString(".", false); }
+ std::string toStringRootDot() const { if(isRoot()) return "."; else return toString(".", false); }
+ std::string toDNSString() const; //!< Our representation in DNS native format
+ std::string toDNSStringLC() const; //!< Our representation in DNS native format, lower cased
+ void appendRawLabel(const std::string& str); //!< Append this unescaped label
+ void appendRawLabel(const char* start, unsigned int length); //!< Append this unescaped label
+ void prependRawLabel(const std::string& str); //!< Prepend this unescaped label
+ std::vector<std::string> getRawLabels() const; //!< Individual raw unescaped labels
+ bool chopOff(); //!< Turn www.powerdns.com. into powerdns.com., returns false for .
+ DNSName makeRelative(const DNSName& zone) const;
+ DNSName makeLowerCase() const
+ {
+ DNSName ret(*this);
+ ret.makeUsLowerCase();
+ return ret;
+ }
+ void makeUsLowerCase()
+ {
+ for(auto & c : d_storage) {
+ c=dns2_tolower(c);
+ }
+ }
+ void makeUsRelative(const DNSName& zone);
+ DNSName labelReverse() const;
+ bool isWildcard() const;
+ unsigned int countLabels() const;
+ size_t wirelength() const; //!< Number of total bytes in the name
+ bool empty() const { return d_storage.empty(); }
+ bool isRoot() const { return d_storage.size()==1 && d_storage[0]==0; }
+ void clear() { d_storage.clear(); }
+ void trimToLabels(unsigned int);
+ size_t hash(size_t init=0) const
+ {
+ return burtleCI((const unsigned char*)d_storage.c_str(), d_storage.size(), init);
+ }
+ DNSName& operator+=(const DNSName& rhs)
+ {
+ if(d_storage.size() + rhs.d_storage.size() > 256) // one extra byte for the second root label
+ throw std::range_error("name too long");
+ if(rhs.empty())
+ return *this;
+
+ if(d_storage.empty())
+ d_storage+=rhs.d_storage;
+ else
+ d_storage.replace(d_storage.length()-1, rhs.d_storage.length(), rhs.d_storage);
+
+ return *this;
+ }
+
+ bool operator<(const DNSName& rhs) const // this delivers _some_ kind of ordering, but not one useful in a DNS context. Really fast though.
+ {
+ return std::lexicographical_compare(d_storage.rbegin(), d_storage.rend(),
+ rhs.d_storage.rbegin(), rhs.d_storage.rend(),
+ [](const char& a, const char& b) {
+ return dns2_tolower(a) < dns2_tolower(b);
+ }); // note that this is case insensitive, including on the label lengths
+ }
+
+ inline bool canonCompare(const DNSName& rhs) const;
+ bool slowCanonCompare(const DNSName& rhs) const;
+
+#if BOOST_VERSION >= 104800 && ! defined( __APPLE__ ) && ! defined(__OpenBSD__)
+ typedef boost::container::string string_t;
+#else
+ typedef std::string string_t;
+#endif
+
+private:
+ string_t d_storage;
+
+ void packetParser(const char* p, int len, int offset, bool uncompress, uint16_t* qtype, uint16_t* qclass, unsigned int* consumed, int depth, uint16_t minOffset);
+ static std::string escapeLabel(const std::string& orig);
+ static std::string unescapeLabel(const std::string& orig);
+};
+
+size_t hash_value(DNSName const& d);
+
+
+inline bool DNSName::canonCompare(const DNSName& rhs) const
+{
+ // 01234567890abcd
+ // us: 1a3www4ds9a2nl
+ // rhs: 3www6online3com
+ // to compare, we start at the back, is nl < com? no -> done
+ //
+ // 0,2,6,a
+ // 0,4,a
+
+ uint8_t ourpos[64], rhspos[64];
+ uint8_t ourcount=0, rhscount=0;
+ //cout<<"Asked to compare "<<toString()<<" to "<<rhs.toString()<<endl;
+ for(const unsigned char* p = (const unsigned char*)d_storage.c_str(); p < (const unsigned char*)d_storage.c_str() + d_storage.size() && *p && ourcount < sizeof(ourpos); p+=*p+1)
+ ourpos[ourcount++]=(p-(const unsigned char*)d_storage.c_str());
+ for(const unsigned char* p = (const unsigned char*)rhs.d_storage.c_str(); p < (const unsigned char*)rhs.d_storage.c_str() + rhs.d_storage.size() && *p && rhscount < sizeof(rhspos); p+=*p+1)
+ rhspos[rhscount++]=(p-(const unsigned char*)rhs.d_storage.c_str());
+
+ if(ourcount == sizeof(ourpos) || rhscount==sizeof(rhspos)) {
+ return slowCanonCompare(rhs);
+ }
+
+ for(;;) {
+ if(ourcount == 0 && rhscount != 0)
+ return true;
+ if(ourcount == 0 && rhscount == 0)
+ return false;
+ if(ourcount !=0 && rhscount == 0)
+ return false;
+ ourcount--;
+ rhscount--;
+
+ bool res=std::lexicographical_compare(
+ d_storage.c_str() + ourpos[ourcount] + 1,
+ d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
+ rhs.d_storage.c_str() + rhspos[rhscount] + 1,
+ rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
+ [](const char& a, const char& b) {
+ return dns2_tolower(a) < dns2_tolower(b);
+ });
+
+ // cout<<"Forward: "<<res<<endl;
+ if(res)
+ return true;
+
+ res=std::lexicographical_compare( rhs.d_storage.c_str() + rhspos[rhscount] + 1,
+ rhs.d_storage.c_str() + rhspos[rhscount] + 1 + *(rhs.d_storage.c_str() + rhspos[rhscount]),
+ d_storage.c_str() + ourpos[ourcount] + 1,
+ d_storage.c_str() + ourpos[ourcount] + 1 + *(d_storage.c_str() + ourpos[ourcount]),
+ [](const char& a, const char& b) {
+ return dns2_tolower(a) < dns2_tolower(b);
+ });
+ // cout<<"Reverse: "<<res<<endl;
+ if(res)
+ return false;
+ }
+ return false;
+}
+
+
+struct CanonDNSNameCompare: public std::binary_function<DNSName, DNSName, bool>
+{
+ bool operator()(const DNSName&a, const DNSName& b) const
+ {
+ return a.canonCompare(b);
+ }
+};
+
+inline DNSName operator+(const DNSName& lhs, const DNSName& rhs)
+{
+ DNSName ret=lhs;
+ ret += rhs;
+ return ret;
+}
+
+/* Quest in life: serve as a rapid block list. If you add a DNSName to a root SuffixMatchNode,
+ anything part of that domain will return 'true' in check */
+struct SuffixMatchNode
+{
+ SuffixMatchNode(const std::string& name_="", bool endNode_=false) : name(name_), endNode(endNode_)
+ {}
+ std::string name;
+ std::string d_human;
+ mutable std::set<SuffixMatchNode> children;
+ mutable bool endNode;
+ bool operator<(const SuffixMatchNode& rhs) const
+ {
+ return strcasecmp(name.c_str(), rhs.name.c_str()) < 0;
+ }
+
+ void add(const DNSName& name)
+ {
+ if(!d_human.empty())
+ d_human.append(", ");
+ d_human += name.toString();
+ add(name.getRawLabels());
+ }
+
+ void add(std::vector<std::string> labels) const
+ {
+ if(labels.empty()) { // this allows insertion of the root
+ endNode=true;
+ }
+ else if(labels.size()==1) {
+ auto res=children.insert(SuffixMatchNode(*labels.begin(), true));
+ if(!res.second) {
+ if(!res.first->endNode) {
+ res.first->endNode = true;
+ }
+ }
+ }
+ else {
+ auto res=children.insert(SuffixMatchNode(*labels.rbegin(), false));
+ labels.pop_back();
+ res.first->add(labels);
+ }
+ }
+
+ bool check(const DNSName& name) const
+ {
+ if(children.empty()) // speed up empty set
+ return endNode;
+ return check(name.getRawLabels());
+ }
+
+ bool check(std::vector<std::string> labels) const
+ {
+ if(labels.empty()) // optimization
+ return endNode;
+
+ SuffixMatchNode smn(*labels.rbegin());
+ auto child = children.find(smn);
+ if(child == children.end())
+ return endNode;
+ labels.pop_back();
+ return child->check(labels);
+ }
+
+ std::string toString() const
+ {
+ return d_human;
+ }
+
+};
+
+std::ostream & operator<<(std::ostream &os, const DNSName& d);
+namespace std {
+ template <>
+ struct hash<DNSName> {
+ size_t operator () (const DNSName& dn) const { return dn.hash(0); }
+ };
+}
+
+DNSName::string_t segmentDNSNameRaw(const char* input); // from ragel
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include <cstdio>
+#include <cstdlib>
+#include <sys/types.h>
+#include <iostream>
+#include <string>
+#include <errno.h>
+#include <boost/tokenizer.hpp>
+#include <boost/algorithm/string.hpp>
+#include <algorithm>
+
+#include "dnsseckeeper.hh"
+#include "dns.hh"
+#include "dnsbackend.hh"
+#include "pdnsexception.hh"
+#include "dnspacket.hh"
+#include "logger.hh"
+#include "arguments.hh"
+#include "dnswriter.hh"
+#include "dnsparser.hh"
+#include "dnsrecords.hh"
+#include "dnssecinfra.hh"
+#include "base64.hh"
+#include "ednssubnet.hh"
+#include "gss_context.hh"
+#include "dns_random.hh"
+
+bool DNSPacket::s_doEDNSSubnetProcessing;
+uint16_t DNSPacket::s_udpTruncationThreshold;
+
+DNSPacket::DNSPacket(bool isQuery)
+{
+ d_wrapped=false;
+ d_compress=true;
+ d_tcp=false;
+ d_wantsnsid=false;
+ d_haveednssubnet = false;
+ d_dnssecOk=false;
+ d_ednsversion=0;
+ d_ednsrcode=0;
+ memset(&d, 0, sizeof(d));
+ qclass = QClass::IN;
+ d_tsig_algo = TSIG_MD5;
+ d_havetsig = false;
+ d_socket = -1;
+ d_maxreplylen = 0;
+ d_tsigtimersonly = false;
+ d_haveednssection = false;
+ d_isQuery = isQuery;
+}
+
+const string& DNSPacket::getString()
+{
+ if(!d_wrapped)
+ wrapup();
+
+ return d_rawpacket;
+}
+
+ComboAddress DNSPacket::getRemote() const
+{
+ return d_remote;
+}
+
+uint16_t DNSPacket::getRemotePort() const
+{
+ return d_remote.sin4.sin_port;
+}
+
+DNSPacket::DNSPacket(const DNSPacket &orig)
+{
+ DLOG(L<<"DNSPacket copy constructor called!"<<endl);
+ d_socket=orig.d_socket;
+ d_remote=orig.d_remote;
+ d_dt=orig.d_dt;
+ d_compress=orig.d_compress;
+ d_tcp=orig.d_tcp;
+ qtype=orig.qtype;
+ qclass=orig.qclass;
+ qdomain=orig.qdomain;
+ qdomainwild=orig.qdomainwild;
+ qdomainzone=orig.qdomainzone;
+ d_maxreplylen = orig.d_maxreplylen;
+ d_ednsping = orig.d_ednsping;
+ d_wantsnsid = orig.d_wantsnsid;
+ d_anyLocal = orig.d_anyLocal;
+ d_eso = orig.d_eso;
+ d_haveednssubnet = orig.d_haveednssubnet;
+ d_haveednssection = orig.d_haveednssection;
+ d_ednsversion = orig.d_ednsversion;
+ d_ednsrcode = orig.d_ednsrcode;
+ d_dnssecOk = orig.d_dnssecOk;
+ d_rrs=orig.d_rrs;
+
+ d_tsigkeyname = orig.d_tsigkeyname;
+ d_tsigprevious = orig.d_tsigprevious;
+ d_tsigtimersonly = orig.d_tsigtimersonly;
+ d_trc = orig.d_trc;
+ d_tsigsecret = orig.d_tsigsecret;
+
+ d_havetsig = orig.d_havetsig;
+ d_wrapped=orig.d_wrapped;
+
+ d_rawpacket=orig.d_rawpacket;
+ d_tsig_algo=orig.d_tsig_algo;
+ d=orig.d;
+
+ d_isQuery = orig.d_isQuery;
+}
+
+void DNSPacket::setRcode(int v)
+{
+ d.rcode=v;
+}
+
+void DNSPacket::setAnswer(bool b)
+{
+ if(b) {
+ d_rawpacket.assign(12,(char)0);
+ memset((void *)&d,0,sizeof(d));
+
+ d.qr=b;
+ }
+}
+
+void DNSPacket::setA(bool b)
+{
+ d.aa=b;
+}
+
+void DNSPacket::setID(uint16_t id)
+{
+ d.id=id;
+}
+
+void DNSPacket::setRA(bool b)
+{
+ d.ra=b;
+}
+
+void DNSPacket::setRD(bool b)
+{
+ d.rd=b;
+}
+
+void DNSPacket::setOpcode(uint16_t opcode)
+{
+ d.opcode=opcode;
+}
+
+
+void DNSPacket::clearRecords()
+{
+ d_rrs.clear();
+}
+
+void DNSPacket::addRecord(const DNSResourceRecord &rr)
+{
+ // this removes duplicates from the packet in case we are not compressing
+ // for AXFR, no such checking is performed!
+ // cerr<<"addrecord, content=["<<rr.content<<"]"<<endl;
+ if(d_compress)
+ for(vector<DNSResourceRecord>::const_iterator i=d_rrs.begin();i!=d_rrs.end();++i)
+ if(rr.qname==i->qname && rr.qtype==i->qtype && rr.content==i->content) {
+ return;
+ }
+ // cerr<<"added to d_rrs"<<endl;
+ d_rrs.push_back(rr);
+}
+
+
+
+static int rrcomp(const DNSResourceRecord &A, const DNSResourceRecord &B)
+{
+ if(A.d_place < B.d_place)
+ return 1;
+
+ return 0;
+}
+
+vector<DNSResourceRecord*> DNSPacket::getAPRecords()
+{
+ vector<DNSResourceRecord*> arrs;
+
+ for(vector<DNSResourceRecord>::iterator i=d_rrs.begin();
+ i!=d_rrs.end();
+ ++i)
+ {
+ if(i->d_place!=DNSResourceRecord::ADDITIONAL &&
+ (i->qtype.getCode()==QType::MX ||
+ i->qtype.getCode()==QType::NS ||
+ i->qtype.getCode()==QType::SRV))
+ {
+ arrs.push_back(&*i);
+ }
+ }
+
+ return arrs;
+
+}
+
+vector<DNSResourceRecord*> DNSPacket::getAnswerRecords()
+{
+ vector<DNSResourceRecord*> arrs;
+
+ for(vector<DNSResourceRecord>::iterator i=d_rrs.begin();
+ i!=d_rrs.end();
+ ++i)
+ {
+ if(i->d_place!=DNSResourceRecord::ADDITIONAL)
+ arrs.push_back(&*i);
+ }
+ return arrs;
+}
+
+
+void DNSPacket::setCompress(bool compress)
+{
+ d_compress=compress;
+ d_rawpacket.reserve(65000);
+ d_rrs.reserve(200);
+}
+
+bool DNSPacket::couldBeCached()
+{
+ return d_ednsping.empty() && !d_wantsnsid && qclass==QClass::IN && !d_havetsig;
+}
+
+unsigned int DNSPacket::getMinTTL()
+{
+ unsigned int minttl = UINT_MAX;
+ for(const DNSResourceRecord& rr : d_rrs) {
+ if (rr.ttl < minttl)
+ minttl = rr.ttl;
+ }
+
+ return minttl;
+}
+
+bool DNSPacket::isEmpty()
+{
+ return (d_rrs.empty());
+}
+
+/** Must be called before attempting to access getData(). This function stuffs all resource
+ * records found in rrs into the data buffer. It also frees resource records queued for us.
+ */
+void DNSPacket::wrapup()
+{
+ if(d_wrapped) {
+ return;
+ }
+
+ DNSResourceRecord rr;
+ vector<DNSResourceRecord>::iterator pos;
+
+ // we now need to order rrs so that the different sections come at the right place
+ // we want a stable sort, based on the d_place field
+
+ stable_sort(d_rrs.begin(),d_rrs.end(), rrcomp);
+ static bool mustNotShuffle = ::arg().mustDo("no-shuffle");
+
+ if(!d_tcp && !mustNotShuffle) {
+ shuffle(d_rrs);
+ }
+ d_wrapped=true;
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, qdomain, qtype.getCode(), qclass);
+
+ pw.getHeader()->rcode=d.rcode;
+ pw.getHeader()->opcode = d.opcode;
+ pw.getHeader()->aa=d.aa;
+ pw.getHeader()->ra=d.ra;
+ pw.getHeader()->qr=d.qr;
+ pw.getHeader()->id=d.id;
+ pw.getHeader()->rd=d.rd;
+ pw.getHeader()->tc=d.tc;
+
+ DNSPacketWriter::optvect_t opts;
+ if(d_wantsnsid) {
+ const static string mode_server_id=::arg()["server-id"];
+ if(mode_server_id != "disabled") {
+ opts.push_back(make_pair(3, mode_server_id));
+ }
+ }
+
+ if(!d_ednsping.empty()) {
+ opts.push_back(make_pair(4, d_ednsping));
+ }
+
+
+ if(!d_rrs.empty() || !opts.empty() || d_haveednssubnet || d_haveednssection) {
+ try {
+ uint8_t maxScopeMask=0;
+ for(pos=d_rrs.begin(); pos < d_rrs.end(); ++pos) {
+ // cerr<<"during wrapup, content=["<<pos->content<<"]"<<endl;
+ maxScopeMask = max(maxScopeMask, pos->scopeMask);
+
+ if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') {
+ pos->content="\""+pos->content+"\"";
+ }
+ if(pos->content.empty()) // empty contents confuse the MOADNS setup
+ pos->content=".";
+
+ pw.startRecord(pos->qname, pos->qtype.getCode(), pos->ttl, pos->qclass, pos->d_place);
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), pos->qclass, pos->content));
+ drc->toPacket(pw);
+ if(pw.size() + 20U > (d_tcp ? 65535 : getMaxReplyLen())) { // 20 = room for EDNS0
+ pw.rollback();
+ if(pos->d_place == DNSResourceRecord::ANSWER || pos->d_place == DNSResourceRecord::AUTHORITY) {
+ pw.getHeader()->tc=1;
+ }
+ goto noCommit;
+ }
+ }
+
+ // if(!pw.getHeader()->tc) // protect against double commit from addSignature
+
+ if(!d_rrs.empty()) pw.commit();
+
+ noCommit:;
+
+ if(d_haveednssubnet) {
+ string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso);
+ EDNSSubnetOpts eso = d_eso;
+ eso.scope = Netmask(eso.source.getNetwork(), maxScopeMask);
+
+ string opt = makeEDNSSubnetOptsString(eso);
+ opts.push_back(make_pair(8, opt)); // 'EDNS SUBNET'
+ }
+
+ if(!opts.empty() || d_haveednssection || d_dnssecOk)
+ {
+ pw.addOpt(s_udpTruncationThreshold, d_ednsrcode, d_dnssecOk ? EDNSOpts::DNSSECOK : 0, opts);
+ pw.commit();
+ }
+ }
+ catch(std::exception& e) {
+ L<<Logger::Warning<<"Exception: "<<e.what()<<endl;
+ throw;
+ }
+ }
+
+ if(d_trc.d_algoName.countLabels())
+ addTSIG(pw, &d_trc, d_tsigkeyname, d_tsigsecret, d_tsigprevious, d_tsigtimersonly);
+
+ d_rawpacket.assign((char*)&packet[0], packet.size());
+
+ // copy RR counts so LPE can read them
+ d.qdcount = pw.getHeader()->qdcount;
+ d.ancount = pw.getHeader()->ancount;
+ d.nscount = pw.getHeader()->nscount;
+ d.arcount = pw.getHeader()->arcount;
+}
+
+void DNSPacket::setQuestion(int op, const DNSName &qd, int newqtype)
+{
+ memset(&d,0,sizeof(d));
+ d.id=dns_random(0xffff);
+ d.rd=d.tc=d.aa=false;
+ d.qr=false;
+ d.qdcount=1; // is htons'ed later on
+ d.ancount=d.arcount=d.nscount=0;
+ d.opcode=op;
+ qdomain=qd;
+ qtype=newqtype;
+}
+
+/** convenience function for creating a reply packet from a question packet. Do not forget to delete it after use! */
+DNSPacket *DNSPacket::replyPacket() const
+{
+ DNSPacket *r=new DNSPacket(false);
+ r->setSocket(d_socket);
+ r->d_anyLocal=d_anyLocal;
+ r->setRemote(&d_remote);
+ r->setAnswer(true); // this implies the allocation of the header
+ r->setA(true); // and we are authoritative
+ r->setRA(0); // no recursion available
+ r->setRD(d.rd); // if you wanted to recurse, answer will say you wanted it
+ r->setID(d.id);
+ r->setOpcode(d.opcode);
+
+ r->d_dt=d_dt;
+ r->d.qdcount=1;
+ r->d_tcp = d_tcp;
+ r->qdomain = qdomain;
+ r->qtype = qtype;
+ r->qclass = qclass;
+ r->d_maxreplylen = d_maxreplylen;
+ r->d_ednsping = d_ednsping;
+ r->d_wantsnsid = d_wantsnsid;
+ r->d_dnssecOk = d_dnssecOk;
+ r->d_eso = d_eso;
+ r->d_haveednssubnet = d_haveednssubnet;
+ r->d_haveednssection = d_haveednssection;
+ r->d_ednsversion = 0;
+ r->d_ednsrcode = 0;
+
+ if(d_tsigkeyname.countLabels()) {
+ r->d_tsigkeyname = d_tsigkeyname;
+ r->d_tsigprevious = d_tsigprevious;
+ r->d_trc = d_trc;
+ r->d_tsigsecret = d_tsigsecret;
+ r->d_tsigtimersonly = d_tsigtimersonly;
+ }
+ r->d_havetsig = d_havetsig;
+ return r;
+}
+
+void DNSPacket::spoofQuestion(const DNSPacket *qd)
+{
+ d_wrapped=true; // if we do this, don't later on wrapup
+
+ int labellen;
+ string::size_type i=sizeof(d);
+
+ for(;;) {
+ labellen = qd->d_rawpacket[i];
+ if(!labellen) break;
+ i++;
+ d_rawpacket.replace(i, labellen, qd->d_rawpacket, i, labellen);
+ i = i + labellen;
+ }
+}
+
+int DNSPacket::noparse(const char *mesg, size_t length)
+{
+ d_rawpacket.assign(mesg,length);
+ if(length < 12) {
+ L << Logger::Warning << "Ignoring packet: too short ("<<length<<" < 12) from "
+ << d_remote.toStringWithPort()<< endl;
+ return -1;
+ }
+ d_wantsnsid=false;
+ d_ednsping.clear();
+ d_maxreplylen=512;
+ memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
+ return 0;
+}
+
+void DNSPacket::setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyname, const string& secret, const string& previous, bool timersonly)
+{
+ d_trc=tr;
+ d_trc.d_origID = (((d.id & 0xFF)<<8) | ((d.id & 0xFF00)>>8));
+ d_tsigkeyname = keyname;
+ d_tsigsecret = secret;
+ d_tsigprevious = previous;
+ d_tsigtimersonly=timersonly;
+}
+
+bool DNSPacket::getTSIGDetails(TSIGRecordContent* trc, DNSName* keyname, string* message) const
+{
+ MOADNSParser mdp(d_isQuery, d_rawpacket);
+
+ if(!mdp.getTSIGPos())
+ return false;
+
+ bool gotit=false;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if(i->first.d_type == QType::TSIG && i->first.d_class == QType::ANY) {
+ // cast can fail, f.e. if d_content is an UnknownRecordContent.
+ shared_ptr<TSIGRecordContent> content = std::dynamic_pointer_cast<TSIGRecordContent>(i->first.d_content);
+ if (!content) {
+ L<<Logger::Error<<"TSIG record has no or invalid content (invalid packet)"<<endl;
+ return false;
+ }
+ *trc = *content;
+ *keyname = i->first.d_name;
+ gotit=true;
+ }
+ }
+ if(!gotit)
+ return false;
+ if(message)
+ *message = makeTSIGMessageFromTSIGPacket(d_rawpacket, mdp.getTSIGPos(), *keyname, *trc, "", false); // if you change rawpacket to getString it breaks!
+
+ return true;
+}
+
+bool DNSPacket::getTKEYRecord(TKEYRecordContent *tr, DNSName *keyname) const
+{
+ MOADNSParser mdp(d_isQuery, d_rawpacket);
+ bool gotit=false;
+
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if (gotit) {
+ L<<Logger::Error<<"More than one TKEY record found in query"<<endl;
+ return false;
+ }
+
+ if(i->first.d_type == QType::TKEY) {
+ // cast can fail, f.e. if d_content is an UnknownRecordContent.
+ shared_ptr<TKEYRecordContent> content = std::dynamic_pointer_cast<TKEYRecordContent>(i->first.d_content);
+ if (!content) {
+ L<<Logger::Error<<"TKEY record has no or invalid content (invalid packet)"<<endl;
+ return false;
+ }
+ *tr = *content;
+ *keyname = i->first.d_name;
+ gotit=true;
+ }
+ }
+
+ return gotit;
+}
+
+/** This function takes data from the network, possibly received with recvfrom, and parses
+ it into our class. Results of calling this function multiple times on one packet are
+ unknown. Returns -1 if the packet cannot be parsed.
+*/
+int DNSPacket::parse(const char *mesg, size_t length)
+try
+{
+ d_rawpacket.assign(mesg,length);
+ d_wrapped=true;
+ if(length < 12) {
+ L << Logger::Warning << "Ignoring packet: too short from "
+ << getRemote() << endl;
+ return -1;
+ }
+
+ MOADNSParser mdp(d_isQuery, d_rawpacket);
+ EDNSOpts edo;
+
+ // ANY OPTION WHICH *MIGHT* BE SET DOWN BELOW SHOULD BE CLEARED FIRST!
+
+ d_wantsnsid=false;
+ d_dnssecOk=false;
+ d_ednsping.clear();
+ d_havetsig = mdp.getTSIGPos();
+ d_haveednssubnet = false;
+ d_haveednssection = false;
+
+
+ if(getEDNSOpts(mdp, &edo)) {
+ d_haveednssection=true;
+ d_maxreplylen=std::min(edo.d_packetsize, s_udpTruncationThreshold);
+// cerr<<edo.d_Z<<endl;
+ if(edo.d_Z & EDNSOpts::DNSSECOK)
+ d_dnssecOk=true;
+
+ for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
+ iter != edo.d_options.end();
+ ++iter) {
+ if(iter->first == 3) {// 'EDNS NSID'
+ d_wantsnsid=1;
+ }
+ else if(iter->first == 5) {// 'EDNS PING'
+ d_ednsping = iter->second;
+ }
+ else if(s_doEDNSSubnetProcessing && (iter->first == 8)) { // 'EDNS SUBNET'
+ if(getEDNSSubnetOptsFromString(iter->second, &d_eso)) {
+ //cerr<<"Parsed, source: "<<d_eso.source.toString()<<", scope: "<<d_eso.scope.toString()<<", family = "<<d_eso.scope.getNetwork().sin4.sin_family<<endl;
+ d_haveednssubnet=true;
+ }
+ }
+ else {
+ // cerr<<"Have an option #"<<iter->first<<": "<<makeHexDump(iter->second)<<endl;
+ }
+ }
+ d_ednsversion = edo.d_version;
+ d_ednsrcode = edo.d_extRCode;
+ }
+ else {
+ d_maxreplylen=512;
+ }
+
+ memcpy((void *)&d,(const void *)d_rawpacket.c_str(),12);
+ qdomain=mdp.d_qname;
+ // if(!qdomain.empty()) // strip dot
+ // boost::erase_tail(qdomain, 1);
+
+ if(!ntohs(d.qdcount)) {
+ if(!d_tcp) {
+ L << Logger::Warning << "No question section in packet from " << getRemote() <<", error="<<RCode::to_s(d.rcode)<<endl;
+ return -1;
+ }
+ }
+
+ qtype=mdp.d_qtype;
+ qclass=mdp.d_qclass;
+ return 0;
+}
+catch(std::exception& e) {
+ return -1;
+}
+
+unsigned int DNSPacket::getMaxReplyLen()
+{
+ return d_maxreplylen;
+}
+
+void DNSPacket::setMaxReplyLen(int bytes)
+{
+ d_maxreplylen=bytes;
+}
+
+//! Use this to set where this packet was received from or should be sent to
+void DNSPacket::setRemote(const ComboAddress *s)
+{
+ d_remote=*s;
+}
+
+bool DNSPacket::hasEDNSSubnet()
+{
+ return d_haveednssubnet;
+}
+
+bool DNSPacket::hasEDNS()
+{
+ return d_haveednssection;
+}
+
+Netmask DNSPacket::getRealRemote() const
+{
+ if(d_haveednssubnet)
+ return d_eso.source;
+ return Netmask(d_remote);
+}
+
+void DNSPacket::setSocket(Utility::sock_t sock)
+{
+ d_socket=sock;
+}
+
+void DNSPacket::commitD()
+{
+ d_rawpacket.replace(0,12,(char *)&d,12); // copy in d
+}
+
+bool checkForCorrectTSIG(const DNSPacket* q, UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc)
+{
+ string message;
+
+ if (!q->getTSIGDetails(trc, keyname, &message)) {
+ return false;
+ }
+
+ uint64_t delta = std::abs((int64_t)trc->d_time - (int64_t)time(0));
+ if(delta > trc->d_fudge) {
+ L<<Logger::Error<<"Packet for '"<<q->qdomain<<"' denied: TSIG (key '"<<*keyname<<"') time delta "<< delta <<" > 'fudge' "<<trc->d_fudge<<endl;
+ return false;
+ }
+
+ DNSName algoName = trc->d_algoName; // FIXME400
+ if (algoName == DNSName("hmac-md5.sig-alg.reg.int"))
+ algoName = DNSName("hmac-md5");
+
+ if (algoName == DNSName("gss-tsig")) {
+ if (!gss_verify_signature(*keyname, message, trc->d_mac)) {
+ L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: TSIG signature mismatch using '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
+ return false;
+ }
+ return true;
+ }
+
+ string secret64;
+ if(!B->getTSIGKey(*keyname, &algoName, &secret64)) {
+ L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: can't find TSIG key with name '"<<*keyname<<"' and algorithm '"<<algoName<<"'"<<endl;
+ return false;
+ }
+ if (trc->d_algoName == DNSName("hmac-md5"))
+ trc->d_algoName += DNSName("sig-alg.reg.int");
+
+ TSIGHashEnum algo;
+ if(!getTSIGHashEnum(trc->d_algoName, algo)) {
+ L<<Logger::Error<<"Unsupported TSIG HMAC algorithm " << trc->d_algoName.toString() << endl;
+ return false;
+ }
+
+ B64Decode(secret64, *secret);
+ bool result=calculateHMAC(*secret, message, algo) == trc->d_mac;
+ if(!result) {
+ L<<Logger::Error<<"Packet for domain '"<<q->qdomain<<"' denied: TSIG signature mismatch using '"<<*keyname<<"' and algorithm '"<<trc->d_algoName<<"'"<<endl;
+ }
+
+ return result;
+}
+
+const DNSName& DNSPacket::getTSIGKeyname() const {
+ return d_tsigkeyname;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef DNSPACKET_HH
+
+#if __GNUC__ == 2
+#if __GNUC_MINOR__ < 95
+ #error Your compiler is too old! Try g++ 3.3 or higher
+#else
+ #warning There are known problems with PowerDNS binaries compiled by gcc version 2.95 and 2.96!
+#endif
+#endif
+
+#define DNSPACKET_HH
+
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <sys/types.h>
+#include "iputils.hh"
+#include "ednssubnet.hh"
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+
+#include <iostream>
+#include <string>
+#include <vector>
+#include "qtype.hh"
+#include "dns.hh"
+#include "misc.hh"
+#include "utility.hh"
+#include "logger.hh"
+#include "pdnsexception.hh"
+#include "dnsrecords.hh"
+
+
+
+class UeberBackend;
+class DNSSECKeeper;
+
+//! This class represents DNS packets, either received or to be sent.
+class DNSPacket
+{
+public:
+ DNSPacket(bool isQuery);
+ DNSPacket(const DNSPacket &orig);
+
+ int noparse(const char *mesg, size_t len); //!< just suck the data inward
+ int parse(const char *mesg, size_t len); //!< parse a raw UDP or TCP packet and suck the data inward
+ const string& getString(); //!< for serialization - just passes the whole packet
+
+ // address & socket manipulation
+ void setRemote(const ComboAddress*);
+ ComboAddress getRemote() const;
+ Netmask getRealRemote() const;
+ ComboAddress getLocal() const
+ {
+ ComboAddress ca;
+ socklen_t len=sizeof(ca);
+ getsockname(d_socket, (sockaddr*)&ca, &len);
+ return ca;
+ }
+ uint16_t getRemotePort() const;
+
+ boost::optional<ComboAddress> d_anyLocal;
+
+ Utility::sock_t getSocket() const
+ {
+ return d_socket;
+ }
+ void setSocket(Utility::sock_t sock);
+
+
+ // these manipulate 'd'
+ void setA(bool); //!< make this packet authoritative - manipulates 'd'
+ void setID(uint16_t); //!< set the DNS id of this packet - manipulates 'd'
+ void setRA(bool); //!< set the Recursion Available flag - manipulates 'd'
+ void setRD(bool); //!< set the Recursion Desired flag - manipulates 'd'
+ void setAnswer(bool); //!< Make this packet an answer - clears the 'stringbuffer' first, if passed 'true', does nothing otherwise, manipulates 'd'
+
+ void setOpcode(uint16_t); //!< set the Opcode of this packet - manipulates 'd'
+ void setRcode(int v); //!< set the Rcode of this packet - manipulates 'd'
+
+ void clearRecords(); //!< when building a packet, wipe all previously added records (clears 'rrs')
+
+ /** Add a DNSResourceRecord to this packet. A DNSPacket (as does a DNS Packet) has 4 kinds of resource records. Questions,
+ Answers, Authority and Additional. See RFC 1034 and 1035 for details. You can specify where a record needs to go in the
+ DNSResourceRecord d_place field */
+ void addRecord(const DNSResourceRecord &); // adds to 'rrs'
+
+ void setQuestion(int op, const DNSName &qdomain, int qtype); // wipes 'd', sets a random id, creates start of packet (domain, type, class etc)
+
+ DTime d_dt; //!< the time this packet was created. replyPacket() copies this in for you, so d_dt becomes the time spent processing the question+answer
+ void wrapup(); // writes out queued rrs, and generates the binary packet. also shuffles. also rectifies dnsheader 'd', and copies it to the stringbuffer
+ void spoofQuestion(const DNSPacket *qd); //!< paste in the exact right case of the question. Useful for PacketCache
+ unsigned int getMinTTL(); //!< returns lowest TTL of any record in the packet
+ bool isEmpty(); //!< returns true if there are no rrs in the packet
+
+ vector<DNSResourceRecord*> getAPRecords(); //!< get a vector with DNSResourceRecords that need additional processing
+ vector<DNSResourceRecord*> getAnswerRecords(); //!< get a vector with DNSResourceRecords that are answers
+ void setCompress(bool compress);
+
+ DNSPacket *replyPacket() const; //!< convenience function that creates a virgin answer packet to this question
+
+ void commitD(); //!< copies 'd' into the stringbuffer
+ unsigned int getMaxReplyLen(); //!< retrieve the maximum length of the packet we should send in response
+ void setMaxReplyLen(int bytes); //!< set the max reply len (used when retrieving from the packet cache, and this changed)
+
+ bool couldBeCached(); //!< returns 0 if this query should bypass the packet cache
+ bool hasEDNSSubnet();
+ bool hasEDNS();
+ uint8_t getEDNSVersion() const { return d_ednsversion; };
+ void setEDNSRcode(uint16_t extRCode)
+ {
+ // WARNING: this is really 12 bits
+ d_ednsrcode=extRCode;
+ };
+ uint8_t getEDNSRCode() const { return d_ednsrcode; };
+ //////// DATA !
+
+ DNSName qdomain; //!< qname of the question 4 - unsure how this is used
+ DNSName qdomainwild; //!< wildcard matched by qname, used by LuaPolicyEngine
+ DNSName qdomainzone; //!< zone name for the answer (as reflected in SOA for negative responses), used by LuaPolicyEngine
+ string d_peer_principal;
+ const DNSName& getTSIGKeyname() const;
+
+ uint16_t qclass; //!< class of the question - should always be INternet 2
+ struct dnsheader d; //!< dnsheader at the start of the databuffer 12
+
+ QType qtype; //!< type of the question 2
+
+ TSIGRecordContent d_trc; //72
+
+ ComboAddress d_remote; //28
+ TSIGHashEnum d_tsig_algo; //4
+
+ bool d_tcp;
+ bool d_dnssecOk;
+ bool d_havetsig;
+
+ bool getTSIGDetails(TSIGRecordContent* tr, DNSName* keyname, string* message) const;
+ void setTSIGDetails(const TSIGRecordContent& tr, const DNSName& keyname, const string& secret, const string& previous, bool timersonly=false);
+ bool getTKEYRecord(TKEYRecordContent* tr, DNSName* keyname) const;
+
+ vector<DNSResourceRecord>& getRRS() { return d_rrs; }
+ static bool s_doEDNSSubnetProcessing;
+ static uint16_t s_udpTruncationThreshold; //2
+private:
+ void pasteQ(const char *question, int length); //!< set the question of this packet, useful for crafting replies
+
+ bool d_wrapped; // 1
+ int d_socket; // 4
+
+ string d_tsigsecret;
+ DNSName d_tsigkeyname;
+ string d_tsigprevious;
+
+ vector<DNSResourceRecord> d_rrs; // 8
+ string d_rawpacket; // this is where everything lives 8
+ string d_ednsping;
+ EDNSSubnetOpts d_eso;
+
+ int d_maxreplylen;
+ uint8_t d_ednsversion;
+ // WARNING! This is really 12 bits
+ uint16_t d_ednsrcode;
+
+ bool d_compress; // 1
+ bool d_tsigtimersonly;
+ bool d_wantsnsid;
+ bool d_haveednssubnet;
+ bool d_haveednssection;
+ bool d_isQuery;
+};
+
+
+bool checkForCorrectTSIG(const DNSPacket* q, UeberBackend* B, DNSName* keyname, string* secret, TSIGRecordContent* trc);
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dnsparser.hh"
+#include "dnswriter.hh"
+#include <boost/algorithm/string.hpp>
+#include <boost/format.hpp>
+
+#include "namespaces.hh"
+
+class UnknownRecordContent : public DNSRecordContent
+{
+public:
+ UnknownRecordContent(const DNSRecord& dr, PacketReader& pr)
+ : d_dr(dr)
+ {
+ pr.copyRecord(d_record, dr.d_clen);
+ }
+
+ UnknownRecordContent(const string& zone)
+ {
+ // parse the input
+ vector<string> parts;
+ stringtok(parts, zone);
+ if(parts.size()!=3 && !(parts.size()==2 && equals(parts[1],"0")) )
+ throw MOADNSException("Unknown record was stored incorrectly, need 3 fields, got "+std::to_string(parts.size())+": "+zone );
+ const string& relevant=(parts.size() > 2) ? parts[2] : "";
+ unsigned int total=pdns_stou(parts[1]);
+ if(relevant.size() % 2 || relevant.size() / 2 != total)
+ throw MOADNSException((boost::format("invalid unknown record length: size not equal to length field (%d != 2 * %d)") % relevant.size() % total).str());
+ string out;
+ out.reserve(total+1);
+ for(unsigned int n=0; n < total; ++n) {
+ int c;
+ sscanf(relevant.c_str()+2*n, "%02x", &c);
+ out.append(1, (char)c);
+ }
+
+ d_record.insert(d_record.end(), out.begin(), out.end());
+ }
+
+ string getZoneRepresentation(bool noDot) const override
+ {
+ ostringstream str;
+ str<<"\\# "<<(unsigned int)d_record.size()<<" ";
+ char hex[4];
+ for(size_t n=0; n<d_record.size(); ++n) {
+ snprintf(hex,sizeof(hex)-1, "%02x", d_record.at(n));
+ str << hex;
+ }
+ return str.str();
+ }
+
+ void toPacket(DNSPacketWriter& pw) override
+ {
+ pw.xfrBlob(string(d_record.begin(),d_record.end()));
+ }
+
+ uint16_t getType() const override
+ {
+ return d_dr.d_type;
+ }
+private:
+ DNSRecord d_dr;
+ vector<uint8_t> d_record;
+};
+
+shared_ptr<DNSRecordContent> DNSRecordContent::unserialize(const DNSName& qname, uint16_t qtype, const string& serialized)
+{
+ dnsheader dnsheader;
+ memset(&dnsheader, 0, sizeof(dnsheader));
+ dnsheader.qdcount=htons(1);
+ dnsheader.ancount=htons(1);
+
+ vector<uint8_t> packet; // build pseudo packet
+
+ /* will look like: dnsheader, 5 bytes, encoded qname, dns record header, serialized data */
+
+ string encoded=qname.toDNSString();
+
+ packet.resize(sizeof(dnsheader) + 5 + encoded.size() + sizeof(struct dnsrecordheader) + serialized.size());
+
+ uint16_t pos=0;
+
+ memcpy(&packet[0], &dnsheader, sizeof(dnsheader)); pos+=sizeof(dnsheader);
+
+ char tmp[6]="\x0" "\x0\x1" "\x0\x1"; // root question for ns_t_a
+ memcpy(&packet[pos], &tmp, 5); pos+=5;
+
+ memcpy(&packet[pos], encoded.c_str(), encoded.size()); pos+=(uint16_t)encoded.size();
+
+ struct dnsrecordheader drh;
+ drh.d_type=htons(qtype);
+ drh.d_class=htons(1);
+ drh.d_ttl=0;
+ drh.d_clen=htons(serialized.size());
+
+ memcpy(&packet[pos], &drh, sizeof(drh)); pos+=sizeof(drh);
+ memcpy(&packet[pos], serialized.c_str(), serialized.size()); pos+=(uint16_t)serialized.size();
+
+ MOADNSParser mdp(false, (char*)&*packet.begin(), (unsigned int)packet.size());
+ shared_ptr<DNSRecordContent> ret= mdp.d_answers.begin()->first.d_content;
+ return ret;
+}
+
+DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr,
+ PacketReader& pr)
+{
+ uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
+
+ typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
+ if(i==getTypemap().end() || !i->second) {
+ return new UnknownRecordContent(dr, pr);
+ }
+
+ return i->second(dr, pr);
+}
+
+DNSRecordContent* DNSRecordContent::mastermake(uint16_t qtype, uint16_t qclass,
+ const string& content)
+{
+ zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
+ if(i==getZmakermap().end()) {
+ return new UnknownRecordContent(content);
+ }
+
+ return i->second(content);
+}
+
+std::unique_ptr<DNSRecordContent> DNSRecordContent::makeunique(uint16_t qtype, uint16_t qclass,
+ const string& content)
+{
+ zmakermap_t::const_iterator i=getZmakermap().find(make_pair(qclass, qtype));
+ if(i==getZmakermap().end()) {
+ return std::unique_ptr<DNSRecordContent>(new UnknownRecordContent(content));
+ }
+
+ return std::unique_ptr<DNSRecordContent>(i->second(content));
+}
+
+
+DNSRecordContent* DNSRecordContent::mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t oc) {
+ // For opcode UPDATE and where the DNSRecord is an answer record, we don't care about content, because this is
+ // not used within the prerequisite section of RFC2136, so - we can simply use unknownrecordcontent.
+ // For section 3.2.3, we do need content so we need to get it properly. But only for the correct Qclasses.
+ if (oc == Opcode::Update && dr.d_place == DNSResourceRecord::ANSWER && dr.d_class != 1)
+ return new UnknownRecordContent(dr, pr);
+
+ uint16_t searchclass = (dr.d_type == QType::OPT) ? 1 : dr.d_class; // class is invalid for OPT
+
+ typemap_t::const_iterator i=getTypemap().find(make_pair(searchclass, dr.d_type));
+ if(i==getTypemap().end() || !i->second) {
+ return new UnknownRecordContent(dr, pr);
+ }
+
+ return i->second(dr, pr);
+}
+
+
+DNSRecordContent::typemap_t& DNSRecordContent::getTypemap()
+{
+ static DNSRecordContent::typemap_t typemap;
+ return typemap;
+}
+
+DNSRecordContent::n2typemap_t& DNSRecordContent::getN2Typemap()
+{
+ static DNSRecordContent::n2typemap_t n2typemap;
+ return n2typemap;
+}
+
+DNSRecordContent::t2namemap_t& DNSRecordContent::getT2Namemap()
+{
+ static DNSRecordContent::t2namemap_t t2namemap;
+ return t2namemap;
+}
+
+
+DNSRecordContent::zmakermap_t& DNSRecordContent::getZmakermap()
+{
+ static DNSRecordContent::zmakermap_t zmakermap;
+ return zmakermap;
+}
+
+DNSRecord::DNSRecord(const DNSResourceRecord& rr)
+{
+ d_name = rr.qname;
+ d_type = rr.qtype.getCode();
+ d_ttl = rr.ttl;
+ d_class = rr.qclass;
+ d_place = rr.d_place;
+ d_clen = 0;
+ d_content = std::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(d_type, rr.qclass, rr.content));
+}
+
+void MOADNSParser::init(bool query, const char *packet, unsigned int len)
+{
+ if(len < sizeof(dnsheader))
+ throw MOADNSException("Packet shorter than minimal header");
+
+ memcpy(&d_header, packet, sizeof(dnsheader));
+
+ if(d_header.opcode != Opcode::Query && d_header.opcode != Opcode::Notify && d_header.opcode != Opcode::Update)
+ throw MOADNSException("Can't parse non-query packet with opcode="+ std::to_string(d_header.opcode));
+
+ d_header.qdcount=ntohs(d_header.qdcount);
+ d_header.ancount=ntohs(d_header.ancount);
+ d_header.nscount=ntohs(d_header.nscount);
+ d_header.arcount=ntohs(d_header.arcount);
+
+ if (query && (d_header.qdcount > 1))
+ throw MOADNSException("Query with QD > 1 ("+std::to_string(d_header.qdcount)+")");
+
+ uint16_t contentlen=len-sizeof(dnsheader);
+
+ d_content.resize(contentlen);
+ copy(packet+sizeof(dnsheader), packet+len, d_content.begin());
+
+ unsigned int n=0;
+
+ PacketReader pr(d_content);
+ bool validPacket=false;
+ try {
+ d_qtype = d_qclass = 0; // sometimes replies come in with no question, don't present garbage then
+
+ for(n=0;n < d_header.qdcount; ++n) {
+ d_qname=pr.getName();
+ d_qtype=pr.get16BitInt();
+ d_qclass=pr.get16BitInt();
+ }
+
+ struct dnsrecordheader ah;
+ vector<unsigned char> record;
+ validPacket=true;
+ d_answers.reserve((unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount));
+ for(n=0;n < (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount); ++n) {
+ DNSRecord dr;
+
+ if(n < d_header.ancount)
+ dr.d_place=DNSResourceRecord::ANSWER;
+ else if(n < d_header.ancount + d_header.nscount)
+ dr.d_place=DNSResourceRecord::AUTHORITY;
+ else
+ dr.d_place=DNSResourceRecord::ADDITIONAL;
+
+ unsigned int recordStartPos=pr.d_pos;
+
+ DNSName name=pr.getName();
+
+ pr.getDnsrecordheader(ah);
+ dr.d_ttl=ah.d_ttl;
+ dr.d_type=ah.d_type;
+ dr.d_class=ah.d_class;
+
+ dr.d_name=name;
+ dr.d_clen=ah.d_clen;
+
+ if (query && (dr.d_place == DNSResourceRecord::ANSWER || dr.d_place == DNSResourceRecord::AUTHORITY || (dr.d_type != QType::OPT && dr.d_type != QType::TSIG && dr.d_type != QType::SIG && dr.d_type != QType::TKEY) || ((dr.d_type == QType::TSIG || dr.d_type == QType::SIG || dr.d_type == QType::TKEY) && dr.d_class != QClass::ANY))) {
+// cerr<<"discarding RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
+ dr.d_content=std::shared_ptr<DNSRecordContent>(new UnknownRecordContent(dr, pr));
+ }
+ else {
+// cerr<<"parsing RR, query is "<<query<<", place is "<<dr.d_place<<", type is "<<dr.d_type<<", class is "<<dr.d_class<<endl;
+ dr.d_content=std::shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(dr, pr, d_header.opcode));
+ }
+
+ d_answers.push_back(make_pair(dr, pr.d_pos));
+
+ if(dr.d_type == QType::TSIG && dr.d_class == QClass::ANY) {
+ if(dr.d_place != DNSResourceRecord::ADDITIONAL || n != (unsigned int)(d_header.ancount + d_header.nscount + d_header.arcount) - 1) {
+ throw MOADNSException("Packet ("+d_qname.toString()+"|#"+std::to_string(d_qtype)+") has a TSIG record in an invalid position.");
+ }
+ d_tsigPos = recordStartPos + sizeof(struct dnsheader);
+ }
+ }
+
+#if 0
+ if(pr.d_pos!=contentlen) {
+ throw MOADNSException("Packet ("+d_qname+"|#"+std::to_string(d_qtype)+") has trailing garbage ("+ std::to_string(pr.d_pos) + " < " +
+ std::to_string(contentlen) + ")");
+ }
+#endif
+ }
+ catch(std::out_of_range &re) {
+ if(validPacket && d_header.tc) { // don't sweat it over truncated packets, but do adjust an, ns and arcount
+ if(n < d_header.ancount) {
+ d_header.ancount=n; d_header.nscount = d_header.arcount = 0;
+ }
+ else if(n < d_header.ancount + d_header.nscount) {
+ d_header.nscount = n - d_header.ancount; d_header.arcount=0;
+ }
+ else {
+ d_header.arcount = n - d_header.ancount - d_header.nscount;
+ }
+ }
+ else {
+ throw MOADNSException("Error parsing packet of "+std::to_string(len)+" bytes (rd="+
+ std::to_string(d_header.rd)+
+ "), out of bounds: "+string(re.what()));
+ }
+ }
+}
+
+
+void PacketReader::getDnsrecordheader(struct dnsrecordheader &ah)
+{
+ unsigned int n;
+ unsigned char *p=reinterpret_cast<unsigned char*>(&ah);
+
+ for(n=0; n < sizeof(dnsrecordheader); ++n)
+ p[n]=d_content.at(d_pos++);
+
+ ah.d_type=ntohs(ah.d_type);
+ ah.d_class=ntohs(ah.d_class);
+ ah.d_clen=ntohs(ah.d_clen);
+ ah.d_ttl=ntohl(ah.d_ttl);
+
+ d_startrecordpos=d_pos; // needed for getBlob later on
+ d_recordlen=ah.d_clen;
+}
+
+
+void PacketReader::copyRecord(vector<unsigned char>& dest, uint16_t len)
+{
+ dest.resize(len);
+ if(!len)
+ return;
+
+ for(uint16_t n=0;n<len;++n) {
+ dest.at(n)=d_content.at(d_pos++);
+ }
+}
+
+void PacketReader::copyRecord(unsigned char* dest, uint16_t len)
+{
+ if(d_pos + len > d_content.size())
+ throw std::out_of_range("Attempt to copy outside of packet");
+
+ memcpy(dest, &d_content.at(d_pos), len);
+ d_pos+=len;
+}
+
+void PacketReader::xfr48BitInt(uint64_t& ret)
+{
+ ret=0;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+}
+
+uint32_t PacketReader::get32BitInt()
+{
+ uint32_t ret=0;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+ ret<<=8;
+ ret+=d_content.at(d_pos++);
+
+ return ret;
+}
+
+
+uint16_t PacketReader::get16BitInt()
+{
+ return get16BitInt(d_content, d_pos);
+}
+
+uint16_t PacketReader::get16BitInt(const vector<unsigned char>&content, uint16_t& pos)
+{
+ uint16_t ret=0;
+ ret+=content.at(pos++);
+ ret<<=8;
+ ret+=content.at(pos++);
+
+ return ret;
+}
+
+uint8_t PacketReader::get8BitInt()
+{
+ return d_content.at(d_pos++);
+}
+
+DNSName PacketReader::getName()
+{
+ unsigned int consumed;
+ try {
+ DNSName dn((const char*) d_content.data() - 12, d_content.size() + 12, d_pos + sizeof(dnsheader), true /* uncompress */, 0 /* qtype */, 0 /* qclass */, &consumed, sizeof(dnsheader));
+
+ // the -12 fakery is because we don't have the header in 'd_content', but we do need to get
+ // the internal offsets to work
+ d_pos+=consumed;
+ return dn;
+ }
+ catch(std::range_error& re)
+ {
+ throw std::out_of_range(string("dnsname issue: ")+re.what());
+ }
+
+ catch(...)
+ {
+ throw std::out_of_range("dnsname issue");
+ }
+ throw PDNSException("PacketReader::getName(): name is empty");
+}
+
+static string txtEscape(const string &name)
+{
+ string ret;
+ char ebuf[5];
+
+ for(string::const_iterator i=name.begin();i!=name.end();++i) {
+ if((unsigned char) *i > 127 || (unsigned char) *i < 32) {
+ snprintf(ebuf, sizeof(ebuf), "\\%03u", (unsigned char)*i);
+ ret += ebuf;
+ }
+ else if(*i=='"' || *i=='\\'){
+ ret += '\\';
+ ret += *i;
+ }
+ else
+ ret += *i;
+ }
+ return ret;
+}
+
+// exceptions thrown here do not result in logging in the main pdns auth server - just so you know!
+string PacketReader::getText(bool multi, bool lenField)
+{
+ string ret;
+ ret.reserve(40);
+ while(d_pos < d_startrecordpos + d_recordlen ) {
+ if(!ret.empty()) {
+ ret.append(1,' ');
+ }
+ uint16_t labellen;
+ if(lenField)
+ labellen=d_content.at(d_pos++);
+ else
+ labellen=d_recordlen - (d_pos - d_startrecordpos);
+
+ ret.append(1,'"');
+ if(labellen) { // no need to do anything for an empty string
+ string val(&d_content.at(d_pos), &d_content.at(d_pos+labellen-1)+1);
+ ret.append(txtEscape(val)); // the end is one beyond the packet
+ }
+ ret.append(1,'"');
+ d_pos+=labellen;
+ if(!multi)
+ break;
+ }
+
+ return ret;
+}
+
+string PacketReader::getUnquotedText(bool lenField)
+{
+ int16_t stop_at;
+ if(lenField)
+ stop_at = (uint8_t)d_content.at(d_pos) + d_pos + 1;
+ else
+ stop_at = d_recordlen;
+
+ if(stop_at == d_pos)
+ return "";
+
+ d_pos++;
+ string ret(&d_content.at(d_pos), &d_content.at(stop_at));
+ d_pos = stop_at;
+ return ret;
+}
+
+void PacketReader::xfrBlob(string& blob)
+try
+{
+ if(d_recordlen && !(d_pos == (d_startrecordpos + d_recordlen)))
+ blob.assign(&d_content.at(d_pos), &d_content.at(d_startrecordpos + d_recordlen - 1 ) + 1);
+ else
+ blob.clear();
+
+ d_pos = d_startrecordpos + d_recordlen;
+}
+catch(...)
+{
+ throw std::out_of_range("xfrBlob out of range");
+}
+
+void PacketReader::xfrBlobNoSpaces(string& blob, int length) {
+ xfrBlob(blob, length);
+}
+
+void PacketReader::xfrBlob(string& blob, int length)
+{
+ if(length) {
+ blob.assign(&d_content.at(d_pos), &d_content.at(d_pos + length - 1 ) + 1 );
+
+ d_pos += length;
+ }
+ else
+ blob.clear();
+}
+
+
+void PacketReader::xfrHexBlob(string& blob, bool keepReading)
+{
+ xfrBlob(blob);
+}
+
+//FIXME400 remove this method completely
+string simpleCompress(const string& elabel, const string& root)
+{
+ string label=elabel;
+ // FIXME400: this relies on the semi-canonical escaped output from getName
+ if(strchr(label.c_str(), '\\')) {
+ boost::replace_all(label, "\\.", ".");
+ boost::replace_all(label, "\\032", " ");
+ boost::replace_all(label, "\\\\", "\\");
+ }
+ typedef vector<pair<unsigned int, unsigned int> > parts_t;
+ parts_t parts;
+ vstringtok(parts, label, ".");
+ string ret;
+ ret.reserve(label.size()+4);
+ for(parts_t::const_iterator i=parts.begin(); i!=parts.end(); ++i) {
+ if(!root.empty() && !strncasecmp(root.c_str(), label.c_str() + i->first, 1 + label.length() - i->first)) { // also match trailing 0, hence '1 +'
+ const unsigned char rootptr[2]={0xc0,0x11};
+ ret.append((const char *) rootptr, 2);
+ return ret;
+ }
+ ret.append(1, (char)(i->second - i->first));
+ ret.append(label.c_str() + i->first, i->second - i->first);
+ }
+ ret.append(1, (char)0);
+ return ret;
+}
+
+
+/** Simple DNSPacketMangler. Ritual is: get a pointer into the packet and moveOffset() to beyond your needs
+ * If you survive that, feel free to read from the pointer */
+class DNSPacketMangler
+{
+public:
+ explicit DNSPacketMangler(std::string& packet)
+ : d_packet((char*) packet.c_str()), d_length(packet.length()), d_notyouroffset(12), d_offset(d_notyouroffset)
+ {}
+ DNSPacketMangler(char* packet, size_t length)
+ : d_packet(packet), d_length(length), d_notyouroffset(12), d_offset(d_notyouroffset)
+ {}
+
+ void skipLabel()
+ {
+ uint8_t len;
+ while((len=get8BitInt())) {
+ if(len >= 0xc0) { // extended label
+ get8BitInt();
+ return;
+ }
+ skipBytes(len);
+ }
+ }
+ void skipBytes(uint16_t bytes)
+ {
+ moveOffset(bytes);
+ }
+ uint32_t get32BitInt()
+ {
+ const char* p = d_packet + d_offset;
+ moveOffset(4);
+ uint32_t ret;
+ memcpy(&ret, (void*)p, sizeof(ret));
+ return ntohl(ret);
+ }
+ uint16_t get16BitInt()
+ {
+ const char* p = d_packet + d_offset;
+ moveOffset(2);
+ uint16_t ret;
+ memcpy(&ret, (void*)p, sizeof(ret));
+ return ntohs(ret);
+ }
+
+ uint8_t get8BitInt()
+ {
+ const char* p = d_packet + d_offset;
+ moveOffset(1);
+ return *p;
+ }
+
+ void skipRData()
+ {
+ int toskip = get16BitInt();
+ moveOffset(toskip);
+ }
+ void decreaseAndSkip32BitInt(uint32_t decrease)
+ {
+ const char *p = d_packet + d_offset;
+ moveOffset(4);
+
+ uint32_t tmp;
+ memcpy(&tmp, (void*) p, sizeof(tmp));
+ tmp = ntohl(tmp);
+ tmp-=decrease;
+ tmp = htonl(tmp);
+ memcpy(d_packet + d_offset-4, (const char*)&tmp, sizeof(tmp));
+ }
+ uint32_t getOffset() const
+ {
+ return d_offset;
+ }
+private:
+ void moveOffset(uint16_t by)
+ {
+ d_notyouroffset += by;
+ if(d_notyouroffset > d_length)
+ throw std::out_of_range("dns packet out of range: "+std::to_string(d_notyouroffset) +" > "
+ + std::to_string(d_length) );
+ }
+ char* d_packet;
+ size_t d_length;
+
+ uint32_t d_notyouroffset; // only 'moveOffset' can touch this
+ const uint32_t& d_offset; // look.. but don't touch
+
+};
+
+// method of operation: silently fail if it doesn't work - we're only trying to be nice, don't fall over on it
+void ageDNSPacket(char* packet, size_t length, uint32_t seconds)
+{
+ if(length < sizeof(dnsheader))
+ return;
+ try
+ {
+ dnsheader dh;
+ memcpy((void*)&dh, (const dnsheader*)packet, sizeof(dh));
+ uint64_t numrecords = ntohs(dh.ancount) + ntohs(dh.nscount) + ntohs(dh.arcount);
+ DNSPacketMangler dpm(packet, length);
+
+ uint64_t n;
+ for(n=0; n < ntohs(dh.qdcount) ; ++n) {
+ dpm.skipLabel();
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ // cerr<<"Skipped "<<n<<" questions, now parsing "<<numrecords<<" records"<<endl;
+ for(n=0; n < numrecords; ++n) {
+ dpm.skipLabel();
+
+ uint16_t dnstype = dpm.get16BitInt();
+ /* class */
+ dpm.skipBytes(2);
+
+ if(dnstype == QType::OPT) // not aging that one with a stick
+ break;
+
+ dpm.decreaseAndSkip32BitInt(seconds);
+ dpm.skipRData();
+ }
+ }
+ catch(...)
+ {
+ return;
+ }
+}
+
+void ageDNSPacket(std::string& packet, uint32_t seconds)
+{
+ ageDNSPacket((char*)packet.c_str(), packet.length(), seconds);
+}
+
+uint32_t getDNSPacketMinTTL(const char* packet, size_t length)
+{
+ uint32_t result = std::numeric_limits<uint32_t>::max();
+ if(length < sizeof(dnsheader)) {
+ return result;
+ }
+ try
+ {
+ const dnsheader* dh = (const dnsheader*) packet;
+ DNSPacketMangler dpm(const_cast<char*>(packet), length);
+
+ const uint16_t qdcount = ntohs(dh->qdcount);
+ for(size_t n = 0; n < qdcount; ++n) {
+ dpm.skipLabel();
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
+ for(size_t n = 0; n < numrecords; ++n) {
+ dpm.skipLabel();
+ const uint16_t dnstype = dpm.get16BitInt();
+ /* class */
+ dpm.skipBytes(2);
+
+ if(dnstype == QType::OPT)
+ break;
+
+ const uint32_t ttl = dpm.get32BitInt();
+ if (result > ttl)
+ result = ttl;
+
+ dpm.skipRData();
+ }
+ }
+ catch(...)
+ {
+ }
+ return result;
+}
+
+uint32_t getDNSPacketLength(const char* packet, size_t length)
+{
+ uint32_t result = length;
+ if(length < sizeof(dnsheader)) {
+ return result;
+ }
+ try
+ {
+ const dnsheader* dh = (const dnsheader*) packet;
+ DNSPacketMangler dpm(const_cast<char*>(packet), length);
+
+ const uint16_t qdcount = ntohs(dh->qdcount);
+ for(size_t n = 0; n < qdcount; ++n) {
+ dpm.skipLabel();
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ const size_t numrecords = ntohs(dh->ancount) + ntohs(dh->nscount) + ntohs(dh->arcount);
+ for(size_t n = 0; n < numrecords; ++n) {
+ dpm.skipLabel();
+ /* type (2), class (2) and ttl (4) */
+ dpm.skipBytes(8);
+ dpm.skipRData();
+ }
+ result = dpm.getOffset();
+ }
+ catch(...)
+ {
+ }
+ return result;
+}
+
+uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type)
+{
+ uint16_t result = 0;
+ if(length < sizeof(dnsheader)) {
+ return result;
+ }
+ try
+ {
+ const dnsheader* dh = (const dnsheader*) packet;
+ DNSPacketMangler dpm(const_cast<char*>(packet), length);
+
+ const uint16_t qdcount = ntohs(dh->qdcount);
+ for(size_t n = 0; n < qdcount; ++n) {
+ dpm.skipLabel();
+ if (section == 0) {
+ uint16_t dnstype = dpm.get16BitInt();
+ if (dnstype == type) {
+ result++;
+ }
+ /* class */
+ dpm.skipBytes(2);
+ } else {
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ }
+ const uint16_t ancount = ntohs(dh->ancount);
+ for(size_t n = 0; n < ancount; ++n) {
+ dpm.skipLabel();
+ if (section == 1) {
+ uint16_t dnstype = dpm.get16BitInt();
+ if (dnstype == type) {
+ result++;
+ }
+ /* class */
+ dpm.skipBytes(2);
+ } else {
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ /* ttl */
+ dpm.skipBytes(4);
+ dpm.skipRData();
+ }
+ const uint16_t nscount = ntohs(dh->nscount);
+ for(size_t n = 0; n < nscount; ++n) {
+ dpm.skipLabel();
+ if (section == 2) {
+ uint16_t dnstype = dpm.get16BitInt();
+ if (dnstype == type) {
+ result++;
+ }
+ /* class */
+ dpm.skipBytes(2);
+ } else {
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ /* ttl */
+ dpm.skipBytes(4);
+ dpm.skipRData();
+ }
+ const uint16_t arcount = ntohs(dh->arcount);
+ for(size_t n = 0; n < arcount; ++n) {
+ dpm.skipLabel();
+ if (section == 3) {
+ uint16_t dnstype = dpm.get16BitInt();
+ if (dnstype == type) {
+ result++;
+ }
+ /* class */
+ dpm.skipBytes(2);
+ } else {
+ /* type and class */
+ dpm.skipBytes(4);
+ }
+ /* ttl */
+ dpm.skipBytes(4);
+ dpm.skipRData();
+ }
+ }
+ catch(...)
+ {
+ }
+ return result;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef DNSPARSER_HH
+#define DNSPARSER_HH
+
+#include <map>
+#include <sstream>
+#include <stdexcept>
+#include <iostream>
+#include <vector>
+#include <errno.h>
+// #include <netinet/in.h>
+#include "misc.hh"
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include "dns.hh"
+#include "dnswriter.hh"
+#include "dnsname.hh"
+#include "pdnsexception.hh"
+
+/** DNS records have three representations:
+ 1) in the packet
+ 2) parsed in a class, ready for use
+ 3) in the zone
+
+ We should implement bidirectional transitions between 1&2 and 2&3.
+ Currently we have: 1 -> 2
+ 2 -> 3
+
+ We can add: 2 -> 1 easily by reversing the packetwriter
+ And we might be able to reverse 2 -> 3 as well
+*/
+
+#include "namespaces.hh"
+#include "namespaces.hh"
+
+class MOADNSException : public runtime_error
+{
+public:
+ MOADNSException(const string& str) : runtime_error(str)
+ {}
+};
+
+
+class MOADNSParser;
+
+class PacketReader
+{
+public:
+ PacketReader(const vector<uint8_t>& content)
+ : d_pos(0), d_startrecordpos(0), d_content(content)
+ {
+ if(content.size() > std::numeric_limits<uint16_t>::max())
+ throw std::out_of_range("packet too large");
+
+ d_recordlen = (uint16_t) content.size();
+ not_used = 0;
+ }
+
+ uint32_t get32BitInt();
+ uint16_t get16BitInt();
+ uint8_t get8BitInt();
+
+ void xfr48BitInt(uint64_t& val);
+
+ void xfr32BitInt(uint32_t& val)
+ {
+ val=get32BitInt();
+ }
+
+ void xfrIP(uint32_t& val)
+ {
+ xfr32BitInt(val);
+ val=htonl(val);
+ }
+
+ void xfrIP6(std::string &val) {
+ xfrBlob(val, 16);
+ }
+
+ void xfrTime(uint32_t& val)
+ {
+ xfr32BitInt(val);
+ }
+
+
+ void xfr16BitInt(uint16_t& val)
+ {
+ val=get16BitInt();
+ }
+
+ void xfrType(uint16_t& val)
+ {
+ xfr16BitInt(val);
+ }
+
+
+ void xfr8BitInt(uint8_t& val)
+ {
+ val=get8BitInt();
+ }
+
+
+ void xfrName(DNSName &name, bool compress=false, bool noDot=false)
+ {
+ name=getName();
+ }
+
+ void xfrText(string &text, bool multi=false, bool lenField=true)
+ {
+ text=getText(multi, lenField);
+ }
+
+ void xfrUnquotedText(string &text, bool lenField){
+ text=getUnquotedText(lenField);
+ }
+
+ void xfrBlob(string& blob);
+ void xfrBlobNoSpaces(string& blob, int len);
+ void xfrBlob(string& blob, int length);
+ void xfrHexBlob(string& blob, bool keepReading=false);
+
+ static uint16_t get16BitInt(const vector<unsigned char>&content, uint16_t& pos);
+
+ void getDnsrecordheader(struct dnsrecordheader &ah);
+ void copyRecord(vector<unsigned char>& dest, uint16_t len);
+ void copyRecord(unsigned char* dest, uint16_t len);
+
+ DNSName getName();
+ string getText(bool multi, bool lenField);
+ string getUnquotedText(bool lenField);
+
+ uint16_t d_pos;
+
+ bool eof() { return true; };
+
+private:
+ uint16_t d_startrecordpos; // needed for getBlob later on
+ uint16_t d_recordlen; // ditto
+ uint16_t not_used; // Alighns the whole class on 8-byte boundries
+ const vector<uint8_t>& d_content;
+};
+
+struct DNSRecord;
+
+class DNSRecordContent
+{
+public:
+ static DNSRecordContent* mastermake(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* mastermake(const DNSRecord &dr, PacketReader& pr, uint16_t opcode);
+ static DNSRecordContent* mastermake(uint16_t qtype, uint16_t qclass, const string& zone);
+ static std::unique_ptr<DNSRecordContent> makeunique(uint16_t qtype, uint16_t qclass, const string& content);
+
+ virtual std::string getZoneRepresentation(bool noDot=false) const = 0;
+ virtual ~DNSRecordContent() {}
+ virtual void toPacket(DNSPacketWriter& pw)=0;
+ virtual string serialize(const DNSName& qname, bool canonic=false, bool lowerCase=false) // it would rock if this were const, but it is too hard
+ {
+ vector<uint8_t> packet;
+ DNSName empty;
+ DNSPacketWriter pw(packet, empty, 1);
+ if(canonic)
+ pw.setCanonic(true);
+
+ if(lowerCase)
+ pw.setLowercase(true);
+
+ pw.startRecord(qname, this->getType());
+ this->toPacket(pw);
+ pw.commit();
+
+ string record;
+ pw.getRecords(record);
+ return record;
+ }
+
+ static shared_ptr<DNSRecordContent> unserialize(const DNSName& qname, uint16_t qtype, const string& serialized);
+
+ void doRecordCheck(const struct DNSRecord&){}
+
+ typedef DNSRecordContent* makerfunc_t(const struct DNSRecord& dr, PacketReader& pr);
+ typedef DNSRecordContent* zmakerfunc_t(const string& str);
+
+ static void regist(uint16_t cl, uint16_t ty, makerfunc_t* f, zmakerfunc_t* z, const char* name)
+ {
+ if(f)
+ getTypemap()[make_pair(cl,ty)]=f;
+ if(z)
+ getZmakermap()[make_pair(cl,ty)]=z;
+
+ getT2Namemap().insert(make_pair(make_pair(cl,ty), name));
+ getN2Typemap().insert(make_pair(name, make_pair(cl,ty)));
+ }
+
+ static void unregist(uint16_t cl, uint16_t ty)
+ {
+ pair<uint16_t, uint16_t> key=make_pair(cl, ty);
+ getTypemap().erase(key);
+ getZmakermap().erase(key);
+ }
+
+ static uint16_t TypeToNumber(const string& name)
+ {
+ n2typemap_t::const_iterator iter = getN2Typemap().find(toUpper(name));
+ if(iter != getN2Typemap().end())
+ return iter->second.second;
+
+ if(boost::starts_with(name, "TYPE") || boost::starts_with(name, "type"))
+ return (uint16_t) pdns_stou(name.substr(4));
+
+ throw runtime_error("Unknown DNS type '"+name+"'");
+ }
+
+ static const string NumberToType(uint16_t num, uint16_t classnum=1)
+ {
+ t2namemap_t::const_iterator iter = getT2Namemap().find(make_pair(classnum, num));
+ if(iter == getT2Namemap().end())
+ return "TYPE" + std::to_string(num);
+ // throw runtime_error("Unknown DNS type with numerical id "+std::to_string(num));
+ return iter->second;
+ }
+
+ virtual uint16_t getType() const = 0;
+
+protected:
+ typedef std::map<std::pair<uint16_t, uint16_t>, makerfunc_t* > typemap_t;
+ typedef std::map<std::pair<uint16_t, uint16_t>, zmakerfunc_t* > zmakermap_t;
+ typedef std::map<std::pair<uint16_t, uint16_t>, string > t2namemap_t;
+ typedef std::map<string, std::pair<uint16_t, uint16_t> > n2typemap_t;
+ static typemap_t& getTypemap();
+ static t2namemap_t& getT2Namemap();
+ static n2typemap_t& getN2Typemap();
+ static zmakermap_t& getZmakermap();
+};
+
+struct DNSRecord
+{
+ DNSRecord() {
+ d_type = 0;
+ d_class = QClass::IN;
+ d_ttl = 0;
+ d_clen = 0;
+ d_place = DNSResourceRecord::ANSWER;
+ }
+ explicit DNSRecord(const DNSResourceRecord& rr);
+ DNSName d_name;
+ std::shared_ptr<DNSRecordContent> d_content;
+ uint16_t d_type;
+ uint16_t d_class;
+ uint32_t d_ttl;
+ uint16_t d_clen;
+ DNSResourceRecord::Place d_place;
+
+ bool operator<(const DNSRecord& rhs) const
+ {
+ if(tie(d_name, d_type, d_class, d_ttl) < tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
+ return true;
+
+ if(tie(d_name, d_type, d_class, d_ttl) != tie(rhs.d_name, rhs.d_type, rhs.d_class, rhs.d_ttl))
+ return false;
+
+ string lzrp, rzrp;
+ if(d_content)
+ lzrp=toLower(d_content->getZoneRepresentation());
+ if(rhs.d_content)
+ rzrp=toLower(rhs.d_content->getZoneRepresentation());
+
+ return lzrp < rzrp;
+ }
+
+ // this orders in canonical order and keeps the SOA record on top
+ static bool prettyCompare(const DNSRecord& a, const DNSRecord& b)
+ {
+ auto aType = (a.d_type == QType::SOA) ? 0 : a.d_type;
+ auto bType = (b.d_type == QType::SOA) ? 0 : b.d_type;
+
+ if(a.d_name.canonCompare(b.d_name))
+ return true;
+ if(b.d_name.canonCompare(a.d_name))
+ return false;
+
+ if(tie(aType, a.d_class, a.d_ttl) < tie(bType, b.d_class, b.d_ttl))
+ return true;
+
+ if(tie(aType, a.d_class, a.d_ttl) != tie(bType, b.d_class, b.d_ttl))
+ return false;
+
+ string lzrp, rzrp;
+ if(a.d_content)
+ lzrp=toLower(a.d_content->getZoneRepresentation());
+ if(b.d_content)
+ rzrp=toLower(b.d_content->getZoneRepresentation());
+
+ return lzrp < rzrp;
+ }
+
+
+ bool operator==(const DNSRecord& rhs) const
+ {
+ string lzrp, rzrp;
+ if(d_content)
+ lzrp=toLower(d_content->getZoneRepresentation());
+ if(rhs.d_content)
+ rzrp=toLower(rhs.d_content->getZoneRepresentation());
+
+ string llabel=toLower(d_name.toString());
+ string rlabel=toLower(rhs.d_name.toString());
+
+ return
+ tie(llabel, d_type, d_class, lzrp) ==
+ tie(rlabel, rhs.d_type, rhs.d_class, rzrp);
+ }
+};
+
+//! This class can be used to parse incoming packets, and is copyable
+class MOADNSParser : public boost::noncopyable
+{
+public:
+ //! Parse from a string
+ MOADNSParser(bool query, const string& buffer) : d_tsigPos(0)
+ {
+ init(query, buffer.c_str(), (unsigned int)buffer.size());
+ }
+
+ //! Parse from a pointer and length
+ MOADNSParser(bool query, const char *packet, unsigned int len) : d_tsigPos(0)
+ {
+ init(query, packet, len);
+ }
+
+ DNSName d_qname;
+ uint16_t d_qclass, d_qtype;
+ //uint8_t d_rcode;
+ dnsheader d_header;
+
+ typedef vector<pair<DNSRecord, uint16_t > > answers_t;
+
+ //! All answers contained in this packet
+ answers_t d_answers;
+
+ shared_ptr<PacketReader> getPacketReader(uint16_t offset)
+ {
+ shared_ptr<PacketReader> pr(new PacketReader(d_content));
+ pr->d_pos=offset;
+ return pr;
+ }
+
+ uint16_t getTSIGPos() const
+ {
+ return d_tsigPos;
+ }
+private:
+ void getDnsrecordheader(struct dnsrecordheader &ah);
+ void init(bool query, const char *packet, unsigned int len);
+ vector<uint8_t> d_content;
+ uint16_t d_tsigPos;
+};
+
+string simpleCompress(const string& label, const string& root="");
+void ageDNSPacket(char* packet, size_t length, uint32_t seconds);
+void ageDNSPacket(std::string& packet, uint32_t seconds);
+uint32_t getDNSPacketMinTTL(const char* packet, size_t length);
+uint32_t getDNSPacketLength(const char* packet, size_t length);
+uint16_t getRecordsOfTypeCount(const char* packet, size_t length, uint8_t section, uint16_t type);
+
+template<typename T>
+std::shared_ptr<T> getRR(const DNSRecord& dr)
+{
+ return std::dynamic_pointer_cast<T>(dr.d_content);
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define __FAVOR_BSD
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnspcap.hh"
+#include <boost/format.hpp>
+#include <fcntl.h>
+
+#include "namespaces.hh"
+PcapPacketReader::PcapPacketReader(const string& fname) : d_fname(fname)
+{
+ d_fp=fopen(fname.c_str(),"r");
+ if(!d_fp)
+ unixDie("Unable to open file " + fname);
+
+ int flags=fcntl(fileno(d_fp),F_GETFL,0);
+ fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
+
+ checkedFread(&d_pfh);
+
+ if(d_pfh.magic != 2712847316UL)
+ throw runtime_error((format("PCAP file %s has bad magic %x, should be %x") % fname % d_pfh.magic % 2712847316UL).str());
+
+ if( d_pfh.linktype==1) {
+ d_skipMediaHeader=sizeof(struct ether_header);
+ }
+ else if(d_pfh.linktype==101) {
+ d_skipMediaHeader=0;
+ }
+ else if(d_pfh.linktype==113) {
+ d_skipMediaHeader=16;
+ }
+ else throw runtime_error((format("Unsupported link type %d") % d_pfh.linktype).str());
+
+ d_runts = d_oversized = d_correctpackets = d_nonetheripudp = 0;
+}
+
+PcapPacketReader::~PcapPacketReader()
+{
+ fclose(d_fp);
+}
+
+
+void PcapPacketReader::checkedFreadSize(void* ptr, size_t size)
+{
+ int ret=fread(ptr, 1, size, d_fp);
+ if(ret < 0)
+ unixDie( (format("Error reading %d bytes from %s") % size % d_fname).str());
+
+ if(!ret)
+ throw EofException();
+
+ if((size_t)ret != size)
+ throw EofException((format("Incomplete read from '%s', got only %d bytes") % d_fname % ret).str());
+}
+
+bool PcapPacketReader::getUDPPacket()
+try
+{
+ for(;;) {
+ checkedFread(&d_pheader);
+ if(!d_pheader.caplen) {
+ d_runts++;
+ continue;
+ }
+
+ if(d_pheader.caplen > sizeof(d_buffer)) {
+ d_oversized++;
+ throw runtime_error((format("Can't handle a %d byte packet, have space for %d") % d_pheader.caplen % sizeof(d_buffer)).str());
+ }
+
+ checkedFreadSize(d_buffer, d_pheader.caplen);
+
+ if(d_pheader.caplen!=d_pheader.len) {
+ d_runts++;
+ continue;
+ }
+
+ d_ether=reinterpret_cast<struct ether_header*>(d_buffer);
+ d_lcc=reinterpret_cast<struct pdns_lcc_header*>(d_buffer);
+
+ d_ip=reinterpret_cast<struct ip*>(d_buffer + d_skipMediaHeader);
+ d_ip6=reinterpret_cast<struct ip6_hdr*>(d_buffer + d_skipMediaHeader);
+ uint16_t contentCode=0;
+ if(d_pfh.linktype==1)
+ contentCode=ntohs(d_ether->ether_type);
+ else if(d_pfh.linktype==101) {
+ if(d_ip->ip_v==4)
+ contentCode = 0x0800;
+ else
+ contentCode = 0x86dd;
+ }
+ else if(d_pfh.linktype==113)
+ contentCode=ntohs(d_lcc->lcc_protocol);
+
+ if(contentCode==0x0800 && d_ip->ip_p==17) { // udp
+ d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + 4 * d_ip->ip_hl);
+ d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
+ d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
+ if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
+ d_runts++;
+ continue;
+ }
+ d_correctpackets++;
+ return true;
+ }
+ if(contentCode==0x86dd && d_ip6->ip6_ctlun.ip6_un1.ip6_un1_nxt==17) { // udpv6, we ignore anything with extension hdr
+ d_udp=reinterpret_cast<const struct udphdr*>(d_buffer + d_skipMediaHeader + sizeof(struct ip6_hdr));
+ d_payload = (unsigned char*)d_udp + sizeof(struct udphdr);
+ d_len = ntohs(d_udp->uh_ulen) - sizeof(struct udphdr);
+ if((const char*)d_payload + d_len > d_buffer + d_pheader.caplen) {
+ d_runts++;
+ continue;
+ }
+
+ d_correctpackets++;
+ return true;
+ }
+ else {
+ d_nonetheripudp++;
+ }
+ }
+}
+catch(EofException) {
+ return false;
+}
+
+ComboAddress PcapPacketReader::getSource() const
+{
+ ComboAddress ret;
+ if(d_ip->ip_v == 4) {
+ ret.sin4.sin_family = AF_INET;
+ ret.sin4.sin_addr = d_ip->ip_src;
+ ret.sin4.sin_port = d_udp->uh_sport; // should deal with TCP too!
+ } else {
+ ret.sin6.sin6_family = AF_INET6;
+ ret.sin6.sin6_addr = d_ip6->ip6_src;
+ ret.sin6.sin6_port = d_udp->uh_sport; // should deal with TCP too!
+ }
+ return ret;
+}
+
+ComboAddress PcapPacketReader::getDest() const
+{
+ ComboAddress ret;
+ if(d_ip->ip_v == 4) {
+ ret.sin4.sin_family = AF_INET;
+ ret.sin4.sin_addr = d_ip->ip_dst;
+ ret.sin4.sin_port = d_udp->uh_dport; // should deal with TCP too!
+ } else {
+ ret.sin6.sin6_family = AF_INET6;
+ ret.sin6.sin6_addr = d_ip6->ip6_dst;
+ ret.sin6.sin6_port = d_udp->uh_dport; // should deal with TCP too!
+ }
+ return ret;
+}
+
+PcapPacketWriter::PcapPacketWriter(const string& fname, const PcapPacketReader& ppr) : PcapPacketWriter(fname)
+{
+ setPPR(ppr);
+}
+
+PcapPacketWriter::PcapPacketWriter(const string& fname) : d_fname(fname)
+{
+ d_fp=fopen(fname.c_str(),"w");
+ if(!d_fp)
+ unixDie("Unable to open file");
+
+ int flags=fcntl(fileno(d_fp),F_GETFL,0);
+ fcntl(fileno(d_fp), F_SETFL,flags&(~O_NONBLOCK)); // bsd needs this in stdin (??)
+}
+
+void PcapPacketWriter::write()
+{
+ if (!d_ppr) {
+ return;
+ }
+
+ if(d_first) {
+ fwrite(&d_ppr->d_pfh, 1, sizeof(d_ppr->d_pfh), d_fp);
+ d_first=false;
+ }
+ fwrite(&d_ppr->d_pheader, 1, sizeof(d_ppr->d_pheader), d_fp);
+ fwrite(d_ppr->d_buffer, 1, d_ppr->d_pheader.caplen, d_fp);
+}
+
+PcapPacketWriter::~PcapPacketWriter()
+{
+ fclose(d_fp);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNSPCAP_HH
+#define PDNS_DNSPCAP_HH
+
+#include <cstdio>
+#include <stdexcept>
+#include "iputils.hh"
+#include <string>
+#include "misc.hh"
+#include <iostream>
+#define __FAVOR_BSD
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/udp.h>
+#if defined(__NetBSD__)
+#include <net/if.h>
+#include <net/if_ether.h>
+#elif defined (__OpenBSD__)
+#include <net/if.h>
+#include <netinet/if_ether.h>
+#elif defined (__SVR4) && defined (__sun)
+#include <sys/ethernet.h>
+#else
+#include <net/ethernet.h>
+#endif
+#include <vector>
+#include <boost/format.hpp>
+#include "namespaces.hh"
+
+struct pdns_pcap_file_header {
+ uint32_t magic;
+ uint16_t version_major;
+ uint16_t version_minor;
+ uint32_t thiszone; /* gmt to local correction */
+ uint32_t sigfigs; /* accuracy of timestamps */
+ uint32_t snaplen; /* max length saved portion of each pkt */
+ uint32_t linktype; /* data link type (LINKTYPE_*) */
+};
+
+
+struct pdns_timeval
+{
+ uint32_t tv_sec{0};
+ uint32_t tv_usec{0};
+};
+
+struct pdns_pcap_pkthdr {
+ struct pdns_timeval ts; /* time stamp */
+ uint32_t caplen{0}; /* length of portion present */
+ uint32_t len{0}; /* length this packet (off wire) */
+};
+
+struct pdns_lcc_header {
+ uint16_t lcc_pkttype;/* packet type */
+ uint16_t lcc_hatype;/* link-layer address type */
+ uint16_t lcc_halen;/* link-layer address length */
+ uint8_t lcc_addr[8];/* link-layer address */
+ uint16_t lcc_protocol;/* protocol */
+};
+
+class PcapPacketReader
+{
+public:
+ class EofException : public runtime_error
+ {
+ public:
+ EofException(const string& str="") : runtime_error(str)
+ {
+ }
+ };
+
+ PcapPacketReader(const string& fname);
+
+ ~PcapPacketReader();
+
+ template<typename T>
+ void checkedFread(T* ptr)
+ {
+ checkedFreadSize(ptr, sizeof(*ptr));
+ }
+
+ void checkedFreadSize(void* ptr, size_t size) ;
+
+ bool getUDPPacket();
+
+ ComboAddress getSource() const;
+ ComboAddress getDest() const;
+
+ struct pdns_lcc_header* d_lcc{nullptr};
+ struct ether_header* d_ether{nullptr};
+ struct ip *d_ip{nullptr};
+ struct ip6_hdr *d_ip6{nullptr};
+ const struct tcphdr *d_tcp{nullptr};
+ const struct udphdr *d_udp{nullptr};
+ const uint8_t* d_payload{nullptr};
+ unsigned int d_len{0};
+ struct pdns_pcap_pkthdr d_pheader;
+
+ pdns_pcap_file_header d_pfh;
+ unsigned int d_runts, d_oversized, d_correctpackets, d_nonetheripudp;
+ char d_buffer[32768];
+private:
+ FILE* d_fp;
+ string d_fname;
+ int d_skipMediaHeader;
+};
+
+class PcapPacketWriter
+{
+public:
+ PcapPacketWriter(const string& fname, const PcapPacketReader& ppr);
+ PcapPacketWriter(const string& fname);
+
+ void write();
+ void setPPR(const PcapPacketReader& ppr) { d_ppr = &ppr; }
+ ~PcapPacketWriter();
+
+private:
+ string d_fname;
+ const PcapPacketReader* d_ppr{nullptr};
+
+ FILE *d_fp;
+ bool d_first{true};
+};
+
+#endif // DNSPCAP_HH
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+
+#include "iputils.hh"
+#include "misc.hh"
+#include "dns.hh"
+#include "dnspcap.hh"
+#include "dnsparser.hh"
+#include "protobuf.hh"
+
+#include "statbag.hh"
+StatBag S;
+
+static void usage()
+{
+ cerr<<"This program reads DNS queries and responses from a PCAP file and stores them into our protobuf format."<<endl;
+ cerr<<"Usage: dnspcap2protobuf PCAPFILE OUTFILE"<<endl;
+}
+
+int main(int argc, char **argv)
+try {
+ for(int n=1 ; n < argc; ++n) {
+ if ((string) argv[n] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[n] == "--version") {
+ cerr<<"dnspcap2protobuf "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(argc < 3) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+
+ PcapPacketReader pr(argv[1]);
+
+ FILE* fp = fopen(argv[2], "w");
+ if (!fp) {
+ cerr<<"Error opening output file "<<argv[2]<<": "<<strerror(errno)<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ int ind=0;
+ if(argc==4)
+ ind=atoi(argv[3]);
+
+ std::map<uint16_t,std::pair<boost::uuids::uuid,struct timeval> > ids;
+ boost::uuids::random_generator uuidGenerator;
+ try {
+ while (pr.getUDPPacket()) {
+ const dnsheader* dh=(dnsheader*)pr.d_payload;
+ if (!dh->qdcount)
+ continue;
+
+ if (pr.d_len < sizeof(dnsheader))
+ continue;
+
+ if(!dh->rd)
+ continue;
+
+ uint16_t qtype, qclass;
+ DNSName qname;
+ try {
+ qname=DNSName((const char*)pr.d_payload, pr.d_len, sizeof(dnsheader), false, &qtype, &qclass);
+ }
+ catch(const std::exception& e) {
+ cerr<<"Error while parsing qname: "<<e.what()<<endl;
+ continue;
+ }
+
+ boost::uuids::uuid uniqueId;
+ struct timeval queryTime = { 0, 0 };
+ bool hasQueryTime = false;
+ if (!dh->qr) {
+ queryTime.tv_sec = pr.d_pheader.ts.tv_sec;
+ queryTime.tv_usec = pr.d_pheader.ts.tv_usec;
+ uniqueId = uuidGenerator();
+ ids[dh->id] = std::make_pair(uniqueId, queryTime);
+ }
+ else {
+ const auto& it = ids.find(dh->id);
+ if (it != ids.end()) {
+ uniqueId = it->second.first;
+ queryTime = it->second.second;
+ hasQueryTime = true;
+ }
+ else {
+ uniqueId = uuidGenerator();
+ }
+ }
+
+ const ComboAddress requestor = dh->qr ? pr.getDest() : pr.getSource();
+ const ComboAddress responder = dh->qr ? pr.getSource() : pr.getDest();
+ *((char*)&requestor.sin4.sin_addr.s_addr)|=ind;
+ *((char*)&responder.sin4.sin_addr.s_addr)|=ind;
+
+ DNSProtoBufMessage message(dh->qr ? DNSProtoBufMessage::DNSProtoBufMessageType::Response : DNSProtoBufMessage::DNSProtoBufMessageType::Query, uniqueId, &requestor, &responder, qname, qtype, qclass, dh->id, false, pr.d_len);
+ message.setTime(pr.d_pheader.ts.tv_sec, pr.d_pheader.ts.tv_usec);
+
+ if (dh->qr) {
+ message.setResponseCode(dh->rcode);
+ if (hasQueryTime) {
+ message.setQueryTime(queryTime.tv_sec, queryTime.tv_usec);
+ }
+
+ try {
+ message.addRRsFromPacket((const char*) dh, pr.d_len);
+ }
+ catch(std::exception& e)
+ {
+ cerr<<"Error parsing response records: "<<e.what()<<endl;
+ }
+ catch(const PDNSException& e)
+ {
+ cerr<<"Error parsing response records: "<<e.reason<<endl;
+ }
+ }
+
+ std::string str;
+ message.serialize(str);
+
+ uint16_t mlen = htons(str.length());
+ fwrite(&mlen, 1, sizeof(mlen), fp);
+ fwrite(str.c_str(), 1, str.length(), fp);
+ }
+ }
+ catch (const std::exception& e) {
+ cerr<<"Error while parsing the PCAP file: "<<e.what()<<endl;
+ fclose(fp);
+ exit(EXIT_FAILURE);
+ }
+
+ fclose(fp);
+}
+catch(const std::exception& e) {
+ cerr<<"Error opening PCAP file: "<<e.what()<<endl;
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include "dnsproxy.hh"
+#include "pdnsexception.hh"
+#include <sys/types.h>
+#include <errno.h>
+#include "dns.hh"
+#include "logger.hh"
+#include "statbag.hh"
+#include "dns_random.hh"
+
+extern StatBag S;
+extern PacketCache PC;
+
+DNSProxy::DNSProxy(const string &remote)
+{
+ pthread_mutex_init(&d_lock,0);
+ d_resanswers=S.getPointer("recursing-answers");
+ d_resquestions=S.getPointer("recursing-questions");
+ d_udpanswers=S.getPointer("udp-answers");
+ ComboAddress remaddr(remote, 53);
+
+ if((d_sock=socket(remaddr.sin4.sin_family, SOCK_DGRAM,0))<0)
+ throw PDNSException(string("socket: ")+strerror(errno));
+
+ ComboAddress local;
+ if(remaddr.sin4.sin_family==AF_INET)
+ local = ComboAddress("0.0.0.0");
+ else
+ local = ComboAddress("::");
+
+ int n=0;
+ for(;n<10;n++) {
+ local.sin4.sin_port = htons(10000+dns_random(50000));
+
+ if(::bind(d_sock, (struct sockaddr *)&local, local.getSocklen()) >= 0)
+ break;
+ }
+ if(n==10) {
+ closesocket(d_sock);
+ d_sock=-1;
+ throw PDNSException(string("binding dnsproxy socket: ")+strerror(errno));
+ }
+
+ if(connect(d_sock, (sockaddr *)&remaddr, remaddr.getSocklen())<0)
+ throw PDNSException("Unable to UDP connect to remote nameserver "+remaddr.toStringWithPort()+": "+stringerror());
+
+ d_xor=dns_random(0xffff);
+ L<<Logger::Error<<"DNS Proxy launched, local port "<<ntohs(local.sin4.sin_port)<<", remote "<<remaddr.toStringWithPort()<<endl;
+}
+
+void DNSProxy::go()
+{
+ pthread_t tid;
+ pthread_create(&tid,0,&launchhelper,this);
+}
+
+
+void DNSProxy::onlyFrom(const string &ips)
+{
+ d_ng.toMasks(ips);
+}
+
+bool DNSProxy::recurseFor(DNSPacket* p)
+{
+ return d_ng.match((ComboAddress *)&p->d_remote);
+}
+
+/** returns false if p->remote is not allowed to recurse via us */
+bool DNSProxy::sendPacket(DNSPacket *p)
+{
+ if(!recurseFor(p))
+ return false;
+
+ uint16_t id;
+ {
+ Lock l(&d_lock);
+ id=getID_locked();
+
+ ConntrackEntry ce;
+ ce.id = p->d.id;
+ ce.remote = p->d_remote;
+ ce.outsock = p->getSocket();
+ ce.created = time( NULL );
+ ce.qtype = p->qtype.getCode();
+ ce.qname = p->qdomain;
+ ce.anyLocal = p->d_anyLocal;
+ ce.complete=0;
+ d_conntrack[id]=ce;
+ }
+ p->d.id=id^d_xor;
+ p->commitD();
+
+ const string& buffer = p->getString();
+
+ if(send(d_sock,buffer.c_str(), buffer.length() , 0)<0) { // zoom
+ L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
+ }
+ (*d_resquestions)++;
+ return true;
+
+}
+
+//! look up qname aname with r->qtype, plonk it in the answer section of 'r' with name target
+bool DNSProxy::completePacket(DNSPacket *r, const DNSName& target,const DNSName& aname)
+{
+ uint16_t id;
+ {
+ Lock l(&d_lock);
+ id=getID_locked();
+
+ ConntrackEntry ce;
+ ce.id = r->d.id;
+ ce.remote = r->d_remote;
+ ce.outsock = r->getSocket();
+ ce.created = time( NULL );
+ ce.qtype = r->qtype.getCode();
+ ce.qname = target;
+ ce.anyLocal = r->d_anyLocal;
+ ce.complete = r;
+ ce.aname=aname;
+ d_conntrack[id]=ce;
+ }
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, target, r->qtype.getCode());
+ pw.getHeader()->rd=true;
+ pw.getHeader()->id=id ^ d_xor;
+
+ if(send(d_sock,&packet[0], packet.size() , 0)<0) { // zoom
+ L<<Logger::Error<<"Unable to send a packet to our recursing backend: "<<stringerror()<<endl;
+ }
+
+ return true;
+
+}
+
+
+/** This finds us an unused or stale ID. Does not actually clean the contents */
+int DNSProxy::getID_locked()
+{
+ map_t::iterator i;
+ for(int n=0;;++n) {
+ i=d_conntrack.find(n);
+ if(i==d_conntrack.end()) {
+ return n;
+ }
+ else if(i->second.created<time(0)-60) {
+ if(i->second.created) {
+ L<<Logger::Warning<<"Recursive query for remote "<<
+ i->second.remote.toStringWithPort()<<" with internal id "<<n<<
+ " was not answered by backend within timeout, reusing id"<<endl;
+ delete i->second.complete;
+ S.inc("recursion-unanswered");
+ }
+ return n;
+ }
+ }
+}
+
+void DNSProxy::mainloop(void)
+{
+ try {
+ char buffer[1500];
+ ssize_t len;
+
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+
+ for(;;) {
+ len=recv(d_sock, buffer, sizeof(buffer),0); // answer from our backend
+ if(len<(ssize_t)sizeof(dnsheader)) {
+ if(len<0)
+ L<<Logger::Error<<"Error receiving packet from recursor backend: "<<stringerror()<<endl;
+ else if(len==0)
+ L<<Logger::Error<<"Error receiving packet from recursor backend, EOF"<<endl;
+ else
+ L<<Logger::Error<<"Short packet from recursor backend, "<<len<<" bytes"<<endl;
+
+ continue;
+ }
+ (*d_resanswers)++;
+ (*d_udpanswers)++;
+ dnsheader d;
+ memcpy(&d,buffer,sizeof(d));
+ {
+ Lock l(&d_lock);
+#if BYTE_ORDER == BIG_ENDIAN
+ // this is needed because spoof ID down below does not respect the native byteorder
+ d.id = ( 256 * (uint16_t)buffer[1] ) + (uint16_t)buffer[0];
+#endif
+ map_t::iterator i=d_conntrack.find(d.id^d_xor);
+ if(i==d_conntrack.end()) {
+ L<<Logger::Error<<"Discarding untracked packet from recursor backend with id "<<(d.id^d_xor)<<
+ ". Conntrack table size="<<d_conntrack.size()<<endl;
+ continue;
+ }
+ else if(i->second.created==0) {
+ L<<Logger::Error<<"Received packet from recursor backend with id "<<(d.id^d_xor)<<" which is a duplicate"<<endl;
+ continue;
+ }
+
+ d.id=i->second.id;
+ memcpy(buffer,&d,sizeof(d)); // commit spoofed id
+
+ DNSPacket p(false),q(false);
+ p.parse(buffer,(size_t)len);
+ q.parse(buffer,(size_t)len);
+
+ if(p.qtype.getCode() != i->second.qtype || p.qdomain != i->second.qname) {
+ L<<Logger::Error<<"Discarding packet from recursor backend with id "<<(d.id^d_xor)<<
+ ", qname or qtype mismatch ("<<p.qtype.getCode()<<" v " <<i->second.qtype<<", "<<p.qdomain<<" v "<<i->second.qname<<")"<<endl;
+ continue;
+ }
+
+ /* Set up iov and msgh structures. */
+ memset(&msgh, 0, sizeof(struct msghdr));
+ string reply; // needs to be alive at time of sendmsg!
+ if(i->second.complete) {
+
+ MOADNSParser mdp(false, p.getString());
+ // cerr<<"Got completion, "<<mdp.d_answers.size()<<" answers, rcode: "<<mdp.d_header.rcode<<endl;
+ for(MOADNSParser::answers_t::const_iterator j=mdp.d_answers.begin(); j!=mdp.d_answers.end(); ++j) {
+ // cerr<<"comp: "<<(int)j->first.d_place-1<<" "<<j->first.d_label<<" " << DNSRecordContent::NumberToType(j->first.d_type)<<" "<<j->first.d_content->getZoneRepresentation()<<endl;
+ if(j->first.d_place == DNSResourceRecord::ANSWER || (j->first.d_place == DNSResourceRecord::AUTHORITY && j->first.d_type == QType::SOA)) {
+
+ DNSResourceRecord rr;
+
+ if(j->first.d_type == i->second.qtype || (i->second.qtype == QType::ANY && (j->first.d_type == QType::A || j->first.d_type == QType::AAAA))) {
+ rr.qname=i->second.aname;
+ rr.qtype = j->first.d_type;
+ rr.ttl=j->first.d_ttl;
+ rr.d_place= j->first.d_place;
+ rr.content=j->first.d_content->getZoneRepresentation();
+ i->second.complete->addRecord(rr);
+ }
+ }
+ }
+ i->second.complete->setRcode(mdp.d_header.rcode);
+ reply=i->second.complete->getString();
+ iov.iov_base = (void*)reply.c_str();
+ iov.iov_len = reply.length();
+ delete i->second.complete;
+ i->second.complete=0;
+ }
+ else {
+ iov.iov_base = buffer;
+ iov.iov_len = len;
+ }
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_name = (struct sockaddr*)&i->second.remote;
+ msgh.msg_namelen = i->second.remote.getSocklen();
+ msgh.msg_control=NULL;
+
+ if(i->second.anyLocal) {
+ addCMsgSrcAddr(&msgh, cbuf, i->second.anyLocal.get_ptr(), 0);
+ }
+ if(sendmsg(i->second.outsock, &msgh, 0) < 0)
+ L<<Logger::Warning<<"dnsproxy.cc: Error sending reply with sendmsg (socket="<<i->second.outsock<<"): "<<strerror(errno)<<endl;
+
+ PC.insert(&q, &p, true);
+ i->second.created=0;
+ }
+ }
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"Fatal error in DNS proxy: "<<ae.reason<<endl;
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"Communicator thread died because of STL error: "<<e.what()<<endl;
+ }
+ catch( ... )
+ {
+ L << Logger::Error << "Caught unknown exception." << endl;
+ }
+ L<<Logger::Error<<"Exiting because DNS proxy failed"<<endl;
+ exit(1);
+}
+
+DNSProxy::~DNSProxy() {
+ if (d_sock>-1) {
+ try {
+ closesocket(d_sock);
+ }
+ catch(const PDNSException& e) {
+ }
+ }
+
+ d_sock=-1;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNSPROXY
+#define PDNS_DNSPROXY
+#include <pthread.h>
+#include <map>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "dnspacket.hh"
+#include "lock.hh"
+#include "iputils.hh"
+
+#include "namespaces.hh"
+
+/**
+
+how will this work.
+
+This is a thread that just throws packets around. Should handle ~1000 packets/second.
+
+Consists of a thread receiving packets back from the backend and retransmitting them to the original client.
+
+Furthermore, it provides a member function that reports the packet to the connection tracker and actually sends it out.
+
+The sending happens from a source port that is determined by the constructor, but IS random. Furthermore, the ID is XOR-ed with a random value
+to make sure outside parties can't spoof us.
+
+To fix: how to remove the stale entries that will surely accumulate
+*/
+
+class DNSProxy
+{
+public:
+ DNSProxy(const string &ip); //!< creates socket
+ ~DNSProxy(); //<! dtor for DNSProxy
+ void go(); //!< launches the actual thread
+ void onlyFrom(const string &ips); //!< Only these netmasks are allowed to recurse via us
+ bool sendPacket(DNSPacket *p); //!< send out a packet and make a conntrack entry to we can send back the answer
+ bool completePacket(DNSPacket *r, const DNSName& target,const DNSName& aname);
+
+ void mainloop(); //!< this is the main loop that receives reply packets and sends them out again
+ static void *launchhelper(void *p)
+ {
+ static_cast<DNSProxy *>(p)->mainloop();
+ return 0;
+ }
+ bool recurseFor(DNSPacket* p);
+private:
+ struct ConntrackEntry
+ {
+ time_t created;
+ boost::optional<ComboAddress> anyLocal;
+ DNSName qname;
+ DNSPacket* complete;
+ DNSName aname;
+ ComboAddress remote;
+ uint16_t id;
+ uint16_t qtype;
+ int outsock;
+ };
+
+ typedef map<int,ConntrackEntry> map_t;
+
+ // Data
+ NetmaskGroup d_ng;
+ AtomicCounter* d_resanswers;
+ AtomicCounter* d_udpanswers;
+ AtomicCounter* d_resquestions;
+ pthread_mutex_t d_lock;
+ map_t d_conntrack;
+ int d_sock;
+ int getID_locked();
+ uint16_t d_xor;
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "dnsrecords.hh"
+#include "iputils.hh"
+
+
+void DNSResourceRecord::setContent(const string &cont) {
+ content = cont;
+ switch(qtype.getCode()) {
+ case QType::SRV:
+ case QType::MX:
+ if (content.size() >= 2 && *(content.rbegin()+1) == ' ')
+ return;
+ case QType::CNAME:
+ case QType::DNAME:
+ case QType::NS:
+ case QType::PTR:
+ if(!content.empty())
+ boost::erase_tail(content, 1);
+ }
+}
+
+string DNSResourceRecord::getZoneRepresentation(bool noDot) const {
+ ostringstream ret;
+ switch(qtype.getCode()) {
+ case QType::SRV:
+ case QType::MX:
+ case QType::CNAME:
+ case QType::DNAME:
+ case QType::NS:
+ case QType::PTR:
+ if (*(content.rbegin()) != '.') {
+ ret<<content;
+ if(!noDot)
+ ret<<".";
+ }
+ break;
+ default:
+ ret<<content;
+ break;
+ }
+ return ret.str();
+}
+
+bool DNSResourceRecord::operator==(const DNSResourceRecord& rhs)
+{
+ string lcontent=toLower(content);
+ string rcontent=toLower(rhs.content);
+
+ return
+ tie(qname, qtype, lcontent, ttl) ==
+ tie(rhs.qname, rhs.qtype, rcontent, rhs.ttl);
+}
+
+DNSResourceRecord::DNSResourceRecord(const DNSRecord &p) {
+ auth=true;
+ qclass = p.d_class;
+ disabled=false;
+ qname = p.d_name;
+ d_place = p.d_place;
+ // if(!qname.empty())
+ // boost::erase_tail(qname, 1); // strip .
+
+ qtype = p.d_type;
+ ttl = p.d_ttl;
+ setContent(p.d_content->getZoneRepresentation());
+ last_modified = 0;
+ signttl = 0;
+ domain_id = -1;
+ qclass = p.d_class;
+ d_place = p.d_place;
+ scopeMask = 0;
+}
+
+boilerplate_conv(A, QType::A, conv.xfrIP(d_ip));
+
+ARecordContent::ARecordContent(uint32_t ip)
+{
+ d_ip = ip;
+}
+
+ARecordContent::ARecordContent(const ComboAddress& ca)
+{
+ d_ip = ca.sin4.sin_addr.s_addr;
+}
+
+AAAARecordContent::AAAARecordContent(const ComboAddress& ca)
+{
+ d_ip6.assign((const char*)ca.sin6.sin6_addr.s6_addr, 16);
+}
+
+
+ComboAddress ARecordContent::getCA(int port) const
+{
+ ComboAddress ret;
+ ret.sin4.sin_family=AF_INET;
+ ret.sin4.sin_port=htons(port);
+ memcpy(&ret.sin4.sin_addr.s_addr, &d_ip, sizeof(ret.sin4.sin_addr.s_addr));
+ return ret;
+}
+
+ComboAddress AAAARecordContent::getCA(int port) const
+{
+ ComboAddress ret;
+ memset(&ret, 0, sizeof(ret));
+
+ ret.sin4.sin_family=AF_INET6;
+ ret.sin6.sin6_port = htons(port);
+ memcpy(&ret.sin6.sin6_addr.s6_addr, d_ip6.c_str(), sizeof(ret.sin6.sin6_addr.s6_addr));
+ return ret;
+}
+
+
+void ARecordContent::doRecordCheck(const DNSRecord& dr)
+{
+ if(dr.d_clen!=4)
+ throw MOADNSException("Wrong size for A record ("+std::to_string(dr.d_clen)+")");
+}
+
+boilerplate_conv(AAAA, QType::AAAA, conv.xfrIP6(d_ip6); );
+
+boilerplate_conv(NS, QType::NS, conv.xfrName(d_content, true));
+boilerplate_conv(PTR, QType::PTR, conv.xfrName(d_content, true));
+boilerplate_conv(CNAME, QType::CNAME, conv.xfrName(d_content, true));
+boilerplate_conv(ALIAS, QType::ALIAS, conv.xfrName(d_content, true));
+boilerplate_conv(DNAME, QType::DNAME, conv.xfrName(d_content));
+boilerplate_conv(MR, QType::MR, conv.xfrName(d_alias, true));
+boilerplate_conv(MINFO, QType::MINFO, conv.xfrName(d_rmailbx, true); conv.xfrName(d_emailbx, true));
+boilerplate_conv(TXT, QType::TXT, conv.xfrText(d_text, true));
+boilerplate_conv(SPF, 99, conv.xfrText(d_text, true));
+boilerplate_conv(HINFO, QType::HINFO, conv.xfrText(d_cpu); conv.xfrText(d_host));
+
+boilerplate_conv(RP, QType::RP,
+ conv.xfrName(d_mbox);
+ conv.xfrName(d_info)
+ );
+
+
+boilerplate_conv(OPT, QType::OPT,
+ conv.xfrBlob(d_data)
+ );
+
+void OPTRecordContent::getData(vector<pair<uint16_t, string> >& options)
+{
+ string::size_type pos=0;
+ uint16_t code, len;
+ while(d_data.size() >= 4 + pos) {
+ code = 256 * (unsigned char)d_data[pos] + (unsigned char)d_data[pos+1];
+ len = 256 * (unsigned char)d_data[pos+2] + (unsigned char)d_data[pos+3];
+ pos+=4;
+
+ if(pos + len > d_data.size())
+ break;
+
+ string field(d_data.c_str() + pos, len);
+ pos+=len;
+ options.push_back(make_pair(code, field));
+ }
+}
+
+boilerplate_conv(TSIG, QType::TSIG,
+ conv.xfrName(d_algoName);
+ conv.xfr48BitInt(d_time);
+ conv.xfr16BitInt(d_fudge);
+ uint16_t size=d_mac.size();
+ conv.xfr16BitInt(size);
+ if (size>0) conv.xfrBlobNoSpaces(d_mac, size);
+ conv.xfr16BitInt(d_origID);
+ conv.xfr16BitInt(d_eRcode);
+ size=d_otherData.size();
+ conv.xfr16BitInt(size);
+ if (size>0) conv.xfrBlobNoSpaces(d_otherData, size);
+ );
+
+MXRecordContent::MXRecordContent(uint16_t preference, const DNSName& mxname): d_preference(preference), d_mxname(mxname)
+{
+}
+
+boilerplate_conv(MX, QType::MX,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrName(d_mxname, true);
+ )
+
+boilerplate_conv(KX, QType::KX,
+ conv.xfr16BitInt(d_preference);
+ conv.xfrName(d_exchanger, false);
+ )
+
+boilerplate_conv(IPSECKEY, QType::IPSECKEY,
+ conv.xfr8BitInt(d_preference);
+ conv.xfr8BitInt(d_gatewaytype);
+ conv.xfr8BitInt(d_algorithm);
+
+ // now we need to determine values
+ switch(d_gatewaytype) {
+ case 0: // NO KEY
+ break;
+ case 1: // IPv4 GW
+ conv.xfrIP(d_ip4);
+ break;
+ case 2: // IPv6 GW
+ conv.xfrIP6(d_ip6);
+ break;
+ case 3: // DNS label
+ conv.xfrName(d_gateway, false);
+ break;
+ default:
+ throw MOADNSException("Parsing record content: invalid gateway type");
+ };
+
+ switch(d_algorithm) {
+ case 0:
+ break;
+ case 1:
+ case 2:
+ conv.xfrBlob(d_publickey);
+ break;
+ default:
+ throw MOADNSException("Parsing record content: invalid algorithm type");
+ }
+)
+
+boilerplate_conv(DHCID, 49,
+ conv.xfrBlob(d_content);
+ )
+
+
+boilerplate_conv(AFSDB, QType::AFSDB,
+ conv.xfr16BitInt(d_subtype);
+ conv.xfrName(d_hostname);
+ )
+
+
+boilerplate_conv(NAPTR, QType::NAPTR,
+ conv.xfr16BitInt(d_order); conv.xfr16BitInt(d_preference);
+ conv.xfrText(d_flags); conv.xfrText(d_services); conv.xfrText(d_regexp);
+ conv.xfrName(d_replacement);
+ )
+
+
+SRVRecordContent::SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const DNSName& target)
+: d_weight(weight), d_port(port), d_target(target), d_preference(preference)
+{}
+
+boilerplate_conv(SRV, QType::SRV,
+ conv.xfr16BitInt(d_preference); conv.xfr16BitInt(d_weight); conv.xfr16BitInt(d_port);
+ conv.xfrName(d_target);
+ )
+
+SOARecordContent::SOARecordContent(const DNSName& mname, const DNSName& rname, const struct soatimes& st)
+: d_mname(mname), d_rname(rname)
+{
+ d_st=st;
+}
+
+boilerplate_conv(SOA, QType::SOA,
+ conv.xfrName(d_mname, true);
+ conv.xfrName(d_rname, true);
+ conv.xfr32BitInt(d_st.serial);
+ conv.xfr32BitInt(d_st.refresh);
+ conv.xfr32BitInt(d_st.retry);
+ conv.xfr32BitInt(d_st.expire);
+ conv.xfr32BitInt(d_st.minimum);
+ );
+#undef KEY
+boilerplate_conv(KEY, QType::KEY,
+ conv.xfr16BitInt(d_flags);
+ conv.xfr8BitInt(d_protocol);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfrBlob(d_certificate);
+ );
+
+boilerplate_conv(CERT, 37,
+ conv.xfr16BitInt(d_type);
+ if (d_type == 0) throw MOADNSException("CERT type 0 is reserved");
+
+ conv.xfr16BitInt(d_tag);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfrBlob(d_certificate);
+ )
+
+boilerplate_conv(TLSA, 52,
+ conv.xfr8BitInt(d_certusage);
+ conv.xfr8BitInt(d_selector);
+ conv.xfr8BitInt(d_matchtype);
+ conv.xfrHexBlob(d_cert, true);
+ )
+
+boilerplate_conv(OPENPGPKEY, 61,
+ conv.xfrBlob(d_keyring);
+ )
+
+DSRecordContent::DSRecordContent() {}
+boilerplate_conv(DS, 43,
+ conv.xfr16BitInt(d_tag);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfr8BitInt(d_digesttype);
+ conv.xfrHexBlob(d_digest, true); // keep reading across spaces
+ )
+
+CDSRecordContent::CDSRecordContent() {}
+boilerplate_conv(CDS, 59,
+ conv.xfr16BitInt(d_tag);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfr8BitInt(d_digesttype);
+ conv.xfrHexBlob(d_digest, true); // keep reading across spaces
+ )
+
+DLVRecordContent::DLVRecordContent() {}
+boilerplate_conv(DLV,32769 ,
+ conv.xfr16BitInt(d_tag);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfr8BitInt(d_digesttype);
+ conv.xfrHexBlob(d_digest, true); // keep reading across spaces
+ )
+
+
+boilerplate_conv(SSHFP, 44,
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfr8BitInt(d_fptype);
+ conv.xfrHexBlob(d_fingerprint, true);
+ )
+
+boilerplate_conv(RRSIG, 46,
+ conv.xfrType(d_type);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfr8BitInt(d_labels);
+ conv.xfr32BitInt(d_originalttl);
+ conv.xfrTime(d_sigexpire);
+ conv.xfrTime(d_siginception);
+ conv.xfr16BitInt(d_tag);
+ conv.xfrName(d_signer);
+ conv.xfrBlob(d_signature);
+ )
+
+RRSIGRecordContent::RRSIGRecordContent() {}
+
+boilerplate_conv(DNSKEY, 48,
+ conv.xfr16BitInt(d_flags);
+ conv.xfr8BitInt(d_protocol);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfrBlob(d_key);
+ )
+DNSKEYRecordContent::DNSKEYRecordContent() {}
+
+boilerplate_conv(CDNSKEY, 60,
+ conv.xfr16BitInt(d_flags);
+ conv.xfr8BitInt(d_protocol);
+ conv.xfr8BitInt(d_algorithm);
+ conv.xfrBlob(d_key);
+ )
+CDNSKEYRecordContent::CDNSKEYRecordContent() {}
+
+boilerplate_conv(RKEY, 57,
+ conv.xfr16BitInt(d_flags);
+ conv.xfr8BitInt(d_protocol);
+ conv.xfrBlob(d_key);
+ )
+RKEYRecordContent::RKEYRecordContent() {}
+
+/* EUI48 start */
+void EUI48RecordContent::report(void)
+{
+ regist(1, QType::EUI48, &make, &make, "EUI48");
+}
+DNSRecordContent* EUI48RecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ if(dr.d_clen!=6)
+ throw MOADNSException("Wrong size for EUI48 record");
+
+ EUI48RecordContent* ret=new EUI48RecordContent();
+ pr.copyRecord((uint8_t*) &ret->d_eui48, 6);
+ return ret;
+}
+DNSRecordContent* EUI48RecordContent::make(const string& zone)
+{
+ // try to parse
+ EUI48RecordContent *ret=new EUI48RecordContent();
+ // format is 6 hex bytes and dashes
+ if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
+ ret->d_eui48, ret->d_eui48+1, ret->d_eui48+2,
+ ret->d_eui48+3, ret->d_eui48+4, ret->d_eui48+5) != 6) {
+ throw MOADNSException("Asked to encode '"+zone+"' as an EUI48 address, but does not parse");
+ }
+ return ret;
+}
+void EUI48RecordContent::toPacket(DNSPacketWriter& pw)
+{
+ string blob(d_eui48, d_eui48+6);
+ pw.xfrBlob(blob);
+}
+string EUI48RecordContent::getZoneRepresentation(bool noDot) const
+{
+ char tmp[18];
+ snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x",
+ d_eui48[0], d_eui48[1], d_eui48[2],
+ d_eui48[3], d_eui48[4], d_eui48[5]);
+ return tmp;
+}
+
+/* EUI48 end */
+
+/* EUI64 start */
+
+void EUI64RecordContent::report(void)
+{
+ regist(1, QType::EUI64, &make, &make, "EUI64");
+}
+DNSRecordContent* EUI64RecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ if(dr.d_clen!=8)
+ throw MOADNSException("Wrong size for EUI64 record");
+
+ EUI64RecordContent* ret=new EUI64RecordContent();
+ pr.copyRecord((uint8_t*) &ret->d_eui64, 8);
+ return ret;
+}
+DNSRecordContent* EUI64RecordContent::make(const string& zone)
+{
+ // try to parse
+ EUI64RecordContent *ret=new EUI64RecordContent();
+ // format is 8 hex bytes and dashes
+ if (sscanf(zone.c_str(), "%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx-%2hhx",
+ ret->d_eui64, ret->d_eui64+1, ret->d_eui64+2,
+ ret->d_eui64+3, ret->d_eui64+4, ret->d_eui64+5,
+ ret->d_eui64+6, ret->d_eui64+7) != 8) {
+ throw MOADNSException("Asked to encode '"+zone+"' as an EUI64 address, but does not parse");
+ }
+ return ret;
+}
+void EUI64RecordContent::toPacket(DNSPacketWriter& pw)
+{
+ string blob(d_eui64, d_eui64+8);
+ pw.xfrBlob(blob);
+}
+string EUI64RecordContent::getZoneRepresentation(bool noDot) const
+{
+ char tmp[24];
+ snprintf(tmp,sizeof(tmp),"%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x",
+ d_eui64[0], d_eui64[1], d_eui64[2],
+ d_eui64[3], d_eui64[4], d_eui64[5],
+ d_eui64[6], d_eui64[7]);
+ return tmp;
+}
+
+/* EUI64 end */
+
+boilerplate_conv(TKEY, QType::TKEY,
+ conv.xfrName(d_algo);
+ conv.xfr32BitInt(d_inception);
+ conv.xfr32BitInt(d_expiration);
+ conv.xfr16BitInt(d_mode);
+ conv.xfr16BitInt(d_error);
+ conv.xfr16BitInt(d_keysize);
+ if (d_keysize>0) conv.xfrBlobNoSpaces(d_key, d_keysize);
+ conv.xfr16BitInt(d_othersize);
+ if (d_othersize>0) conv.xfrBlobNoSpaces(d_other, d_othersize);
+ )
+TKEYRecordContent::TKEYRecordContent() { d_othersize = 0; } // fix CID#1288932
+
+boilerplate_conv(URI, QType::URI,
+ conv.xfr16BitInt(d_priority);
+ conv.xfr16BitInt(d_weight);
+ conv.xfrText(d_target, true, false);
+ )
+
+boilerplate_conv(CAA, QType::CAA,
+ conv.xfr8BitInt(d_flags);
+ conv.xfrUnquotedText(d_tag, true);
+ conv.xfrText(d_value, true, false); /* no lenField */
+ )
+
+static uint16_t makeTag(const std::string& data)
+{
+ const unsigned char* key=(const unsigned char*)data.c_str();
+ unsigned int keysize=data.length();
+
+ unsigned long ac; /* assumed to be 32 bits or larger */
+ unsigned int i; /* loop index */
+
+ for ( ac = 0, i = 0; i < keysize; ++i )
+ ac += (i & 1) ? key[i] : key[i] << 8;
+ ac += (ac >> 16) & 0xFFFF;
+ return ac & 0xFFFF;
+}
+
+uint16_t DNSKEYRecordContent::getTag() const
+{
+ DNSKEYRecordContent tmp(*this);
+ return makeTag(tmp.serialize(DNSName())); // this can't be const for some reason
+}
+
+uint16_t DNSKEYRecordContent::getTag()
+{
+ return makeTag(this->serialize(DNSName()));
+}
+
+
+bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo)
+{
+ eo->d_Z=0;
+ if(mdp.d_header.arcount && !mdp.d_answers.empty()) {
+ for(const MOADNSParser::answers_t::value_type& val : mdp.d_answers) {
+ if(val.first.d_place == DNSResourceRecord::ADDITIONAL && val.first.d_type == QType::OPT) {
+ eo->d_packetsize=val.first.d_class;
+
+ EDNS0Record stuff;
+ uint32_t ttl=ntohl(val.first.d_ttl);
+ static_assert(sizeof(EDNS0Record) == sizeof(uint32_t), "sizeof(EDNS0Record) must match sizeof(uint32_t)");
+ memcpy(&stuff, &ttl, sizeof(stuff));
+
+ eo->d_extRCode=stuff.extRCode;
+ eo->d_version=stuff.version;
+ eo->d_Z = ntohs(stuff.Z);
+ OPTRecordContent* orc =
+ dynamic_cast<OPTRecordContent*>(val.first.d_content.get());
+ if(!orc)
+ return false;
+ orc->getData(eo->d_options);
+ return true;
+ }
+ }
+ }
+ return false;
+}
+
+DNSRecord makeOpt(int udpsize, int extRCode, int Z)
+{
+ EDNS0Record stuff;
+ stuff.extRCode=0;
+ stuff.version=0;
+ stuff.Z=htons(Z);
+ DNSRecord dr;
+ static_assert(sizeof(EDNS0Record) == sizeof(dr.d_ttl), "sizeof(EDNS0Record) must match sizeof(DNSRecord.d_ttl)");
+ memcpy(&dr.d_ttl, &stuff, sizeof(stuff));
+ dr.d_ttl=ntohl(dr.d_ttl);
+ dr.d_name=DNSName(".");
+ dr.d_type = QType::OPT;
+ dr.d_class=udpsize;
+ dr.d_place=DNSResourceRecord::ADDITIONAL;
+ dr.d_content = std::make_shared<OPTRecordContent>();
+ // if we ever do options, I think we stuff them into OPTRecordContent::data
+ return dr;
+}
+
+
+void reportBasicTypes()
+{
+ ARecordContent::report();
+ AAAARecordContent::report();
+ NSRecordContent::report();
+ CNAMERecordContent::report();
+ MXRecordContent::report();
+ SOARecordContent::report();
+ SRVRecordContent::report();
+ PTRRecordContent::report();
+ DNSRecordContent::regist(QClass::CHAOS, QType::TXT, &TXTRecordContent::make, &TXTRecordContent::make, "TXT");
+ TXTRecordContent::report();
+ DNSRecordContent::regist(QClass::IN, QType::ANY, 0, 0, "ANY");
+ DNSRecordContent::regist(QClass::IN, QType::AXFR, 0, 0, "AXFR");
+ DNSRecordContent::regist(QClass::IN, QType::IXFR, 0, 0, "IXFR");
+}
+
+void reportOtherTypes()
+{
+ AFSDBRecordContent::report();
+ DNAMERecordContent::report();
+ ALIASRecordContent::report();
+ SPFRecordContent::report();
+ NAPTRRecordContent::report();
+ LOCRecordContent::report();
+ HINFORecordContent::report();
+ RPRecordContent::report();
+ KEYRecordContent::report();
+ DNSKEYRecordContent::report();
+ DHCIDRecordContent::report();
+ CDNSKEYRecordContent::report();
+ RKEYRecordContent::report();
+ RRSIGRecordContent::report();
+ DSRecordContent::report();
+ CDSRecordContent::report();
+ SSHFPRecordContent::report();
+ CERTRecordContent::report();
+ NSECRecordContent::report();
+ NSEC3RecordContent::report();
+ NSEC3PARAMRecordContent::report();
+ TLSARecordContent::report();
+ OPENPGPKEYRecordContent::report();
+ DLVRecordContent::report();
+ DNSRecordContent::regist(QClass::ANY, QType::TSIG, &TSIGRecordContent::make, &TSIGRecordContent::make, "TSIG");
+ DNSRecordContent::regist(QClass::ANY, QType::TKEY, &TKEYRecordContent::make, &TKEYRecordContent::make, "TKEY");
+ //TSIGRecordContent::report();
+ OPTRecordContent::report();
+ EUI48RecordContent::report();
+ EUI64RecordContent::report();
+ MINFORecordContent::report();
+ URIRecordContent::report();
+ CAARecordContent::report();
+}
+
+void reportAllTypes()
+{
+ reportBasicTypes();
+ reportOtherTypes();
+}
+
+ComboAddress getAddr(const DNSRecord& dr, uint16_t defport)
+{
+ if(auto addr=getRR<ARecordContent>(dr)) {
+ return addr->getCA(defport);
+ }
+ else
+ return getRR<AAAARecordContent>(dr)->getCA(defport);
+}
+
+
+#if 0
+static struct Reporter
+{
+ Reporter()
+ {
+ reportAllTypes();
+ }
+} reporter __attribute__((init_priority(65535)));
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNSRECORDS_HH
+#define PDNS_DNSRECORDS_HH
+
+#include "dnsparser.hh"
+#include "dnswriter.hh"
+#include "rcpgenerator.hh"
+#include <set>
+#include <bitset>
+#include "namespaces.hh"
+
+#define includeboilerplate(RNAME) RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr); \
+ RNAME##RecordContent(const string& zoneData); \
+ static void report(void); \
+ static void unreport(void); \
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr); \
+ static DNSRecordContent* make(const string& zonedata); \
+ string getZoneRepresentation(bool noDot=false) const override; \
+ void toPacket(DNSPacketWriter& pw) override; \
+ uint16_t getType() const override { return QType::RNAME; } \
+ template<class Convertor> void xfrPacket(Convertor& conv, bool noDot=false);
+
+class NAPTRRecordContent : public DNSRecordContent
+{
+public:
+ NAPTRRecordContent(uint16_t order, uint16_t preference, string flags, string services, string regexp, DNSName replacement);
+
+ includeboilerplate(NAPTR);
+ template<class Convertor> void xfrRecordContent(Convertor& conv);
+private:
+ uint16_t d_order, d_preference;
+ string d_flags, d_services, d_regexp;
+ DNSName d_replacement;
+};
+
+
+class ARecordContent : public DNSRecordContent
+{
+public:
+ explicit ARecordContent(const ComboAddress& ca);
+ explicit ARecordContent(uint32_t ip);
+ includeboilerplate(A);
+ void doRecordCheck(const DNSRecord& dr);
+ ComboAddress getCA(int port=0) const;
+private:
+ uint32_t d_ip;
+};
+
+class AAAARecordContent : public DNSRecordContent
+{
+public:
+ AAAARecordContent(std::string &val);
+ explicit AAAARecordContent(const ComboAddress& ca);
+ includeboilerplate(AAAA);
+ ComboAddress getCA(int port=0) const;
+private:
+ string d_ip6; // why??
+};
+
+class MXRecordContent : public DNSRecordContent
+{
+public:
+ MXRecordContent(uint16_t preference, const DNSName& mxname);
+
+ includeboilerplate(MX)
+
+ uint16_t d_preference;
+ DNSName d_mxname;
+};
+
+class KXRecordContent : public DNSRecordContent
+{
+public:
+ KXRecordContent(uint16_t preference, const DNSName& exchanger);
+
+ includeboilerplate(KX)
+
+private:
+ uint16_t d_preference;
+ DNSName d_exchanger;
+};
+
+class IPSECKEYRecordContent : public DNSRecordContent
+{
+public:
+ IPSECKEYRecordContent(uint16_t preference, uint8_t gatewaytype, uint8_t algo, const DNSName& gateway, const string& publickey);
+
+ includeboilerplate(IPSECKEY)
+
+private:
+ uint32_t d_ip4;
+ DNSName d_gateway;
+ string d_publickey;
+ string d_ip6;
+ uint8_t d_preference, d_gatewaytype, d_algorithm;
+};
+
+class DHCIDRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(DHCID)
+
+private:
+ string d_content;
+};
+
+
+class SRVRecordContent : public DNSRecordContent
+{
+public:
+ SRVRecordContent(uint16_t preference, uint16_t weight, uint16_t port, const DNSName& target);
+
+ includeboilerplate(SRV)
+
+ uint16_t d_weight, d_port;
+ DNSName d_target;
+ uint16_t d_preference;
+};
+
+class TSIGRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(TSIG)
+ TSIGRecordContent() {}
+
+ uint16_t d_origID{0};
+ uint16_t d_fudge{0};
+
+ DNSName d_algoName;
+ string d_mac;
+ string d_otherData;
+ uint64_t d_time{0};
+ // uint16_t d_macSize;
+ uint16_t d_eRcode{0};
+ // uint16_t d_otherLen
+};
+
+
+class TXTRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(TXT)
+
+private:
+ string d_text;
+};
+
+class SPFRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(SPF)
+
+private:
+ string d_text;
+};
+
+
+class NSRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(NS)
+ explicit NSRecordContent(const DNSName& content) : d_content(content){}
+ DNSName getNS() const { return d_content; }
+private:
+ DNSName d_content;
+};
+
+class PTRRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(PTR)
+
+private:
+ DNSName d_content;
+};
+
+class CNAMERecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(CNAME)
+ DNSName getTarget() const { return d_content; }
+private:
+ DNSName d_content;
+};
+
+class ALIASRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(ALIAS)
+
+private:
+ DNSName d_content;
+};
+
+
+class DNAMERecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(DNAME)
+
+private:
+ DNSName d_content;
+};
+
+
+class MRRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(MR)
+
+private:
+ DNSName d_alias;
+};
+
+class MINFORecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(MINFO)
+
+private:
+ DNSName d_rmailbx;
+ DNSName d_emailbx;
+};
+
+class OPTRecordContent : public DNSRecordContent
+{
+public:
+ OPTRecordContent(){}
+ includeboilerplate(OPT)
+ void getData(vector<pair<uint16_t, string> > &opts);
+private:
+ string d_data;
+};
+
+
+class HINFORecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(HINFO)
+
+private:
+ string d_cpu, d_host;
+};
+
+class RPRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(RP)
+
+private:
+ DNSName d_mbox, d_info;
+};
+
+
+class DNSKEYRecordContent : public DNSRecordContent
+{
+public:
+ DNSKEYRecordContent();
+ includeboilerplate(DNSKEY)
+ uint16_t getTag() const;
+ uint16_t getTag();
+
+ uint16_t d_flags{0};
+ uint8_t d_protocol{0};
+ uint8_t d_algorithm{0};
+ string d_key;
+ bool operator<(const DNSKEYRecordContent& rhs) const
+ {
+ return tie(d_flags, d_protocol, d_algorithm, d_key) <
+ tie(rhs.d_flags, rhs.d_protocol, rhs.d_algorithm, rhs.d_key);
+ }
+};
+
+class CDNSKEYRecordContent : public DNSRecordContent
+{
+public:
+ CDNSKEYRecordContent();
+ includeboilerplate(CDNSKEY)
+ uint16_t getTag();
+
+ uint16_t d_flags{0};
+ uint8_t d_protocol{0};
+ uint8_t d_algorithm{0};
+ string d_key;
+};
+
+class DSRecordContent : public DNSRecordContent
+{
+public:
+ DSRecordContent();
+ bool operator==(const DSRecordContent& rhs) const
+ {
+ return tie(d_tag, d_algorithm, d_digesttype, d_digest) ==
+ tie(rhs.d_tag, rhs.d_algorithm, rhs.d_digesttype, rhs.d_digest);
+ }
+ bool operator<(const DSRecordContent& rhs) const
+ {
+ return tie(d_tag, d_algorithm, d_digesttype, d_digest) <
+ tie(rhs.d_tag, rhs.d_algorithm, rhs.d_digesttype, rhs.d_digest);
+ }
+
+ includeboilerplate(DS)
+
+ uint16_t d_tag{0};
+ uint8_t d_algorithm{0}, d_digesttype{0};
+ string d_digest;
+};
+
+class CDSRecordContent : public DNSRecordContent
+{
+public:
+ CDSRecordContent();
+ includeboilerplate(CDS)
+
+ uint16_t d_tag{0};
+ uint8_t d_algorithm{0}, d_digesttype{0};
+ string d_digest;
+};
+
+class DLVRecordContent : public DNSRecordContent
+{
+public:
+ DLVRecordContent();
+ includeboilerplate(DLV)
+
+ uint16_t d_tag{0};
+ uint8_t d_algorithm{0}, d_digesttype{0};
+ string d_digest;
+};
+
+
+class SSHFPRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(SSHFP)
+
+private:
+ uint8_t d_algorithm, d_fptype;
+ string d_fingerprint;
+};
+
+class KEYRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(KEY)
+
+private:
+ uint16_t d_flags;
+ uint8_t d_protocol, d_algorithm;
+ string d_certificate;
+};
+
+class AFSDBRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(AFSDB)
+
+private:
+ uint16_t d_subtype;
+ DNSName d_hostname;
+};
+
+
+class CERTRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(CERT)
+
+private:
+ uint16_t d_type, d_tag;
+ string d_certificate;
+ uint8_t d_algorithm;
+};
+
+class TLSARecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(TLSA)
+
+private:
+ uint8_t d_certusage, d_selector, d_matchtype;
+ string d_cert;
+};
+
+class OPENPGPKEYRecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(OPENPGPKEY)
+
+private:
+ string d_keyring;
+};
+
+
+class RRSIGRecordContent : public DNSRecordContent
+{
+public:
+ RRSIGRecordContent();
+ includeboilerplate(RRSIG)
+
+ uint16_t d_type{0};
+ uint16_t d_tag{0};
+ DNSName d_signer;
+ string d_signature;
+ uint32_t d_originalttl{0}, d_sigexpire{0}, d_siginception{0};
+ uint8_t d_algorithm{0}, d_labels{0};
+};
+
+//namespace {
+ struct soatimes
+ {
+ uint32_t serial;
+ uint32_t refresh;
+ uint32_t retry;
+ uint32_t expire;
+ uint32_t minimum;
+ };
+//}
+
+class RKEYRecordContent : public DNSRecordContent
+{
+public:
+ RKEYRecordContent();
+ includeboilerplate(RKEY)
+ uint16_t d_flags{0};
+ uint8_t d_protocol{0}, d_algorithm{0};
+ string d_key;
+};
+
+class SOARecordContent : public DNSRecordContent
+{
+public:
+ includeboilerplate(SOA)
+ SOARecordContent(const DNSName& mname, const DNSName& rname, const struct soatimes& st);
+
+ struct soatimes d_st;
+ DNSName d_mname;
+ DNSName d_rname;
+};
+
+class NSECRecordContent : public DNSRecordContent
+{
+public:
+ static void report(void);
+ NSECRecordContent()
+ {}
+ NSECRecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone?
+
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& content);
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+ uint16_t getType() const override
+ {
+ return QType::NSEC;
+ }
+ DNSName d_next;
+ std::set<uint16_t> d_set;
+private:
+};
+
+class NSEC3RecordContent : public DNSRecordContent
+{
+public:
+ static void report(void);
+ NSEC3RecordContent()
+ {}
+ NSEC3RecordContent(const string& content, const string& zone=""); //FIXME400: DNSName& zone?
+
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& content);
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+
+ uint8_t d_algorithm{0}, d_flags{0};
+ uint16_t d_iterations{0};
+ string d_salt;
+ string d_nexthash;
+ std::set<uint16_t> d_set;
+
+ uint16_t getType() const override
+ {
+ return QType::NSEC3;
+ }
+
+
+private:
+};
+
+
+class NSEC3PARAMRecordContent : public DNSRecordContent
+{
+public:
+ static void report(void);
+ NSEC3PARAMRecordContent()
+ {}
+ NSEC3PARAMRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone?
+
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& content);
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+
+ uint16_t getType() const override
+ {
+ return QType::NSEC3PARAM;
+ }
+
+
+ uint8_t d_algorithm{0}, d_flags{0};
+ uint16_t d_iterations{0};
+ string d_salt;
+};
+
+
+class LOCRecordContent : public DNSRecordContent
+{
+public:
+ static void report(void);
+ LOCRecordContent()
+ {}
+ LOCRecordContent(const string& content, const string& zone="");
+
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& content);
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+
+ uint8_t d_version{0}, d_size{0}, d_horizpre{0}, d_vertpre{0};
+ uint32_t d_latitude{0}, d_longitude{0}, d_altitude{0};
+ uint16_t getType() const override
+ {
+ return QType::LOC;
+ }
+
+private:
+};
+
+
+class WKSRecordContent : public DNSRecordContent
+{
+public:
+ static void report(void);
+ WKSRecordContent()
+ {}
+ WKSRecordContent(const string& content, const string& zone=""); // FIXME400: DNSName& zone?
+
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& content);
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+
+ uint32_t d_ip{0};
+ std::bitset<65535> d_services;
+private:
+};
+
+class EUI48RecordContent : public DNSRecordContent
+{
+public:
+ EUI48RecordContent() {};
+ static void report(void);
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone?
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+ uint16_t getType() const override { return QType::EUI48; }
+private:
+ // storage for the bytes
+ uint8_t d_eui48[6];
+};
+
+class EUI64RecordContent : public DNSRecordContent
+{
+public:
+ EUI64RecordContent() {};
+ static void report(void);
+ static DNSRecordContent* make(const DNSRecord &dr, PacketReader& pr);
+ static DNSRecordContent* make(const string& zone); // FIXME400: DNSName& zone?
+ string getZoneRepresentation(bool noDot=false) const override;
+ void toPacket(DNSPacketWriter& pw) override;
+ uint16_t getType() const override { return QType::EUI64; }
+private:
+ // storage for the bytes
+ uint8_t d_eui64[8];
+};
+
+class TKEYRecordContent : public DNSRecordContent
+{
+public:
+ TKEYRecordContent();
+ includeboilerplate(TKEY)
+
+ // storage for the bytes
+ uint16_t d_othersize{0};
+ uint16_t d_mode{0};
+ uint32_t d_inception{0};
+ uint32_t d_expiration{0};
+
+ DNSName d_algo;
+ string d_key;
+ string d_other;
+
+ uint16_t d_error{0};
+ uint16_t d_keysize{0};
+private:
+};
+
+class URIRecordContent : public DNSRecordContent {
+ public:
+ includeboilerplate(URI)
+ private:
+ uint16_t d_priority, d_weight;
+ string d_target;
+};
+
+class CAARecordContent : public DNSRecordContent {
+ public:
+ includeboilerplate(CAA)
+ private:
+ uint8_t d_flags;
+ string d_tag, d_value;
+};
+
+#define boilerplate(RNAME, RTYPE) \
+RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const DNSRecord& dr, PacketReader& pr) \
+{ \
+ return new RNAME##RecordContent(dr, pr); \
+} \
+ \
+RNAME##RecordContent::RNAME##RecordContent(const DNSRecord& dr, PacketReader& pr) \
+{ \
+ doRecordCheck(dr); \
+ xfrPacket(pr); \
+} \
+ \
+RNAME##RecordContent::DNSRecordContent* RNAME##RecordContent::make(const string& zonedata) \
+{ \
+ return new RNAME##RecordContent(zonedata); \
+} \
+ \
+void RNAME##RecordContent::toPacket(DNSPacketWriter& pw) \
+{ \
+ this->xfrPacket(pw); \
+} \
+ \
+void RNAME##RecordContent::report(void) \
+{ \
+ regist(1, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \
+ regist(254, RTYPE, &RNAME##RecordContent::make, &RNAME##RecordContent::make, #RNAME); \
+} \
+void RNAME##RecordContent::unreport(void) \
+{ \
+ unregist(1, RTYPE); \
+ unregist(254, RTYPE); \
+} \
+ \
+RNAME##RecordContent::RNAME##RecordContent(const string& zoneData) \
+{ \
+ try { \
+ RecordTextReader rtr(zoneData); \
+ xfrPacket(rtr); \
+ } \
+ catch(RecordTextException& rtr) { \
+ throw MOADNSException("Parsing record content (try 'pdnsutil check-zone'): "+string(rtr.what())); \
+ } \
+} \
+ \
+string RNAME##RecordContent::getZoneRepresentation(bool noDot) const \
+{ \
+ string ret; \
+ RecordTextWriter rtw(ret, noDot); \
+ const_cast<RNAME##RecordContent*>(this)->xfrPacket(rtw); \
+ return ret; \
+}
+
+
+#define boilerplate_conv(RNAME, TYPE, CONV) \
+boilerplate(RNAME, TYPE) \
+template<class Convertor> \
+void RNAME##RecordContent::xfrPacket(Convertor& conv, bool noDot) \
+{ \
+ CONV; \
+ if (conv.eof() == false) throw MOADNSException("All data was not consumed"); \
+} \
+
+struct EDNSOpts
+{
+ enum zFlags { DNSSECOK=32768 };
+ vector<pair<uint16_t, string> > d_options;
+ uint16_t d_packetsize{0};
+ uint16_t d_Z{0};
+ uint8_t d_extRCode, d_version;
+};
+//! Convenience function that fills out EDNS0 options, and returns true if there are any
+
+class MOADNSParser;
+bool getEDNSOpts(const MOADNSParser& mdp, EDNSOpts* eo);
+DNSRecord makeOpt(int udpsize, int extRCode, int Z);
+void reportBasicTypes();
+void reportOtherTypes();
+void reportAllTypes();
+ComboAddress getAddr(const DNSRecord& dr, uint16_t defport=0);
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+/**
+Replay all recursion-desired DNS questions to a specified IP address.
+
+Track all outgoing questions, remap id to one of ours.
+Also track all recorded answers, and map them to that same id, the 'expectation'.
+
+When we see a question, parse it, give it a QuestionIdentifyer, and and an id from the free-id list.
+
+When we see an answer in the tcpdump, parse it, make QI, and add it to the original QI
+ and check
+
+When we see an answer from the socket, use the id to match it up to the original QI
+ and check
+
+There is one central object, which has (when complete)
+ our assigned id
+ QI
+ Original answer
+ Socket answer
+
+What to do with timeouts. We keep around at most 65536 outstanding answers.
+*/
+
+/*
+ mental_clock=0;
+ for(;;) {
+
+ do {
+ read a packet
+ send a packet
+ } while(time_of_last_packet_sent < mental_clock)
+ mental_clock=time_of_last_packet_sent;
+
+ wait for a response packet for 0.1 seconds
+ note how much time has passed
+ mental_clock+=time_passed;
+ }
+
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <bitset>
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "sstuff.hh"
+#include "anadns.hh"
+#include <boost/program_options.hpp>
+#include "dnsrecords.hh"
+#include "ednssubnet.hh"
+#include "ednsoptions.hh"
+// this is needed because boost multi_index also uses 'L', as do we (which is sad enough)
+#undef L
+
+#include <set>
+#include <deque>
+
+#include <boost/format.hpp>
+#include <boost/utility.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+#include "namespaces.hh"
+
+StatBag S;
+bool g_quiet=true;
+int g_timeoutMsec=0;
+
+namespace po = boost::program_options;
+
+po::variables_map g_vm;
+
+const struct timeval operator*(float fact, const struct timeval& rhs)
+{
+ // cout<<"In: "<<rhs.tv_sec<<" + "<<rhs.tv_usec<<"\n";
+ struct timeval ret;
+ if( (2000000000 / fact) < rhs.tv_usec) {
+ double d=1.0 * rhs.tv_usec * fact;
+ ret.tv_sec=fact * rhs.tv_sec;
+ ret.tv_sec+=(int) (d/1000000);
+ d/=1000000;
+ d-=(int)d;
+
+ ret.tv_usec=(unsigned int)(1000000*d);
+ normalizeTV(ret);
+
+ cout<<"out complex: "<<ret.tv_sec<<" + "<<ret.tv_usec<<"\n";
+
+ return ret;
+ }
+
+ ret.tv_sec=rhs.tv_sec * fact;
+ ret.tv_usec=rhs.tv_usec * fact;
+
+ normalizeTV(ret);
+ // cout<<"out simple: "<<ret.tv_sec<<" + "<<ret.tv_usec<<"\n";
+ return ret;
+}
+
+bool g_pleaseQuit;
+void pleaseQuitHandler(int)
+{
+ g_pleaseQuit=true;
+}
+
+class DNSIDManager : public boost::noncopyable
+{
+public:
+ DNSIDManager()
+ {
+ for(unsigned int i=0; i < 65536; ++i)
+ d_available.push_back(i);
+ }
+
+ uint16_t peakID()
+ {
+ uint16_t ret;
+ if(!d_available.empty()) {
+ ret=d_available.front();
+ return ret;
+ }
+ else
+ throw runtime_error("out of ids!"); // XXX FIXME
+ }
+
+ uint16_t getID()
+ {
+ uint16_t ret=peakID();
+ d_available.pop_front();
+ return ret;
+ }
+
+ void releaseID(uint16_t id)
+ {
+ d_available.push_back(id);
+ }
+
+private:
+ deque<uint16_t> d_available;
+
+} s_idmanager;
+
+
+void setSocketBuffer(int fd, int optname, uint32_t size)
+{
+ uint32_t psize=0;
+ socklen_t len=sizeof(psize);
+
+ if(!getsockopt(fd, SOL_SOCKET, optname, (char*)&psize, &len) && psize > size) {
+ cerr<<"Not decreasing socket buffer size from "<<psize<<" to "<<size<<endl;
+ return;
+ }
+
+ if (setsockopt(fd, SOL_SOCKET, optname, (char*)&size, sizeof(size)) < 0 )
+ cerr<<"Warning: unable to raise socket buffer size to "<<size<<": "<<strerror(errno)<<endl;
+}
+
+static void setSocketReceiveBuffer(int fd, uint32_t size)
+{
+ setSocketBuffer(fd, SO_RCVBUF, size);
+}
+
+static void setSocketSendBuffer(int fd, uint32_t size)
+{
+ setSocketBuffer(fd, SO_SNDBUF, size);
+}
+
+
+struct AssignedIDTag{};
+struct QuestionTag{};
+
+struct QuestionData
+{
+ QuestionData() : d_assignedID(-1), d_origRcode(-1), d_newRcode(-1), d_norecursionavailable(false), d_origlate(false), d_newlate(false)
+ {
+ }
+ QuestionIdentifier d_qi;
+ int d_assignedID;
+ MOADNSParser::answers_t d_origAnswers, d_newAnswers;
+ int d_origRcode, d_newRcode;
+ struct timeval d_resentTime;
+ bool d_norecursionavailable;
+ bool d_origlate, d_newlate;
+};
+
+typedef multi_index_container<
+ QuestionData,
+ indexed_by<
+ ordered_unique<tag<QuestionTag>, BOOST_MULTI_INDEX_MEMBER(QuestionData, QuestionIdentifier, d_qi) > ,
+ ordered_unique<tag<AssignedIDTag>, BOOST_MULTI_INDEX_MEMBER(QuestionData, int, d_assignedID) >
+ >
+> qids_t;
+
+qids_t qids;
+bool g_throttled;
+
+unsigned int s_questions, s_origanswers, s_weanswers, s_wetimedout, s_perfect, s_mostly, s_origtimedout;
+unsigned int s_wenever, s_orignever;
+unsigned int s_webetter, s_origbetter, s_norecursionavailable;
+unsigned int s_weunmatched, s_origunmatched;
+unsigned int s_wednserrors, s_origdnserrors, s_duplicates;
+
+
+
+void WeOrigSlowQueriesDelta(int& weOutstanding, int& origOutstanding, int& weSlow, int& origSlow)
+{
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ weOutstanding=origOutstanding=weSlow=origSlow=0;
+
+ for(qids_t::iterator i=qids.begin(); i!=qids.end(); ++i) {
+ double dt=DiffTime(i->d_resentTime, now);
+ if(dt < 2.0) {
+ if(i->d_newRcode == -1)
+ weOutstanding++;
+ if(i->d_origRcode == -1)
+ origOutstanding++;
+ }
+ else {
+ if(i->d_newRcode == -1) {
+ weSlow++;
+ if(!i->d_newlate) {
+ QuestionData qd=*i;
+ qd.d_newlate=true;
+ qids.replace(i, qd);
+
+ s_wetimedout++;
+ }
+ }
+ if(i->d_origRcode == -1) {
+ origSlow++;
+ if(!i->d_origlate) {
+ QuestionData qd=*i;
+ qd.d_origlate=true;
+ qids.replace(i, qd);
+
+ s_origtimedout++;
+ }
+ }
+ }
+ }
+}
+
+void compactAnswerSet(MOADNSParser::answers_t orig, set<DNSRecord>& compacted)
+{
+ for(MOADNSParser::answers_t::const_iterator i=orig.begin(); i != orig.end(); ++i)
+ if(i->first.d_place==DNSResourceRecord::ANSWER)
+ compacted.insert(i->first);
+}
+
+bool isRcodeOk(int rcode)
+{
+ return rcode==0 || rcode==3;
+}
+
+set<pair<DNSName,uint16_t> > s_origbetterset;
+
+bool isRootReferral(const MOADNSParser::answers_t& answers)
+{
+ if(answers.empty())
+ return false;
+
+ bool ok=true;
+ for(MOADNSParser::answers_t::const_iterator iter = answers.begin(); iter != answers.end(); ++iter) {
+ // cerr<<(int)iter->first.d_place<<", "<<iter->first.d_name<<" "<<iter->first.d_type<<", # "<<answers.size()<<endl;
+ if(iter->first.d_place!=2)
+ ok=false;
+ if(!iter->first.d_name.isRoot() || iter->first.d_type!=QType::NS)
+ ok=false;
+ }
+ return ok;
+}
+
+vector<uint32_t> flightTimes;
+void accountFlightTime(qids_t::const_iterator iter)
+{
+ if(flightTimes.empty())
+ flightTimes.resize(2050);
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+ unsigned int mdiff = 1000*DiffTime(iter->d_resentTime, now);
+ if(mdiff > flightTimes.size()-2)
+ mdiff= flightTimes.size()-1;
+
+ flightTimes[mdiff]++;
+}
+
+uint64_t countLessThan(unsigned int msec)
+{
+ uint64_t ret=0;
+ for(unsigned int i = 0 ; i < msec && i < flightTimes.size() ; ++i) {
+ ret += flightTimes[i];
+ }
+ return ret;
+}
+
+void emitFlightTimes()
+{
+ uint64_t totals = countLessThan(flightTimes.size());
+ unsigned int limits[]={1, 2, 3, 4, 5, 10, 20, 30, 40, 50, 100, 200, 500, 1000, (unsigned int) flightTimes.size()};
+ uint64_t sofar=0;
+ cout.setf(std::ios::fixed);
+ cout.precision(2);
+ for(unsigned int i =0 ; i < sizeof(limits)/sizeof(limits[0]); ++i) {
+ if(limits[i]!=flightTimes.size())
+ cout<<"Within "<<limits[i]<<" msec: ";
+ else
+ cout<<"Beyond "<<limits[i]-2<<" msec: ";
+ uint64_t here = countLessThan(limits[i]);
+ cout<<100.0*here/totals<<"% ("<<100.0*(here-sofar)/totals<<"%)"<<endl;
+ sofar=here;
+
+ }
+}
+
+void measureResultAndClean(qids_t::const_iterator iter)
+{
+ const QuestionData& qd=*iter;
+ accountFlightTime(iter);
+
+ set<DNSRecord> canonicOrig, canonicNew;
+ compactAnswerSet(qd.d_origAnswers, canonicOrig);
+ compactAnswerSet(qd.d_newAnswers, canonicNew);
+
+ if(!g_quiet) {
+ cout<<qd.d_qi<<", orig rcode: "<<qd.d_origRcode<<", ours: "<<qd.d_newRcode;
+ cout<<", "<<canonicOrig.size()<< " vs " << canonicNew.size()<<", perfect: ";
+ }
+
+ if(canonicOrig==canonicNew) {
+ s_perfect++;
+ if(!g_quiet)
+ cout<<"yes\n";
+ }
+ else {
+ if(!g_quiet)
+ cout<<"no\n";
+
+ if(qd.d_norecursionavailable)
+ if(!g_quiet)
+ cout<<"\t* original nameserver did not provide recursion for this question *"<<endl;
+ if(qd.d_origRcode == qd.d_newRcode ) {
+ if(!g_quiet)
+ cout<<"\t* mostly correct *"<<endl;
+ s_mostly++;
+ }
+
+ if(!isRcodeOk(qd.d_origRcode) && isRcodeOk(qd.d_newRcode)) {
+ if(!g_quiet)
+ cout<<"\t* we better *"<<endl;
+ s_webetter++;
+ }
+ if(isRcodeOk(qd.d_origRcode) && !isRcodeOk(qd.d_newRcode) && !isRootReferral(qd.d_origAnswers)) {
+ if(!g_quiet)
+ cout<<"\t* orig better *"<<endl;
+ s_origbetter++;
+ if(!g_quiet)
+ if(s_origbetterset.insert(make_pair(qd.d_qi.d_qname, qd.d_qi.d_qtype)).second) {
+ cout<<"orig better: " << qd.d_qi.d_qname<<" "<< qd.d_qi.d_qtype<<endl;
+ }
+ }
+
+ if(!g_quiet) {
+ cout<<"orig: rcode="<<qd.d_origRcode<<"\n";
+ for(set<DNSRecord>::const_iterator i=canonicOrig.begin(); i!=canonicOrig.end(); ++i)
+ cout<<"\t"<<i->d_name<<"\t"<<DNSRecordContent::NumberToType(i->d_type)<<"\t'" << (i->d_content ? i->d_content->getZoneRepresentation() : "") <<"'\n";
+ cout<<"new: rcode="<<qd.d_newRcode<<"\n";
+ for(set<DNSRecord>::const_iterator i=canonicNew.begin(); i!=canonicNew.end(); ++i)
+ cout<<"\t"<<i->d_name<<"\t"<<DNSRecordContent::NumberToType(i->d_type)<<"\t'" << (i->d_content ? i->d_content->getZoneRepresentation() : "") <<"'\n";
+ cout<<"\n";
+ cout<<"-\n";
+
+ }
+ }
+
+ int releaseID=qd.d_assignedID;
+ qids.erase(iter); // qd invalid now
+ s_idmanager.releaseID(releaseID);
+}
+
+
+Socket *s_socket;
+
+void receiveFromReference()
+try
+{
+ string packet;
+ ComboAddress remote;
+ int res=waitForData(s_socket->getHandle(), g_timeoutMsec/1000, 1000*(g_timeoutMsec%1000));
+
+ if(res < 0 || res==0)
+ return;
+
+ while(s_socket->recvFromAsync(packet, remote)) {
+ try {
+ s_weanswers++;
+ MOADNSParser mdp(false, packet.c_str(), packet.length());
+ if(!mdp.d_header.qr) {
+ cout<<"Received a question from our reference nameserver!"<<endl;
+ continue;
+ }
+
+ typedef qids_t::index<AssignedIDTag>::type qids_by_id_index_t;
+ qids_by_id_index_t& idindex=qids.get<AssignedIDTag>();
+ qids_by_id_index_t::const_iterator found=idindex.find(ntohs(mdp.d_header.id));
+ if(found == idindex.end()) {
+ if(!g_quiet)
+ cout<<"Received an answer ("<<mdp.d_qname<<") from reference nameserver with id "<<mdp.d_header.id<<" which we can't match to a question!"<<endl;
+ s_weunmatched++;
+ continue;
+ }
+
+ QuestionData qd=*found; // we have to make a copy because we reinsert below
+ qd.d_newAnswers=mdp.d_answers;
+ qd.d_newRcode=mdp.d_header.rcode;
+ idindex.replace(found, qd);
+ if(qd.d_origRcode!=-1) {
+ qids_t::const_iterator iter= qids.project<0>(found);
+ measureResultAndClean(iter);
+ }
+ }
+ catch(MOADNSException &e)
+ {
+ s_wednserrors++;
+ }
+ catch(std::out_of_range &e)
+ {
+ s_wednserrors++;
+ }
+ catch(std::exception& e)
+ {
+ s_wednserrors++;
+ }
+ }
+}
+catch(std::exception& e)
+{
+ cerr<<"Receiver function died: "<<e.what()<<endl;
+ exit(1);
+}
+catch(...)
+{
+ cerr<<"Receiver function died with unknown exception"<<endl;
+ exit(1);
+}
+
+void pruneQids()
+{
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ for(qids_t::iterator i=qids.begin(); i!=qids.end(); ) {
+ if(DiffTime(i->d_resentTime, now) < 10)
+ ++i;
+ else {
+ s_idmanager.releaseID(i->d_assignedID);
+ if(i->d_newRcode==-1) {
+ s_wenever++;
+ }
+ if(i->d_origRcode==-1) {
+ s_orignever++;
+ }
+
+ qids.erase(i++);
+ }
+ }
+}
+
+void printStats(uint64_t origWaitingFor=0, uint64_t weWaitingFor=0)
+{
+ format headerfmt ("%|9t|Questions - Pend. - Drop = Answers = (On time + Late) = (Err + Ok)\n");
+ format datafmt("%s%|9t|%d %|21t|%d %|29t|%d %|36t|%d %|47t|%d %|57t|%d %|66t|%d %|72t|%d\n");
+
+ cerr<<headerfmt;
+ cerr<<(datafmt % "Orig" % s_questions % origWaitingFor % s_orignever % s_origanswers % 0 % s_origtimedout % 0 % 0);
+ cerr<<(datafmt % "Refer." % s_questions % weWaitingFor % s_wenever % s_weanswers % 0 % s_wetimedout % 0 % 0);
+
+ cerr<<weWaitingFor<<" queries that could still come in on time, "<<qids.size()<<" outstanding"<<endl;
+
+ cerr<<"we late: "<<s_wetimedout<<", orig late: "<< s_origtimedout<<", "<<s_questions<<" questions sent, "<<s_origanswers
+ <<" original answers, "<<s_perfect<<" perfect, "<<s_mostly<<" mostly correct"<<", "<<s_webetter<<" we better, "<<s_origbetter<<" orig better ("<<s_origbetterset.size()<<" diff)"<<endl;
+ cerr<<"we never: "<<s_wenever<<", orig never: "<<s_orignever<<endl;
+ cerr<<"original questions from IP addresses for which recursion was not available: "<<s_norecursionavailable<<endl;
+ cerr<<"Unmatched from us: "<<s_weunmatched<<", unmatched from original: "<<s_origunmatched << " ( - decoding err: "<<s_origunmatched-s_origdnserrors<<")"<<endl;
+ cerr<<"DNS decoding errors from us: "<<s_wednserrors<<", from original: "<<s_origdnserrors<<", exact duplicates from client: "<<s_duplicates<<endl<<endl;
+
+}
+
+void houseKeeping()
+{
+ static timeval last;
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ if(DiffTime(last, now) < 0.3)
+ return;
+
+ int weWaitingFor, origWaitingFor, weSlow, origSlow;
+ WeOrigSlowQueriesDelta(weWaitingFor, origWaitingFor, weSlow, origSlow);
+
+ if(!g_throttled) {
+ if( weWaitingFor > 1000) {
+ cerr<<"Too many questions ("<<weWaitingFor<<") outstanding, throttling"<<endl;
+ g_throttled=true;
+ }
+ }
+ else if(weWaitingFor < 750) {
+ cerr<<"Unthrottling ("<<weWaitingFor<<")"<<endl;
+ g_throttled=false;
+ }
+
+ if(DiffTime(last, now) < 2)
+ return;
+
+ last=now;
+
+ /*
+ Questions - Pend. - Drop = Answers = (On time + Late) = (Err + Ok)
+Orig 9 21 29 36 47 57 66 72
+
+
+ */
+
+ printStats(origWaitingFor, weWaitingFor);
+ pruneQids();
+}
+
+
+bool g_rdSelector;
+
+static void generateOptRR(const std::string& optRData, string& res)
+{
+ const uint8_t name = 0;
+ dnsrecordheader dh;
+ EDNS0Record edns0;
+ edns0.extRCode = 0;
+ edns0.version = 0;
+ edns0.Z = 0;
+
+ dh.d_type = htons(QType::OPT);
+ dh.d_class = htons(1280);
+ memcpy(&dh.d_ttl, &edns0, sizeof edns0);
+ dh.d_clen = htons((uint16_t) optRData.length());
+ res.assign((const char *) &name, sizeof name);
+ res.append((const char *) &dh, sizeof dh);
+ res.append(optRData.c_str(), optRData.length());
+}
+
+static void addECSOption(char* packet, const size_t& packetSize, uint16_t* len, const ComboAddress& remote, int stamp)
+{
+ string EDNSRR;
+ struct dnsheader* dh = (struct dnsheader*) packet;
+
+ EDNSSubnetOpts eso;
+ if(stamp < 0)
+ eso.source = Netmask(remote);
+ else {
+ ComboAddress stamped(remote);
+ *((char*)&stamped.sin4.sin_addr.s_addr)=stamp;
+ eso.source = Netmask(stamped);
+ }
+ string optRData=makeEDNSSubnetOptsString(eso);
+ string record;
+ generateEDNSOption(EDNSOptionCode::ECS, optRData, record);
+ generateOptRR(record, EDNSRR);
+
+
+ uint16_t arcount = ntohs(dh->arcount);
+ /* does it fit in the existing buffer? */
+ if (packetSize - *len > EDNSRR.size()) {
+ arcount++;
+ dh->arcount = htons(arcount);
+ memcpy(packet + *len, EDNSRR.c_str(), EDNSRR.size());
+ *len += EDNSRR.size();
+ }
+}
+
+
+bool sendPacketFromPR(PcapPacketReader& pr, const ComboAddress& remote, int stamp)
+{
+ dnsheader* dh=(dnsheader*)pr.d_payload;
+ bool sent=false;
+ if((ntohs(pr.d_udp->uh_dport)!=53 && ntohs(pr.d_udp->uh_sport)!=53) || dh->rd != g_rdSelector || (unsigned int)pr.d_len <= sizeof(dnsheader))
+ return sent;
+
+ QuestionData qd;
+ try {
+ // yes, we send out ALWAYS. Even if we don't do anything with it later,
+ if(!dh->qr) { // this is to stress out the reference server with all the pain
+ s_questions++;
+ qd.d_assignedID = s_idmanager.getID();
+ uint16_t tmp=dh->id;
+ dh->id=htons(qd.d_assignedID);
+ // dh->rd=1; // useful to replay traffic to auths to a recursor
+ uint16_t dlen = pr.d_len;
+
+ if (stamp >= 0) addECSOption((char*)pr.d_payload, 1500, &dlen, pr.getSource(), stamp);
+ pr.d_len=dlen;
+ s_socket->sendTo((const char*)pr.d_payload, dlen, remote);
+ sent=true;
+ dh->id=tmp;
+ }
+ MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
+ QuestionIdentifier qi=QuestionIdentifier::create(pr.getSource(), pr.getDest(), mdp);
+
+ if(!mdp.d_header.qr) {
+
+ if(qids.count(qi)) {
+ if(!g_quiet)
+ cout<<"Saw an exact duplicate question in PCAP "<<qi<< endl;
+ s_duplicates++;
+ s_idmanager.releaseID(qd.d_assignedID); // release = puts at back of pool
+ return sent;
+ }
+ // new question - ID assigned above already
+ qd.d_qi=qi;
+ gettimeofday(&qd.d_resentTime,0);
+ qids.insert(qd);
+ }
+ else {
+ s_origanswers++;
+ qids_t::const_iterator iter=qids.find(qi);
+ if(iter != qids.end()) {
+ QuestionData qd=*iter;
+ qd.d_origAnswers=mdp.d_answers;
+ qd.d_origRcode=mdp.d_header.rcode;
+
+ if(!dh->ra) {
+ s_norecursionavailable++;
+ qd.d_norecursionavailable=true;
+ }
+ qids.replace(iter, qd);
+
+ if(qd.d_newRcode!=-1) {
+ measureResultAndClean(iter);
+ }
+
+ return sent;
+ }
+ else {
+ s_origunmatched++;
+ if(!g_quiet)
+ cout<<"Unmatched original answer "<<qi<<endl;
+ }
+ }
+ }
+ catch(MOADNSException &e)
+ {
+ if(!g_quiet)
+ cerr<<"Error parsing packet: "<<e.what()<<endl;
+ s_idmanager.releaseID(qd.d_assignedID); // not added to qids for cleanup
+ s_origdnserrors++;
+ }
+ catch(std::exception &e)
+ {
+ if(!g_quiet)
+ cerr<<"Error parsing packet: "<<e.what()<<endl;
+
+ s_idmanager.releaseID(qd.d_assignedID); // not added to qids for cleanup
+ s_origdnserrors++;
+ }
+
+ return sent;
+}
+
+void usage(po::options_description &desc) {
+ cerr << "Usage: dnsreplay [OPTIONS] FILENAME [IP-ADDRESS] [PORT]"<<endl;
+ cerr << desc << "\n";
+}
+
+int main(int argc, char** argv)
+try
+{
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("version", "show version number")
+ ("packet-limit", po::value<uint32_t>()->default_value(0), "stop after this many packets")
+ ("quiet", po::value<bool>()->default_value(true), "don't be too noisy")
+ ("recursive", po::value<bool>()->default_value(true), "look at recursion desired packets, or not (defaults true)")
+ ("speedup", po::value<float>()->default_value(1), "replay at this speedup")
+ ("timeout-msec", po::value<uint32_t>()->default_value(500), "wait at least this many milliseconds for a reply")
+ ("ecs-stamp", "Add original IP address to ECS in replay")
+ ("ecs-mask", po::value<uint16_t>(), "Replace first octet of src IP address with this value in ECS")
+ ("source-ip", po::value<string>()->default_value(""), "IP to send the replayed packet from")
+ ("source-port", po::value<uint16_t>()->default_value(0), "Port to send the replayed packet from");
+
+ po::options_description alloptions;
+ po::options_description hidden("hidden options");
+ hidden.add_options()
+ ("pcap-source", po::value<string>(), "PCAP source file")
+ ("target-ip", po::value<string>()->default_value("127.0.0.1"), "target-ip")
+ ("target-port", po::value<uint16_t>()->default_value(5300), "target port");
+
+ alloptions.add(desc).add(hidden);
+ po::positional_options_description p;
+ p.add("pcap-source", 1);
+ p.add("target-ip", 1);
+ p.add("target-port", 1);
+
+ po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+ po::notify(g_vm);
+
+ reportAllTypes();
+
+ if (g_vm.count("help")) {
+ usage(desc);
+ return EXIT_SUCCESS;
+ }
+
+ if (g_vm.count("version")) {
+ cerr<<"dnsreplay "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+
+ if(!g_vm.count("pcap-source")) {
+ cerr<<"Fatal, need to specify at least a PCAP source file"<<endl;
+ usage(desc);
+ return EXIT_FAILURE;
+ }
+
+ uint32_t packetLimit = g_vm["packet-limit"].as<uint32_t>();
+
+ g_rdSelector = g_vm["recursive"].as<bool>();
+
+ g_quiet = g_vm["quiet"].as<bool>();
+
+ signal(SIGINT, pleaseQuitHandler);
+ float speedup=g_vm["speedup"].as<float>();
+ g_timeoutMsec=g_vm["timeout-msec"].as<uint32_t>();
+
+ PcapPacketReader pr(g_vm["pcap-source"].as<string>());
+ s_socket= new Socket(AF_INET, SOCK_DGRAM);
+
+ s_socket->setNonBlocking();
+
+ if(g_vm.count("source-ip") && !g_vm["source-ip"].as<string>().empty())
+ s_socket->bind(ComboAddress(g_vm["source-ip"].as<string>(), g_vm["source-port"].as<uint16_t>()));
+
+ setSocketReceiveBuffer(s_socket->getHandle(), 2000000);
+ setSocketSendBuffer(s_socket->getHandle(), 2000000);
+
+ ComboAddress remote(g_vm["target-ip"].as<string>(),
+ g_vm["target-port"].as<uint16_t>());
+
+ int stamp = -1;
+ if(g_vm.count("ecs-stamp") && g_vm.count("ecs-mask"))
+ stamp=g_vm["ecs-mask"].as<uint16_t>();
+
+ cerr<<"Replaying packets to: '"<<g_vm["target-ip"].as<string>()<<"', port "<<g_vm["target-port"].as<uint16_t>()<<endl;
+
+ unsigned int once=0;
+ struct timeval mental_time;
+ mental_time.tv_sec=0; mental_time.tv_usec=0;
+
+ if(!pr.getUDPPacket()) // we do this here so we error out more cleanly on no packets
+ return 0;
+ unsigned int count=0;
+ bool first = true;
+ for(;;) {
+ if(g_pleaseQuit) {
+ cerr<<"Interrupted from terminal"<<endl;
+ break;
+ }
+ if(!((once++)%100))
+ houseKeeping();
+
+ struct timeval packet_ts;
+ packet_ts.tv_sec = 0;
+ packet_ts.tv_usec = 0;
+
+ while(packet_ts < mental_time) {
+ if(!first && !pr.getUDPPacket()) // otherwise we miss the first packet
+ goto out;
+ first=false;
+
+ packet_ts.tv_sec = pr.d_pheader.ts.tv_sec;
+ packet_ts.tv_usec = pr.d_pheader.ts.tv_usec;
+
+ if(sendPacketFromPR(pr, remote, stamp))
+ count++;
+ }
+ if(packetLimit && count > packetLimit)
+ break;
+
+ mental_time=packet_ts;
+ struct timeval then, now;
+ gettimeofday(&then,0);
+
+ receiveFromReference();
+
+ gettimeofday(&now, 0);
+
+ mental_time= mental_time + speedup * (now-then);
+ }
+ out:;
+ sleep(1);
+ receiveFromReference();
+ printStats();
+ emitFlightTimes();
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <bitset>
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "sstuff.hh"
+#include "anadns.hh"
+
+// this is needed because boost multi_index also uses 'L', as do we (which is sad enough)
+#undef L
+
+#include <set>
+#include <deque>
+
+#include <boost/format.hpp>
+#include <boost/utility.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <cctype>
+
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+#include "namespaces.hh"
+StatBag S;
+
+void usage() {
+ cerr<<"syntax: dnsscan INFILE ..."<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ Socket sock(AF_INET, SOCK_DGRAM);
+
+ /*
+ IPEndpoint remote(argc > 2 ? argv[2] : "127.0.0.1",
+ argc > 3 ? atoi(argv[3]) : 5300);
+
+ */
+
+ if(argc<2) {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+
+ for(int n=1; n < argc; ++n) {
+ if ((string) argv[n] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[n] == "--version") {
+ cerr<<"dnsscan "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ unsigned int counts[256];
+ for(unsigned int n=0 ; n < 256; ++n)
+ counts[n]=0;
+
+ for(int n=1; n < argc; ++n) {
+ PcapPacketReader pr(argv[n]);
+
+ while(pr.getUDPPacket()) {
+ try {
+ MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
+ if(mdp.d_qtype < 256)
+ counts[mdp.d_qtype]++;
+
+ }
+ catch(MOADNSException &e) {
+ cout<<"Error from remote "<<pr.getSource().toString()<<": "<<e.what()<<"\n";
+ // sock.sendTo(string(pr.d_payload, pr.d_payload + pr.d_len), remote);
+ }
+ }
+ }
+ for(unsigned int n=0 ; n < 256; ++n) {
+ if(counts[n])
+ cout << n << "\t" << counts[n] << "\n";
+ }
+
+}
+catch(std::exception& e)
+{
+ cout<<"Fatal: "<<e.what()<<endl;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#define __FAVOR_BSD
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "dnsparser.hh"
+#include "dnsname.hh"
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <map>
+#include <set>
+#include <fstream>
+#include <algorithm>
+#include "anadns.hh"
+#include <boost/program_options.hpp>
+
+#include <boost/logic/tribool.hpp>
+#include "arguments.hh"
+#include "namespaces.hh"
+#include <deque>
+#include "dnsrecords.hh"
+#include "statnode.hh"
+
+namespace po = boost::program_options;
+po::variables_map g_vm;
+
+ArgvMap& arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+StatBag S;
+
+
+
+struct QuestionData
+{
+ QuestionData() : d_qcount(0), d_answercount(0)
+ {
+ d_firstquestiontime.tv_sec=0;
+ }
+
+ int d_qcount;
+ int d_answercount;
+
+ struct pdns_timeval d_firstquestiontime;
+};
+
+typedef map<QuestionIdentifier, QuestionData> statmap_t;
+statmap_t statmap;
+
+unsigned int liveQuestions()
+{
+ unsigned int ret=0;
+ for(statmap_t::value_type& val : statmap) {
+ if(!val.second.d_answercount)
+ ret++;
+ // if(val.second.d_qcount > val.second.d_answercount)
+ // ret+= val.second.d_qcount - val.second.d_answercount;
+ }
+ return ret;
+}
+
+struct LiveCounts
+{
+ unsigned int questions;
+ unsigned int answers;
+ unsigned int outstanding;
+
+ LiveCounts()
+ {
+ questions=answers=outstanding=0;
+ }
+
+ LiveCounts operator-(const LiveCounts& rhs)
+ {
+ LiveCounts ret;
+ ret.questions = questions - rhs.questions;
+ ret.answers = answers - rhs.answers;
+ ret.outstanding = outstanding;
+ return ret;
+ }
+};
+
+void visitor(const StatNode* node, const StatNode::Stat& selfstat, const StatNode::Stat& childstat)
+{
+ // 20% servfails, >100 children, on average less than 2 copies of a query
+ // >100 different subqueries
+ double dups=1.0*childstat.queries/node->children.size();
+ if(dups > 2.0)
+ return;
+ if(1.0*childstat.servfails / childstat.queries > 0.2 && node->children.size()>100) {
+ cout<<node->fullname<<", servfails: "<<childstat.servfails<<", nxdomains: "<<childstat.nxdomains<<", remotes: "<<childstat.remotes.size()<<", children: "<<node->children.size()<<", childstat.queries: "<<childstat.queries;
+ cout<<", dups2: "<<dups<<endl;
+ for(const StatNode::Stat::remotes_t::value_type& rem : childstat.remotes) {
+ cout<<"source: "<<node->fullname<<"\t"<<rem.first.toString()<<"\t"<<rem.second<<endl;
+ }
+ }
+}
+
+int main(int argc, char** argv)
+try
+{
+ po::options_description desc("Allowed options"), hidden, alloptions;
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("version", "print version number")
+ ("rd", po::value<bool>(), "If set to true, only process RD packets, to false only non-RD, unset: both")
+ ("ipv4", po::value<bool>()->default_value(true), "Process IPv4 packets")
+ ("ipv6", po::value<bool>()->default_value(true), "Process IPv6 packets")
+ ("servfail-tree", "Figure out subtrees that generate servfails")
+ ("load-stats,l", po::value<string>()->default_value(""), "if set, emit per-second load statistics (questions, answers, outstanding)")
+ ("write-failures,w", po::value<string>()->default_value(""), "if set, write weird packets to this PCAP file")
+ ("verbose,v", "be verbose");
+
+ hidden.add_options()
+ ("files", po::value<vector<string> >(), "files");
+
+ alloptions.add(desc).add(hidden);
+
+ po::positional_options_description p;
+ p.add("files", -1);
+
+ po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+ po::notify(g_vm);
+
+ vector<string> files;
+ if(g_vm.count("files"))
+ files = g_vm["files"].as<vector<string> >();
+
+ if(g_vm.count("version")) {
+ cerr<<"dnsscope "<<VERSION<<endl;
+ exit(0);
+ }
+
+ if(files.empty() || g_vm.count("help")) {
+ cerr<<"Syntax: dnsscope filename.pcap"<<endl;
+ cout << desc << endl;
+ exit(0);
+ }
+
+ StatNode root;
+
+ bool verbose = g_vm.count("verbose");
+
+ bool haveRDFilter=0, rdFilter=0;
+ if(g_vm.count("rd")) {
+ rdFilter = g_vm["rd"].as<bool>();
+ haveRDFilter=1;
+ cout<<"Filtering on recursion desired="<<rdFilter<<endl;
+ }
+ else
+ cout<<"Warning, looking at both RD and non-RD traffic!"<<endl;
+
+ bool doIPv4 = g_vm["ipv4"].as<bool>();
+ bool doIPv6 = g_vm["ipv6"].as<bool>();
+ bool doServFailTree = g_vm.count("servfail-tree");
+ int dnserrors=0, bogus=0;
+ typedef map<uint32_t,uint32_t> cumul_t;
+ cumul_t cumul;
+ unsigned int untracked=0, errorresult=0, reallylate=0, nonRDQueries=0, queries=0;
+ unsigned int ipv4DNSPackets=0, ipv6DNSPackets=0, fragmented=0, rdNonRAAnswers=0;
+ unsigned int answers=0, nonDNSIP=0, rdFilterMismatch=0;
+ unsigned int dnssecOK=0, edns=0;
+ unsigned int dnssecCD=0, dnssecAD=0;
+ typedef map<uint16_t,uint32_t> rcodes_t;
+ rcodes_t rcodes;
+
+ time_t lowestTime=2000000000, highestTime=0;
+ time_t lastsec=0;
+ LiveCounts lastcounts;
+ set<ComboAddress, ComboAddress::addressOnlyLessThan> requestors, recipients, rdnonra;
+ typedef vector<pair<time_t, LiveCounts> > pcounts_t;
+ pcounts_t pcounts;
+ OPTRecordContent::report();
+ for(unsigned int fno=0; fno < files.size(); ++fno) {
+ PcapPacketReader pr(files[fno]);
+ PcapPacketWriter* pw=0;
+ if(!g_vm["write-failures"].as<string>().empty())
+ pw=new PcapPacketWriter(g_vm["write-failures"].as<string>(), pr);
+
+ EDNSOpts edo;
+ while(pr.getUDPPacket()) {
+
+ if((ntohs(pr.d_udp->uh_dport)==5300 || ntohs(pr.d_udp->uh_sport)==5300 ||
+ ntohs(pr.d_udp->uh_dport)==53 || ntohs(pr.d_udp->uh_sport)==53) &&
+ pr.d_len > 12) {
+ try {
+ if((pr.d_ip->ip_v == 4 && !doIPv4) || (pr.d_ip->ip_v == 6 && !doIPv6))
+ continue;
+ if(pr.d_ip->ip_v == 4) {
+ uint16_t frag = ntohs(pr.d_ip->ip_off);
+ if((frag & IP_MF) || (frag & IP_OFFMASK)) { // more fragments or IS a fragment
+ fragmented++;
+ continue;
+ }
+ }
+ MOADNSParser mdp(false, (const char*)pr.d_payload, pr.d_len);
+ if(haveRDFilter && mdp.d_header.rd != rdFilter) {
+ rdFilterMismatch++;
+ continue;
+ }
+
+ if(!mdp.d_header.qr && getEDNSOpts(mdp, &edo)) {
+ edns++;
+ if(edo.d_Z & EDNSOpts::DNSSECOK)
+ dnssecOK++;
+ if(mdp.d_header.cd)
+ dnssecCD++;
+ if(mdp.d_header.ad)
+ dnssecAD++;
+ }
+
+
+ if(pr.d_ip->ip_v == 4)
+ ++ipv4DNSPackets;
+ else
+ ++ipv6DNSPackets;
+
+ if(pr.d_pheader.ts.tv_sec != lastsec) {
+ LiveCounts lc;
+ if(lastsec) {
+ lc.questions = queries;
+ lc.answers = answers;
+ lc.outstanding = liveQuestions();
+
+ LiveCounts diff = lc - lastcounts;
+ pcounts.push_back(make_pair(pr.d_pheader.ts.tv_sec, diff));
+
+ }
+ lastsec = pr.d_pheader.ts.tv_sec;
+ lastcounts = lc;
+ }
+
+ lowestTime=min((time_t)lowestTime, (time_t)pr.d_pheader.ts.tv_sec);
+ highestTime=max((time_t)highestTime, (time_t)pr.d_pheader.ts.tv_sec);
+
+ string name=mdp.d_qname.toString()+"|"+DNSRecordContent::NumberToType(mdp.d_qtype);
+
+ QuestionIdentifier qi=QuestionIdentifier::create(pr.getSource(), pr.getDest(), mdp);
+
+ if(!mdp.d_header.qr) { // question
+ if(!mdp.d_header.rd)
+ nonRDQueries++;
+ queries++;
+
+ ComboAddress rem = pr.getSource();
+ rem.sin4.sin_port=0;
+ requestors.insert(rem);
+
+ QuestionData& qd=statmap[qi];
+
+ if(!qd.d_firstquestiontime.tv_sec)
+ qd.d_firstquestiontime=pr.d_pheader.ts;
+ qd.d_qcount++;
+ }
+ else { // answer
+ rcodes[mdp.d_header.rcode]++;
+ answers++;
+ if(mdp.d_header.rd && !mdp.d_header.ra) {
+ rdNonRAAnswers++;
+ rdnonra.insert(pr.getDest());
+ }
+
+ if(mdp.d_header.ra) {
+ ComboAddress rem = pr.getDest();
+ rem.sin4.sin_port=0;
+ recipients.insert(rem);
+ }
+
+ QuestionData& qd=statmap[qi];
+
+ if(!qd.d_qcount)
+ untracked++;
+
+ qd.d_answercount++;
+
+ if(qd.d_qcount) {
+ uint32_t usecs= (pr.d_pheader.ts.tv_sec - qd.d_firstquestiontime.tv_sec) * 1000000 +
+ (pr.d_pheader.ts.tv_usec - qd.d_firstquestiontime.tv_usec) ;
+ // cout<<"Took: "<<usecs<<"usec\n";
+ if(usecs<2049000)
+ cumul[usecs]++;
+ else
+ reallylate++;
+
+ if(mdp.d_header.rcode != 0 && mdp.d_header.rcode!=3)
+ errorresult++;
+ ComboAddress rem = pr.getDest();
+ rem.sin4.sin_port=0;
+
+ if(doServFailTree)
+ root.submit(mdp.d_qname, mdp.d_header.rcode, rem);
+ }
+
+ if(!qd.d_qcount || qd.d_qcount == qd.d_answercount)
+ statmap.erase(qi);
+ }
+
+
+ }
+ catch(MOADNSException& mde) {
+ if(verbose)
+ cout<<"error parsing packet: "<<mde.what()<<endl;
+ if(pw)
+ pw->write();
+ dnserrors++;
+ continue;
+ }
+ catch(std::exception& e) {
+ if(verbose)
+ cout<<"error parsing packet: "<<e.what()<<endl;
+
+ if(pw)
+ pw->write();
+ bogus++;
+ continue;
+ }
+ }
+ else { // non-DNS ip
+ nonDNSIP++;
+ }
+ }
+ cout<<"PCAP contained "<<pr.d_correctpackets<<" correct packets, "<<pr.d_runts<<" runts, "<< pr.d_oversized<<" oversize, "<<pr.d_nonetheripudp<<" non-UDP.\n";
+
+ }
+ cout<<"Timespan: "<<(highestTime-lowestTime)/3600.0<<" hours"<<endl;
+
+ cout<<nonDNSIP<<" non-DNS UDP, "<<dnserrors<<" dns decoding errors, "<<bogus<<" bogus packets"<<endl;
+ cout<<"Ignored fragment packets: "<<fragmented<<endl;
+ cout<<"Dropped DNS packets based on recursion-desired filter: "<<rdFilterMismatch<<endl;
+ cout<<"DNS IPv4: "<<ipv4DNSPackets<<" packets, IPv6: "<<ipv6DNSPackets<<" packets"<<endl;
+ cout<<"Questions: "<<queries<<", answers: "<<answers<<endl;
+ unsigned int unanswered=0;
+
+
+ // ofstream openf("openf");
+ for(statmap_t::const_iterator i=statmap.begin(); i!=statmap.end(); ++i) {
+ if(!i->second.d_answercount) {
+ unanswered++;
+ }
+ //openf<< i->first.d_source.toStringWithPort()<<' ' <<i->first.d_dest.toStringWithPort()<<' '<<i->first.d_id<<' '<<i->first.d_qname <<" " <<i->first.d_qtype<< " "<<i->second.d_qcount <<" " <<i->second.d_answercount<<endl;
+ }
+
+ cout<< boost::format("%d (%.02f%% of all) queries did not request recursion") % nonRDQueries % ((nonRDQueries*100.0)/queries) << endl;
+ cout<< rdNonRAAnswers << " answers had recursion desired bit set, but recursion available=0 (for "<<rdnonra.size()<<" remotes)"<<endl;
+ cout<<statmap.size()<<" queries went unanswered, of which "<< statmap.size()-unanswered<<" were answered on exact retransmit"<<endl;
+ cout<<untracked<<" responses could not be matched to questions"<<endl;
+ cout<<edns <<" questions requested EDNS processing, do=1: "<<dnssecOK<<", ad=1: "<<dnssecAD<<", cd=1: "<<dnssecCD<<endl;
+
+ if(answers) {
+ cout<<(boost::format("%1% %|25t|%2%") % "Rcode" % "Count\n");
+ for(rcodes_t::const_iterator i=rcodes.begin(); i!=rcodes.end(); ++i)
+ cout<<(boost::format("%s %|25t|%d %|35t|(%.1f%%)") % RCode::to_s(i->first) % i->second % (i->second*100.0/answers))<<endl;
+ }
+
+ uint32_t sum=0;
+ // ofstream stats("stats");
+ uint32_t totpackets=reallylate;
+ double tottime=0;
+ for(cumul_t::const_iterator i=cumul.begin(); i!=cumul.end(); ++i) {
+ // stats<<i->first<<"\t"<<(sum+=i->second)<<"\n";
+ totpackets+=i->second;
+ tottime+=i->first*i->second;
+ }
+
+ typedef map<uint32_t, bool> done_t;
+ done_t done;
+ done[50];
+ done[100];
+ done[200];
+ done[300];
+ done[400];
+ done[800];
+ done[1000];
+ done[2000];
+ done[4000];
+ done[8000];
+ done[32000];
+ done[64000];
+ done[256000];
+ done[1024000];
+ done[2048000];
+
+ cout.setf(std::ios::fixed);
+ cout.precision(2);
+ sum=0;
+
+ double lastperc=0, perc=0;
+ for(cumul_t::const_iterator i=cumul.begin(); i!=cumul.end(); ++i) {
+ sum+=i->second;
+
+ for(done_t::iterator j=done.begin(); j!=done.end(); ++j)
+ if(!j->second && i->first > j->first) {
+ j->second=true;
+
+ perc=sum*100.0/totpackets;
+ if(j->first < 1024)
+ cout<< perc <<"% of questions answered within " << j->first << " usec (";
+ else
+ cout<< perc <<"% of questions answered within " << j->first/1000.0 << " msec (";
+
+ cout<<perc-lastperc<<"%)\n";
+ lastperc=sum*100.0/totpackets;
+ }
+ }
+ cout<<reallylate<<" responses ("<<reallylate*100.0/answers<<"%) older than 2 seconds"<<endl;
+ if(totpackets)
+ cout<<"Average non-late response time: "<<tottime/totpackets<<" usec"<<endl;
+
+ if(!g_vm["load-stats"].as<string>().empty()) {
+ ofstream load(g_vm["load-stats"].as<string>().c_str());
+ if(!load)
+ throw runtime_error("Error writing load statistics to "+g_vm["load-stats"].as<string>());
+ for(pcounts_t::value_type& val : pcounts) {
+ load<<val.first<<'\t'<<val.second.questions<<'\t'<<val.second.answers<<'\t'<<val.second.outstanding<<'\n';
+ }
+ }
+
+
+ cout<<"Saw questions from "<<requestors.size()<<" distinct remotes, answers to "<<recipients.size()<<endl;
+ ofstream remotes("remotes");
+ for(const ComboAddress& rem : requestors) {
+ remotes<<rem.toString()<<'\n';
+ }
+
+ vector<ComboAddress> diff;
+ set_difference(requestors.begin(), requestors.end(), recipients.begin(), recipients.end(), back_inserter(diff), ComboAddress::addressOnlyLessThan());
+ cout<<"Saw "<<diff.size()<<" unique remotes asking questions, but not getting RA answers"<<endl;
+
+ ofstream ignored("ignored");
+ for(const ComboAddress& rem : diff) {
+ ignored<<rem.toString()<<'\n';
+ }
+ ofstream rdnonrafs("rdnonra");
+ for(const ComboAddress& rem : rdnonra) {
+ rdnonrafs<<rem.toString()<<'\n';
+ }
+
+ if(doServFailTree) {
+ StatNode::Stat node;
+ root.visit(visitor, node);
+ }
+
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#ifndef RECURSOR
+#include "statbag.hh"
+#endif
+#include "iputils.hh"
+
+#include <boost/algorithm/string.hpp>
+#include "dnssecinfra.hh"
+#include "dnsseckeeper.hh"
+#include <openssl/hmac.h>
+#include <openssl/sha.h>
+#include <boost/assign/std/vector.hpp> // for 'operator+=()'
+#include <boost/assign/list_inserter.hpp>
+#include "base64.hh"
+#include "namespaces.hh"
+#ifdef HAVE_P11KIT1
+#include "pkcs11signers.hh"
+#endif
+#include "gss_context.hh"
+#include "misc.hh"
+
+using namespace boost::assign;
+
+shared_ptr<DNSCryptoKeyEngine> DNSCryptoKeyEngine::makeFromISCFile(DNSKEYRecordContent& drc, const char* fname)
+{
+ string sline, isc;
+ FILE *fp=fopen(fname, "r");
+ if(!fp) {
+ throw runtime_error("Unable to read file '"+string(fname)+"' for generating DNS Private Key");
+ }
+
+ while(stringfgets(fp, sline)) {
+ isc += sline;
+ }
+ fclose(fp);
+ shared_ptr<DNSCryptoKeyEngine> dke = makeFromISCString(drc, isc);
+ if(!dke->checkKey()) {
+ throw runtime_error("Invalid DNS Private Key in file '"+string(fname));
+ }
+ return dke;
+}
+
+shared_ptr<DNSCryptoKeyEngine> DNSCryptoKeyEngine::makeFromISCString(DNSKEYRecordContent& drc, const std::string& content)
+{
+ bool pkcs11=false;
+ int algorithm = 0;
+ string sline, key, value, raw;
+ std::istringstream str(content);
+ map<string, string> stormap;
+
+ while(std::getline(str, sline)) {
+ tie(key,value)=splitField(sline, ':');
+ trim(value);
+ if(pdns_iequals(key,"algorithm")) {
+ algorithm = pdns_stou(value);
+ stormap["algorithm"]=std::to_string(algorithm);
+ continue;
+ } else if (pdns_iequals(key,"pin")) {
+ stormap["pin"]=value;
+ continue;
+ } else if (pdns_iequals(key,"engine")) {
+ stormap["engine"]=value;
+ pkcs11=true;
+ continue;
+ } else if (pdns_iequals(key,"slot")) {
+ stormap["slot"]=value;
+ continue;
+ } else if (pdns_iequals(key,"label")) {
+ stormap["label"]=value;
+ continue;
+ }
+ else if(pdns_iequals(key, "Private-key-format"))
+ continue;
+ raw.clear();
+ B64Decode(value, raw);
+ stormap[toLower(key)]=raw;
+ }
+ shared_ptr<DNSCryptoKeyEngine> dpk;
+
+ if (pkcs11) {
+#ifdef HAVE_P11KIT1
+ if (stormap.find("slot") == stormap.end())
+ throw PDNSException("Cannot load PKCS#11 key, no Slot specified");
+ // we need PIN to be at least empty
+ if (stormap.find("pin") == stormap.end()) stormap["pin"] = "";
+ dpk = PKCS11DNSCryptoKeyEngine::maker(algorithm);
+#else
+ throw PDNSException("Cannot load PKCS#11 key without support for it");
+#endif
+ } else {
+ dpk=make(algorithm);
+ }
+ dpk->fromISCMap(drc, stormap);
+ return dpk;
+}
+
+std::string DNSCryptoKeyEngine::convertToISC() const
+{
+ typedef map<string, string> stormap_t;
+ storvector_t stormap = this->convertToISCVector();
+ ostringstream ret;
+ ret<<"Private-key-format: v1.2\n";
+ for(const stormap_t::value_type& value : stormap) {
+ if(value.first != "Algorithm" && value.first != "PIN" &&
+ value.first != "Slot" && value.first != "Engine" &&
+ value.first != "Label")
+ ret<<value.first<<": "<<Base64Encode(value.second)<<"\n";
+ else
+ ret<<value.first<<": "<<value.second<<"\n";
+ }
+ return ret.str();
+}
+
+shared_ptr<DNSCryptoKeyEngine> DNSCryptoKeyEngine::make(unsigned int algo)
+{
+ makers_t& makers = getMakers();
+ makers_t::const_iterator iter = makers.find(algo);
+ if(iter != makers.end())
+ return (iter->second)(algo);
+ else {
+ throw runtime_error("Request to create key object for unknown algorithm number "+std::to_string(algo));
+ }
+}
+
+/**
+ * Returns the supported DNSSEC algorithms with the name of the Crypto Backend used
+ *
+ * @return A vector with pairs of (algorithm-number (int), backend-name (string))
+ */
+vector<pair<uint8_t, string>> DNSCryptoKeyEngine::listAllAlgosWithBackend()
+{
+ vector<pair<uint8_t, string>> ret;
+ for (auto const& value : getMakers()) {
+ shared_ptr<DNSCryptoKeyEngine> dcke(value.second(value.first));
+ ret.push_back(make_pair(value.first, dcke->getName()));
+ }
+ return ret;
+}
+
+void DNSCryptoKeyEngine::report(unsigned int algo, maker_t* maker, bool fallback)
+{
+ getAllMakers()[algo].push_back(maker);
+ if(getMakers().count(algo) && fallback) {
+ return;
+ }
+ getMakers()[algo]=maker;
+}
+
+bool DNSCryptoKeyEngine::testAll()
+{
+ bool ret=true;
+
+ for(const allmakers_t::value_type& value : getAllMakers())
+ {
+ for(maker_t* creator : value.second) {
+
+ for(maker_t* signer : value.second) {
+ // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
+
+ for(maker_t* verifier : value.second) {
+ try {
+ /* pair<unsigned int, unsigned int> res=*/ testMakers(value.first, creator, signer, verifier);
+ }
+ catch(std::exception& e)
+ {
+ cerr<<e.what()<<endl;
+ ret=false;
+ }
+ }
+ }
+ }
+ }
+ return ret;
+}
+
+bool DNSCryptoKeyEngine::testOne(int algo)
+{
+ bool ret=true;
+
+ for(maker_t* creator : getAllMakers()[algo]) {
+
+ for(maker_t* signer : getAllMakers()[algo]) {
+ // multi_map<unsigned int, maker_t*> bestSigner, bestVerifier;
+
+ for(maker_t* verifier : getAllMakers()[algo]) {
+ try {
+ /* pair<unsigned int, unsigned int> res=*/testMakers(algo, creator, signer, verifier);
+ }
+ catch(std::exception& e)
+ {
+ cerr<<e.what()<<endl;
+ ret=false;
+ }
+ }
+ }
+ }
+ return ret;
+}
+// returns times it took to sign and verify
+pair<unsigned int, unsigned int> DNSCryptoKeyEngine::testMakers(unsigned int algo, maker_t* creator, maker_t* signer, maker_t* verifier)
+{
+ shared_ptr<DNSCryptoKeyEngine> dckeCreate(creator(algo));
+ shared_ptr<DNSCryptoKeyEngine> dckeSign(signer(algo));
+ shared_ptr<DNSCryptoKeyEngine> dckeVerify(verifier(algo));
+
+ cerr<<"Testing algorithm "<<algo<<": '"<<dckeCreate->getName()<<"' ->'"<<dckeSign->getName()<<"' -> '"<<dckeVerify->getName()<<"' ";
+ unsigned int bits;
+ if(algo <= 10)
+ bits=1024;
+ else if(algo == 12 || algo == 13 || algo == 15) // ECC-GOST or ECDSAP256SHA256 or ED25519
+ bits=256;
+ else if(algo == 14) // ECDSAP384SHA384
+ bits = 384;
+ else if(algo == 16) // ED448
+ bits = 456;
+ else
+ throw runtime_error("Can't guess key size for algorithm "+std::to_string(algo));
+
+ dckeCreate->create(bits);
+
+ { // FIXME: this block copy/pasted from makeFromISCString
+ DNSKEYRecordContent dkrc;
+ int algorithm = 0;
+ string sline, key, value, raw;
+ std::istringstream str(dckeCreate->convertToISC());
+ map<string, string> stormap;
+
+ while(std::getline(str, sline)) {
+ tie(key,value)=splitField(sline, ':');
+ trim(value);
+ if(pdns_iequals(key,"algorithm")) {
+ algorithm = pdns_stou(value);
+ stormap["algorithm"]=std::to_string(algorithm);
+ continue;
+ } else if (pdns_iequals(key,"pin")) {
+ stormap["pin"]=value;
+ continue;
+ } else if (pdns_iequals(key,"engine")) {
+ stormap["engine"]=value;
+ continue;
+ } else if (pdns_iequals(key,"slot")) {
+ int slot = std::stoi(value);
+ stormap["slot"]=std::to_string(slot);
+ continue;
+ } else if (pdns_iequals(key,"label")) {
+ stormap["label"]=value;
+ continue;
+ }
+ else if(pdns_iequals(key, "Private-key-format"))
+ continue;
+ raw.clear();
+ B64Decode(value, raw);
+ stormap[toLower(key)]=raw;
+ }
+ dckeSign->fromISCMap(dkrc, stormap);
+ if(!dckeSign->checkKey()) {
+ throw runtime_error("Verification of key with creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed");
+ }
+ }
+
+ string message("Hi! How is life?");
+
+ string signature;
+ DTime dt; dt.set();
+ for(unsigned int n = 0; n < 100; ++n)
+ signature = dckeSign->sign(message);
+ unsigned int udiffSign= dt.udiff()/100, udiffVerify;
+
+ dckeVerify->fromPublicKeyString(dckeSign->getPublicKeyString());
+ if (dckeVerify->getPublicKeyString().compare(dckeSign->getPublicKeyString())) {
+ throw runtime_error("Comparison of public key loaded into verifier produced by signer failed");
+ }
+ dt.set();
+ if(dckeVerify->verify(message, signature)) {
+ udiffVerify = dt.udiff();
+ cerr<<"Signature & verify ok, signature "<<udiffSign<<"usec, verify "<<udiffVerify<<"usec"<<endl;
+ }
+ else {
+ throw runtime_error("Verification of creator "+dckeCreate->getName()+" with signer "+dckeSign->getName()+" and verifier "+dckeVerify->getName()+" failed");
+ }
+ return make_pair(udiffSign, udiffVerify);
+}
+
+shared_ptr<DNSCryptoKeyEngine> DNSCryptoKeyEngine::makeFromPublicKeyString(unsigned int algorithm, const std::string& content)
+{
+ shared_ptr<DNSCryptoKeyEngine> dpk=make(algorithm);
+ dpk->fromPublicKeyString(content);
+ return dpk;
+}
+
+
+shared_ptr<DNSCryptoKeyEngine> DNSCryptoKeyEngine::makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw)
+{
+
+ for(makers_t::value_type& val : getMakers())
+ {
+ shared_ptr<DNSCryptoKeyEngine> ret=nullptr;
+ try {
+ ret = val.second(val.first);
+ ret->fromPEMString(drc, raw);
+ return ret;
+ }
+ catch(...)
+ {
+ }
+ }
+ return 0;
+}
+
+
+bool sharedDNSSECCompare(const shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b)
+{
+ return a->serialize(DNSName("."), true, true) < b->serialize(DNSName("."), true, true);
+}
+
+/**
+ * Returns the string that should be hashed to create/verify the RRSIG content
+ *
+ * @param qname DNSName of the RRSIG's owner name.
+ * @param rrc The RRSIGRecordContent we take the Type Covered and
+ * original TTL fields from.
+ * @param signRecords A vector of DNSRecordContent shared_ptr's that are covered
+ * by the RRSIG, where we get the RDATA from.
+ * @param processRRSIGLabels A boolean to trigger processing the RRSIG's "Labels"
+ * field. This is usually only needed for validation
+ * purposes, as the authoritative server correctly
+ * sets qname to the wildcard.
+ */
+string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& signRecords, bool processRRSIGLabels)
+{
+ sort(signRecords.begin(), signRecords.end(), sharedDNSSECCompare);
+
+ string toHash;
+ toHash.append(const_cast<RRSIGRecordContent&>(rrc).serialize(DNSName("."), true, true));
+ toHash.resize(toHash.size() - rrc.d_signature.length()); // chop off the end, don't sign the signature!
+
+ string nameToHash(qname.toDNSStringLC());
+
+ if (processRRSIGLabels) {
+ unsigned int rrsig_labels = rrc.d_labels;
+ unsigned int fqdn_labels = qname.countLabels();
+
+ if (rrsig_labels < fqdn_labels) {
+ DNSName choppedQname(qname);
+ while (choppedQname.countLabels() > rrsig_labels)
+ choppedQname.chopOff();
+ nameToHash = "\x01*" + choppedQname.toDNSStringLC();
+ } else if (rrsig_labels > fqdn_labels) {
+ // The RRSIG Labels field is a lie (or the qname is wrong) and the RRSIG
+ // can never be valid
+ return "";
+ }
+ }
+
+ for(shared_ptr<DNSRecordContent>& add : signRecords) {
+ toHash.append(nameToHash);
+ uint16_t tmp=htons(rrc.d_type);
+ toHash.append((char*)&tmp, 2);
+ tmp=htons(1); // class
+ toHash.append((char*)&tmp, 2);
+ uint32_t ttl=htonl(rrc.d_originalttl);
+ toHash.append((char*)&ttl, 4);
+ // for NSEC signatures, we should not lowercase the rdata section
+ string rdata=add->serialize(DNSName("."), true, (add->getType() == QType::NSEC) ? false : true); // RFC 6840, 5.1
+ tmp=htons(rdata.length());
+ toHash.append((char*)&tmp, 2);
+ toHash.append(rdata);
+ }
+
+ return toHash;
+}
+
+DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, int digest)
+{
+ string toHash;
+ toHash.assign(qname.toDNSStringLC());
+ toHash.append(const_cast<DNSKEYRecordContent&>(drc).serialize(DNSName(), true, true));
+
+ DSRecordContent dsrc;
+ if(digest==1) {
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(5)); // gives us SHA1
+ dsrc.d_digest = dpk->hash(toHash);
+ }
+ else if(digest == 2) {
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(8)); // gives us SHA256
+ dsrc.d_digest = dpk->hash(toHash);
+ }
+ else if(digest == 3) {
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(12)); // gives us GOST
+ dsrc.d_digest = dpk->hash(toHash);
+ }
+ else if(digest == 4) {
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(14)); // gives us ECDSAP384
+ dsrc.d_digest = dpk->hash(toHash);
+ }
+ else
+ throw std::runtime_error("Asked to a DS of unknown digest type " + std::to_string(digest)+"\n");
+
+ dsrc.d_algorithm= drc.d_algorithm;
+ dsrc.d_digesttype=digest;
+ dsrc.d_tag=const_cast<DNSKEYRecordContent&>(drc).getTag();
+
+ return dsrc;
+}
+
+
+DNSKEYRecordContent makeDNSKEYFromDNSCryptoKeyEngine(const std::shared_ptr<DNSCryptoKeyEngine> pk, uint8_t algorithm, uint16_t flags)
+{
+ DNSKEYRecordContent drc;
+
+ drc.d_protocol=3;
+ drc.d_algorithm = algorithm;
+
+ drc.d_flags=flags;
+ drc.d_key = pk->getPublicKeyString();
+
+ return drc;
+}
+
+int countLabels(const std::string& signQName)
+{
+ if(!signQName.empty()) {
+ int count=1;
+ for(string::const_iterator pos = signQName.begin(); pos != signQName.end() ; ++pos)
+ if(*pos == '.' && pos+1 != signQName.end())
+ count++;
+
+ if(boost::starts_with(signQName, "*."))
+ count--;
+ return count;
+ }
+ return 0;
+}
+
+uint32_t getStartOfWeek()
+{
+ uint32_t now = time(0);
+ now -= (now % (7*86400));
+ return now;
+}
+
+string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname)
+{
+ return hashQNameWithSalt(ns3prc.d_salt, ns3prc.d_iterations, qname);
+}
+
+string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname)
+{
+ unsigned int times = iterations;
+ unsigned char hash[20];
+ string toHash(qname.toDNSStringLC());
+
+ for(;;) {
+ toHash.append(salt);
+ SHA1((unsigned char*)toHash.c_str(), toHash.length(), hash);
+ toHash.assign((char*)hash, sizeof(hash));
+ if(!times--)
+ break;
+ }
+ return toHash;
+}
+
+DNSKEYRecordContent DNSSECPrivateKey::getDNSKEY() const
+{
+ return makeDNSKEYFromDNSCryptoKeyEngine(getKey(), d_algorithm, d_flags);
+}
+
+class DEREater
+{
+public:
+ DEREater(const std::string& str) : d_str(str), d_pos(0)
+ {}
+
+ struct eof{};
+
+ uint8_t getByte()
+ {
+ if(d_pos >= d_str.length()) {
+ throw eof();
+ }
+ return (uint8_t) d_str[d_pos++];
+ }
+
+ uint32_t getLength()
+ {
+ uint8_t first = getByte();
+ if(first < 0x80) {
+ return first;
+ }
+ first &= ~0x80;
+
+ uint32_t len=0;
+ for(int n=0; n < first; ++n) {
+ len *= 0x100;
+ len += getByte();
+ }
+ return len;
+ }
+
+ std::string getBytes(unsigned int len)
+ {
+ std::string ret;
+ for(unsigned int n=0; n < len; ++n)
+ ret.append(1, (char)getByte());
+ return ret;
+ }
+
+ std::string::size_type getOffset()
+ {
+ return d_pos;
+ }
+private:
+ const std::string& d_str;
+ std::string::size_type d_pos;
+};
+
+void decodeDERIntegerSequence(const std::string& input, vector<string>& output)
+{
+ output.clear();
+ DEREater de(input);
+ if(de.getByte() != 0x30)
+ throw runtime_error("Not a DER sequence");
+
+ unsigned int seqlen=de.getLength();
+ unsigned int startseq=de.getOffset();
+ unsigned int len;
+ string ret;
+ try {
+ for(;;) {
+ uint8_t kind = de.getByte();
+ if(kind != 0x02)
+ throw runtime_error("DER Sequence contained non-INTEGER component: "+std::to_string(static_cast<unsigned int>(kind)) );
+ len = de.getLength();
+ ret = de.getBytes(len);
+ output.push_back(ret);
+ }
+ }
+ catch(DEREater::eof& eof)
+ {
+ if(de.getOffset() - startseq != seqlen)
+ throw runtime_error("DER Sequence ended before end of data");
+ }
+}
+
+string calculateHMAC(const std::string& key, const std::string& text, TSIGHashEnum hasher) {
+
+ const EVP_MD* md_type;
+ unsigned int outlen;
+ unsigned char hash[EVP_MAX_MD_SIZE];
+ switch(hasher) {
+ case TSIG_MD5:
+ md_type = EVP_md5();
+ break;
+ case TSIG_SHA1:
+ md_type = EVP_sha1();
+ break;
+ case TSIG_SHA224:
+ md_type = EVP_sha224();
+ break;
+ case TSIG_SHA256:
+ md_type = EVP_sha256();
+ break;
+ case TSIG_SHA384:
+ md_type = EVP_sha384();
+ break;
+ case TSIG_SHA512:
+ md_type = EVP_sha512();
+ break;
+ default:
+ throw PDNSException("Unknown hash algorithm requested from calculateHMAC()");
+ }
+
+ unsigned char* out = HMAC(md_type, reinterpret_cast<const unsigned char*>(key.c_str()), key.size(), reinterpret_cast<const unsigned char*>(text.c_str()), text.size(), hash, &outlen);
+ if (out == NULL || outlen == 0) {
+ throw PDNSException("HMAC computation failed");
+ }
+
+ return string((char*) hash, outlen);
+}
+
+bool constantTimeStringEquals(const std::string& a, const std::string& b)
+{
+ if (a.size() != b.size()) {
+ return false;
+ }
+ const size_t size = a.size();
+#if OPENSSL_VERSION_NUMBER >= 0x0090819fL
+ return CRYPTO_memcmp(a.c_str(), b.c_str(), size) == 0;
+#else
+ const volatile unsigned char *_a = (const volatile unsigned char *) a.c_str();
+ const volatile unsigned char *_b = (const volatile unsigned char *) b.c_str();
+ unsigned char res = 0;
+
+ for (size_t idx = 0; idx < size; idx++) {
+ res |= _a[idx] ^ _b[idx];
+ }
+
+ return res == 0;
+#endif
+}
+
+string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigOffset, const DNSName& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset)
+{
+ string message;
+ string packet(opacket);
+
+ packet.resize(tsigOffset); // remove the TSIG record at the end as per RFC2845 3.4.1
+ packet[(dnsHeaderOffset + sizeof(struct dnsheader))-1]--; // Decrease ARCOUNT because we removed the TSIG RR in the previous line.
+
+
+ // Replace the message ID with the original message ID from the TSIG record.
+ // This is needed for forwarded DNS Update as they get a new ID when forwarding (section 6.1 of RFC2136). The TSIG record stores the original ID and the
+ // signature was created with the original ID, so we replace it here to get the originally signed message.
+ // If the message is not forwarded, we simply override it with the same id.
+ uint16_t origID = htons(trc.d_origID);
+ packet.replace(0, 2, (char*)&origID, 2);
+
+ if(!previous.empty()) {
+ uint16_t len = htons(previous.length());
+ message.append((char*)&len, 2);
+ message.append(previous);
+ }
+
+ message.append(packet);
+
+ vector<uint8_t> signVect;
+ DNSPacketWriter dw(signVect, DNSName(), 0);
+ if(!timersonly) {
+ dw.xfrName(keyname, false);
+ dw.xfr16BitInt(QClass::ANY); // class
+ dw.xfr32BitInt(0); // TTL
+ dw.xfrName(trc.d_algoName.makeLowerCase(), false);
+ }
+
+ uint32_t now = trc.d_time;
+ dw.xfr48BitInt(now);
+ dw.xfr16BitInt(trc.d_fudge); // fudge
+ if(!timersonly) {
+ dw.xfr16BitInt(trc.d_eRcode); // extended rcode
+ dw.xfr16BitInt(trc.d_otherData.length()); // length of 'other' data
+ // dw.xfrBlob(trc->d_otherData);
+ }
+ const vector<uint8_t>& signRecord=dw.getRecordBeingWritten();
+ message.append(signRecord.begin(), signRecord.end());
+ return message;
+}
+
+void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly)
+{
+ TSIGHashEnum algo;
+ if (!getTSIGHashEnum(trc->d_algoName, algo)) {
+ throw PDNSException(string("Unsupported TSIG HMAC algorithm ") + trc->d_algoName.toString());
+ }
+
+ string toSign;
+ if(!tsigprevious.empty()) {
+ uint16_t len = htons(tsigprevious.length());
+ toSign.append((char*)&len, 2);
+
+ toSign.append(tsigprevious);
+ }
+ toSign.append(pw.getContent().begin(), pw.getContent().end());
+
+ // now add something that looks a lot like a TSIG record, but isn't
+ vector<uint8_t> signVect;
+ DNSPacketWriter dw(signVect, DNSName(), 0);
+ if(!timersonly) {
+ dw.xfrName(tsigkeyname, false);
+ dw.xfr16BitInt(QClass::ANY); // class
+ dw.xfr32BitInt(0); // TTL
+ dw.xfrName(trc->d_algoName, false);
+ }
+ uint32_t now = trc->d_time;
+ dw.xfr48BitInt(now);
+ dw.xfr16BitInt(trc->d_fudge); // fudge
+
+ if(!timersonly) {
+ dw.xfr16BitInt(trc->d_eRcode); // extended rcode
+ dw.xfr16BitInt(trc->d_otherData.length()); // length of 'other' data
+ // dw.xfrBlob(trc->d_otherData);
+ }
+
+ const vector<uint8_t>& signRecord=dw.getRecordBeingWritten();
+ toSign.append(signRecord.begin(), signRecord.end());
+
+ if (algo == TSIG_GSS) {
+ if (!gss_add_signature(tsigkeyname, toSign, trc->d_mac)) {
+ throw PDNSException(string("Could not add TSIG signature with algorithm 'gss-tsig' and key name '")+tsigkeyname.toString()+string("'"));
+ }
+ } else {
+ trc->d_mac = calculateHMAC(tsigsecret, toSign, algo);
+ // d_trc->d_mac[0]++; // sabotage
+ }
+ pw.startRecord(tsigkeyname, QType::TSIG, 0, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
+ trc->toPacket(pw);
+ pw.commit();
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNSSECINFRA_HH
+#define PDNS_DNSSECINFRA_HH
+
+#include "dnsrecords.hh"
+
+#include <string>
+#include <vector>
+#include <map>
+#include "misc.hh"
+
+class UeberBackend;
+
+// rules of the road: Algorithm must be set in 'make' for each KeyEngine, and will NEVER change!
+
+class DNSCryptoKeyEngine
+{
+ public:
+ explicit DNSCryptoKeyEngine(unsigned int algorithm) : d_algorithm(algorithm) {}
+ virtual ~DNSCryptoKeyEngine() {};
+ virtual string getName() const = 0;
+
+ typedef std::map<std::string, std::string> stormap_t;
+ typedef std::vector<std::pair<std::string, std::string > > storvector_t;
+ virtual void create(unsigned int bits)=0;
+ virtual storvector_t convertToISCVector() const =0;
+ std::string convertToISC() const ;
+ virtual std::string sign(const std::string& msg) const =0;
+ virtual std::string hash(const std::string& msg) const
+ {
+ throw std::runtime_error("hash() function not implemented");
+ return msg;
+ }
+ virtual bool verify(const std::string& msg, const std::string& signature) const =0;
+
+ virtual std::string getPubKeyHash()const =0;
+ virtual std::string getPublicKeyString()const =0;
+ virtual int getBits() const =0;
+
+ virtual void fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap)=0;
+ virtual void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw)
+ {
+ throw std::runtime_error("Can't import from PEM string");
+ }
+ virtual void fromPublicKeyString(const std::string& content) = 0;
+ virtual bool checkKey() const
+ {
+ return true;
+ }
+ static shared_ptr<DNSCryptoKeyEngine> makeFromISCFile(DNSKEYRecordContent& drc, const char* fname);
+ static shared_ptr<DNSCryptoKeyEngine> makeFromISCString(DNSKEYRecordContent& drc, const std::string& content);
+ static shared_ptr<DNSCryptoKeyEngine> makeFromPEMString(DNSKEYRecordContent& drc, const std::string& raw);
+ static shared_ptr<DNSCryptoKeyEngine> makeFromPublicKeyString(unsigned int algorithm, const std::string& raw);
+ static shared_ptr<DNSCryptoKeyEngine> make(unsigned int algorithm);
+
+ typedef shared_ptr<DNSCryptoKeyEngine> maker_t(unsigned int algorithm);
+
+ static void report(unsigned int algorithm, maker_t* maker, bool fallback=false);
+ static std::pair<unsigned int, unsigned int> testMakers(unsigned int algorithm, maker_t* creator, maker_t* signer, maker_t* verifier);
+ static vector<pair<uint8_t, string>> listAllAlgosWithBackend();
+ static bool testAll();
+ static bool testOne(int algo);
+ private:
+
+ typedef std::map<unsigned int, maker_t*> makers_t;
+ typedef std::map<unsigned int, vector<maker_t*> > allmakers_t;
+ static makers_t& getMakers()
+ {
+ static makers_t s_makers;
+ return s_makers;
+ }
+ static allmakers_t& getAllMakers()
+ {
+ static allmakers_t s_allmakers;
+ return s_allmakers;
+ }
+ protected:
+ const unsigned int d_algorithm;
+};
+
+struct DNSSECPrivateKey
+{
+ uint16_t getTag();
+
+ const shared_ptr<DNSCryptoKeyEngine> getKey() const
+ {
+ return d_key;
+ }
+
+ void setKey(const shared_ptr<DNSCryptoKeyEngine> key)
+ {
+ d_key = key;
+ }
+ DNSKEYRecordContent getDNSKEY() const;
+
+ uint16_t d_flags;
+ uint8_t d_algorithm;
+
+private:
+ shared_ptr<DNSCryptoKeyEngine> d_key;
+};
+
+
+
+struct CanonicalCompare: public std::binary_function<string, string, bool>
+{
+ bool operator()(const std::string& a, const std::string& b) {
+ std::vector<std::string> avect, bvect;
+
+ stringtok(avect, a, ".");
+ stringtok(bvect, b, ".");
+
+ reverse(avect.begin(), avect.end());
+ reverse(bvect.begin(), bvect.end());
+
+ return avect < bvect;
+ }
+};
+
+bool sharedDNSSECCompare(const std::shared_ptr<DNSRecordContent>& a, const shared_ptr<DNSRecordContent>& b);
+string getMessageForRRSET(const DNSName& qname, const RRSIGRecordContent& rrc, std::vector<std::shared_ptr<DNSRecordContent> >& signRecords, bool processRRSIGLabels = false);
+
+DSRecordContent makeDSFromDNSKey(const DNSName& qname, const DNSKEYRecordContent& drc, int digest=1);
+
+
+class RSAContext;
+class DNSSECKeeper;
+struct DNSSECPrivateKey;
+
+void fillOutRRSIG(DNSSECPrivateKey& dpk, const DNSName& signQName, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign);
+uint32_t getStartOfWeek();
+void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& signer, const DNSName signQName, const DNSName& wildcardname, uint16_t signQType, uint32_t signTTL, DNSResourceRecord::Place signPlace,
+ vector<shared_ptr<DNSRecordContent> >& toSign, vector<DNSResourceRecord>& outsigned, uint32_t origTTL);
+int getRRSIGsForRRSET(DNSSECKeeper& dk, const DNSName& signer, const DNSName signQName, uint16_t signQType, uint32_t signTTL,
+ vector<shared_ptr<DNSRecordContent> >& toSign, vector<RRSIGRecordContent> &rrc);
+
+string hashQNameWithSalt(const NSEC3PARAMRecordContent& ns3prc, const DNSName& qname);
+string hashQNameWithSalt(const std::string& salt, unsigned int iterations, const DNSName& qname);
+void decodeDERIntegerSequence(const std::string& input, vector<string>& output);
+class DNSPacket;
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const std::set<DNSName>& authMap, vector<DNSResourceRecord>& rrs);
+
+string calculateHMAC(const std::string& key, const std::string& text, TSIGHashEnum hash);
+bool constantTimeStringEquals(const std::string& a, const std::string& b);
+
+string makeTSIGMessageFromTSIGPacket(const string& opacket, unsigned int tsigoffset, const DNSName& keyname, const TSIGRecordContent& trc, const string& previous, bool timersonly, unsigned int dnsHeaderOffset=0);
+void addTSIG(DNSPacketWriter& pw, TSIGRecordContent* trc, const DNSName& tsigkeyname, const string& tsigsecret, const string& tsigprevious, bool timersonly);
+uint64_t signatureCacheSize(const std::string& str);
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <string>
+#include <string.h>
+#include <vector>
+#include <boost/logic/tribool.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include "dnssecinfra.hh"
+#include "dnsrecords.hh"
+#include "ueberbackend.hh"
+
+using namespace ::boost::multi_index;
+
+class DNSSECKeeper : public boost::noncopyable
+{
+public:
+ enum keytype_t { KSK, ZSK, CSK };
+ enum keyalgorithm_t : uint8_t {
+ RSAMD5=1,
+ DH=2,
+ DSA=3,
+ RSASHA1=5,
+ DSANSEC3SHA1=6,
+ RSASHA1NSEC3SHA1=7,
+ RSASHA256=8,
+ RSASHA512=10,
+ ECCGOST=12,
+ ECDSA256=13,
+ ECDSA384=14,
+ ED25519=15,
+ ED448=16
+ };
+
+ struct KeyMetaData
+ {
+ string fname;
+ unsigned int id;
+ bool active;
+ keytype_t keyType;
+ bool hasSEPBit;
+ };
+ typedef std::pair<DNSSECPrivateKey, KeyMetaData> keymeta_t;
+ typedef std::vector<keymeta_t > keyset_t;
+
+ static string keyTypeToString(const keytype_t &keyType)
+ {
+ switch(keyType) {
+ case DNSSECKeeper::KSK:
+ return("KSK");
+ case DNSSECKeeper::ZSK:
+ return("ZSK");
+ case DNSSECKeeper::CSK:
+ return("CSK");
+ default:
+ return("UNKNOWN");
+ }
+ }
+
+ static int shorthand2algorithm(const string &algorithm)
+ {
+ if (!algorithm.compare("rsamd5")) return RSAMD5;
+ if (!algorithm.compare("dh")) return DH;
+ if (!algorithm.compare("dsa")) return DSA;
+ if (!algorithm.compare("rsasha1")) return RSASHA1;
+ if (!algorithm.compare("rsasha256")) return RSASHA256;
+ if (!algorithm.compare("rsasha512")) return RSASHA512;
+ if (!algorithm.compare("ecc-gost")) return ECCGOST;
+ if (!algorithm.compare("gost")) return ECCGOST;
+ if (!algorithm.compare("ecdsa256")) return ECDSA256;
+ if (!algorithm.compare("ecdsa384")) return ECDSA384;
+ if (!algorithm.compare("ed25519")) return ED25519;
+ if (!algorithm.compare("ed448")) return ED448;
+ return -1;
+ }
+
+ static string algorithm2name(uint8_t algo) {
+ switch(algo) {
+ case 0:
+ case 4:
+ case 9:
+ case 11:
+ return "Reserved";
+ case RSAMD5:
+ return "RSAMD5";
+ case DH:
+ return "DH";
+ case DSA:
+ return "DSA";
+ case RSASHA1:
+ return "RSASHA1";
+ case DSANSEC3SHA1:
+ return "DSA-NSEC3-SHA1";
+ case RSASHA1NSEC3SHA1:
+ return "RSASHA1-NSEC3-SHA1";
+ case RSASHA256:
+ return "RSASHA256";
+ case RSASHA512:
+ return "RSASHA512";
+ case ECCGOST:
+ return "ECC-GOST";
+ case ECDSA256:
+ return "ECDSAP256SHA256";
+ case ECDSA384:
+ return "ECDSAP384SHA384";
+ case ED25519:
+ return "ED25519";
+ case ED448:
+ return "ED448";
+ case 252:
+ return "INDIRECT";
+ case 253:
+ return "PRIVATEDNS";
+ case 254:
+ return "PRIVATEOID";
+ default:
+ return "Unallocated/Reserved";
+ }
+ }
+
+private:
+ UeberBackend* d_keymetadb;
+ bool d_ourDB;
+
+public:
+ DNSSECKeeper() : d_keymetadb( new UeberBackend("key-only")), d_ourDB(true)
+ {
+
+ }
+
+ DNSSECKeeper(UeberBackend* db) : d_keymetadb(db), d_ourDB(false)
+ {
+ }
+
+ ~DNSSECKeeper()
+ {
+ if(d_ourDB)
+ delete d_keymetadb;
+ }
+ bool doesDNSSEC();
+ bool isSecuredZone(const DNSName& zone);
+ static uint64_t dbdnssecCacheSizes(const std::string& str);
+ keyset_t getEntryPoints(const DNSName& zname);
+ keyset_t getKeys(const DNSName& zone, bool useCache = true);
+ DNSSECPrivateKey getKeyById(const DNSName& zone, unsigned int id);
+ bool addKey(const DNSName& zname, bool setSEPBit, int algorithm, int bits=0, bool active=true);
+ bool addKey(const DNSName& zname, const DNSSECPrivateKey& dpk, bool active=true);
+ bool removeKey(const DNSName& zname, unsigned int id);
+ bool activateKey(const DNSName& zname, unsigned int id);
+ bool deactivateKey(const DNSName& zname, unsigned int id);
+ bool checkKeys(const DNSName& zname);
+
+ bool getNSEC3PARAM(const DNSName& zname, NSEC3PARAMRecordContent* n3p=0, bool* narrow=0);
+ bool setNSEC3PARAM(const DNSName& zname, const NSEC3PARAMRecordContent& n3p, const bool& narrow=false);
+ bool unsetNSEC3PARAM(const DNSName& zname);
+ void clearAllCaches();
+ void clearCaches(const DNSName& name);
+ bool getPreRRSIGs(UeberBackend& db, const DNSName& signer, const DNSName& qname, const DNSName& wildcardname, const QType& qtype, DNSResourceRecord::Place, vector<DNSResourceRecord>& rrsigs, uint32_t signTTL);
+ bool isPresigned(const DNSName& zname);
+ bool setPresigned(const DNSName& zname);
+ bool unsetPresigned(const DNSName& zname);
+ bool setPublishCDNSKEY(const DNSName& zname);
+ bool unsetPublishCDNSKEY(const DNSName& zname);
+ bool setPublishCDS(const DNSName& zname, const string& digestAlgos);
+ bool unsetPublishCDS(const DNSName& zname);
+
+ bool TSIGGrantsAccess(const DNSName& zone, const DNSName& keyname);
+ bool getTSIGForAccess(const DNSName& zone, const string& master, DNSName* keyname);
+
+ void startTransaction(const DNSName& zone, int zone_id)
+ {
+ (*d_keymetadb->backends.begin())->startTransaction(zone, zone_id);
+ }
+
+ void commitTransaction()
+ {
+ (*d_keymetadb->backends.begin())->commitTransaction();
+ }
+
+ void getFromMeta(const DNSName& zname, const std::string& key, std::string& value);
+ void getSoaEdit(const DNSName& zname, std::string& value);
+private:
+
+
+ struct KeyCacheEntry
+ {
+ typedef vector<DNSSECKeeper::keymeta_t> keys_t;
+
+ uint32_t getTTD() const
+ {
+ return d_ttd;
+ }
+
+ DNSName d_domain;
+ mutable keys_t d_keys;
+ unsigned int d_ttd;
+ };
+
+ struct METACacheEntry
+ {
+ uint32_t getTTD() const
+ {
+ return d_ttd;
+ }
+
+ DNSName d_domain;
+ mutable std::string d_key, d_value;
+ unsigned int d_ttd;
+
+ };
+
+
+ typedef multi_index_container<
+ KeyCacheEntry,
+ indexed_by<
+ ordered_unique<member<KeyCacheEntry, DNSName, &KeyCacheEntry::d_domain> >,
+ sequenced<>
+ >
+ > keycache_t;
+ typedef multi_index_container<
+ METACacheEntry,
+ indexed_by<
+ ordered_unique<
+ composite_key<
+ METACacheEntry,
+ member<METACacheEntry, DNSName, &METACacheEntry::d_domain> ,
+ member<METACacheEntry, std::string, &METACacheEntry::d_key>
+ >, composite_key_compare<std::less<DNSName>, CIStringCompare> >,
+ sequenced<>
+ >
+ > metacache_t;
+
+ void cleanup();
+
+ static keycache_t s_keycache;
+ static metacache_t s_metacache;
+ static pthread_rwlock_t s_metacachelock;
+ static pthread_rwlock_t s_keycachelock;
+ static AtomicCounter s_ops;
+ static time_t s_last_prune;
+};
+
+class DNSPacket;
+uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq);
+// for SOA-EDIT
+uint32_t calculateEditSOA(SOAData sd, const string& kind);
+bool editSOA(DNSSECKeeper& dk, const DNSName& qname, DNSPacket* dp);
+bool editSOARecord(DNSResourceRecord& rr, const string& kind, const DNSName& qname);
+// for SOA-EDIT-DNSUPDATE/API
+uint32_t calculateIncreaseSOA(SOAData sd, const string& increaseKind, const string& editKind);
+bool increaseSOARecord(DNSResourceRecord& rr, const string& increaseKind, const string& editKind);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnssecinfra.hh"
+#include "namespaces.hh"
+
+#include "md5.hh"
+#include "dnsseckeeper.hh"
+#include "dns_random.hh"
+#include "lock.hh"
+#include "arguments.hh"
+#include "statbag.hh"
+extern StatBag S;
+
+/* this is where the RRSIGs begin, keys are retrieved,
+ but the actual signing happens in fillOutRRSIG */
+int getRRSIGsForRRSET(DNSSECKeeper& dk, const DNSName& signer, const DNSName signQName, uint16_t signQType, uint32_t signTTL,
+ vector<shared_ptr<DNSRecordContent> >& toSign, vector<RRSIGRecordContent>& rrcs)
+{
+ if(toSign.empty())
+ return -1;
+ uint32_t startOfWeek = getStartOfWeek();
+ RRSIGRecordContent rrc;
+ rrc.d_type=signQType;
+
+ rrc.d_labels=signQName.countLabels()-signQName.isWildcard();
+ rrc.d_originalttl=signTTL;
+ rrc.d_siginception=startOfWeek - 7*86400; // XXX should come from zone metadata
+ rrc.d_sigexpire=startOfWeek + 14*86400;
+ rrc.d_signer = signer;
+ rrc.d_tag = 0;
+
+ DNSSECKeeper::keyset_t keys = dk.getKeys(signer);
+
+ for(DNSSECKeeper::keyset_t::value_type& keymeta : keys) {
+ if(!keymeta.second.active)
+ continue;
+
+ if((signQType == QType::DNSKEY && keymeta.second.keyType == DNSSECKeeper::ZSK) ||
+ (signQType != QType::DNSKEY && keymeta.second.keyType == DNSSECKeeper::KSK)) {
+ continue;
+ }
+
+ fillOutRRSIG(keymeta.first, signQName, rrc, toSign);
+ rrcs.push_back(rrc);
+ }
+ return 0;
+}
+
+// this is the entrypoint from DNSPacket
+void addSignature(DNSSECKeeper& dk, UeberBackend& db, const DNSName& signer, const DNSName signQName, const DNSName& wildcardname, uint16_t signQType,
+ uint32_t signTTL, DNSResourceRecord::Place signPlace,
+ vector<shared_ptr<DNSRecordContent> >& toSign, vector<DNSResourceRecord>& outsigned, uint32_t origTTL)
+{
+ //cerr<<"Asked to sign '"<<signQName<<"'|"<<DNSRecordContent::NumberToType(signQType)<<", "<<toSign.size()<<" records\n";
+ if(toSign.empty())
+ return;
+ vector<RRSIGRecordContent> rrcs;
+ if(dk.isPresigned(signer)) {
+ //cerr<<"Doing presignatures"<<endl;
+ dk.getPreRRSIGs(db, signer, signQName, wildcardname, QType(signQType), signPlace, outsigned, origTTL); // does it all
+ }
+ else {
+ if(getRRSIGsForRRSET(dk, signer, wildcardname.countLabels() ? wildcardname : signQName, signQType, signTTL, toSign, rrcs) < 0) {
+ // cerr<<"Error signing a record!"<<endl;
+ return;
+ }
+
+ DNSResourceRecord rr;
+ rr.qname=signQName;
+ rr.qtype=QType::RRSIG;
+ if(origTTL)
+ rr.ttl=origTTL;
+ else
+ rr.ttl=signTTL;
+ rr.auth=false;
+ rr.d_place = signPlace;
+ for(RRSIGRecordContent& rrc : rrcs) {
+ rr.content = rrc.getZoneRepresentation();
+ outsigned.push_back(rr);
+ }
+ }
+ toSign.clear();
+}
+
+static pthread_rwlock_t g_signatures_lock = PTHREAD_RWLOCK_INITIALIZER;
+typedef map<pair<string, string>, string> signaturecache_t;
+static signaturecache_t g_signatures;
+static int g_cacheweekno;
+
+AtomicCounter* g_signatureCount;
+
+uint64_t signatureCacheSize(const std::string& str)
+{
+ ReadLock l(&g_signatures_lock);
+ return g_signatures.size();
+}
+
+void fillOutRRSIG(DNSSECPrivateKey& dpk, const DNSName& signQName, RRSIGRecordContent& rrc, vector<shared_ptr<DNSRecordContent> >& toSign)
+{
+ if(!g_signatureCount)
+ g_signatureCount = S.getPointer("signatures");
+
+ DNSKEYRecordContent drc = dpk.getDNSKEY();
+ const std::shared_ptr<DNSCryptoKeyEngine> rc = dpk.getKey();
+ rrc.d_tag = drc.getTag();
+ rrc.d_algorithm = drc.d_algorithm;
+
+ string msg=getMessageForRRSET(signQName, rrc, toSign); // this is what we will hash & sign
+ pair<string, string> lookup(rc->getPubKeyHash(), pdns_md5sum(msg)); // this hash is a memory saving exercise
+
+ bool doCache=1;
+ if(doCache)
+ {
+ ReadLock l(&g_signatures_lock);
+ signaturecache_t::const_iterator iter = g_signatures.find(lookup);
+ if(iter != g_signatures.end()) {
+ rrc.d_signature=iter->second;
+ return;
+ }
+ // else cerr<<"Miss!"<<endl;
+ }
+
+ rrc.d_signature = rc->sign(msg);
+ (*g_signatureCount)++;
+ if(doCache) {
+ /* we add some jitter here so not all your slaves start pruning their caches at the very same millisecond */
+ int weekno = (time(0) - dns_random(3600)) / (86400*7); // we just spent milliseconds doing a signature, microsecond more won't kill us
+ const static int maxcachesize=::arg().asNum("max-signature-cache-entries", INT_MAX);
+
+ WriteLock l(&g_signatures_lock);
+ if(g_cacheweekno < weekno || g_signatures.size() >= (uint) maxcachesize) { // blunt but effective (C) Habbie, mind04
+ L<<Logger::Warning<<"Cleared signature cache."<<endl;
+ g_signatures.clear();
+ g_cacheweekno = weekno;
+ }
+ g_signatures[lookup] = rrc.d_signature;
+ }
+}
+
+static bool rrsigncomp(const DNSResourceRecord& a, const DNSResourceRecord& b)
+{
+ return tie(a.d_place, a.qtype) < tie(b.d_place, b.qtype);
+}
+
+static bool getBestAuthFromSet(const set<DNSName>& authSet, const DNSName& name, DNSName& auth)
+{
+ auth.trimToLabels(0);
+ DNSName sname(name);
+ do {
+ if(authSet.find(sname) != authSet.end()) {
+ auth = sname;
+ return true;
+ }
+ }
+ while(sname.chopOff());
+
+ return false;
+}
+
+void addRRSigs(DNSSECKeeper& dk, UeberBackend& db, const set<DNSName>& authSet, vector<DNSResourceRecord>& rrs)
+{
+ stable_sort(rrs.begin(), rrs.end(), rrsigncomp);
+
+ DNSName signQName, wildcardQName;
+ uint16_t signQType=0;
+ uint32_t signTTL=0;
+ uint32_t origTTL=0;
+
+ DNSResourceRecord::Place signPlace=DNSResourceRecord::ANSWER;
+ vector<shared_ptr<DNSRecordContent> > toSign;
+
+ vector<DNSResourceRecord> signedRecords;
+ signedRecords.reserve(rrs.size()*1.5);
+ // cout<<rrs.size()<<", "<<sizeof(DNSResourceRecord)<<endl;
+ DNSName signer;
+ for(vector<DNSResourceRecord>::const_iterator pos = rrs.begin(); pos != rrs.end(); ++pos) {
+ if(pos != rrs.begin() && (signQType != pos->qtype.getCode() || signQName != pos->qname)) {
+ if(getBestAuthFromSet(authSet, signQName, signer))
+ addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+ }
+ signedRecords.push_back(*pos);
+ signQName= pos->qname.makeLowerCase();
+ if(!pos->wildcardname.empty())
+ wildcardQName = pos->wildcardname.makeLowerCase();
+ else
+ wildcardQName.clear();
+ signQType = pos ->qtype.getCode();
+ if(pos->signttl)
+ signTTL = pos->signttl;
+ else
+ signTTL = pos->ttl;
+ origTTL = pos->ttl;
+ signPlace = pos->d_place;
+ if(pos->auth || pos->qtype.getCode() == QType::DS) {
+ string content = pos->content;
+ if(!pos->content.empty() && pos->qtype.getCode()==QType::TXT && pos->content[0]!='"') {
+ content="\""+pos->content+"\"";
+ }
+ if(pos->content.empty()) // empty contents confuse the MOADNS setup
+ content=".";
+
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(pos->qtype.getCode(), 1, content));
+ toSign.push_back(drc);
+ }
+ }
+ if(getBestAuthFromSet(authSet, signQName, signer))
+ addSignature(dk, db, signer, signQName, wildcardQName, signQType, signTTL, signPlace, toSign, signedRecords, origTTL);
+ rrs.swap(signedRecords);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/accumulators/statistics/median.hpp>
+#include <boost/accumulators/statistics/mean.hpp>
+#include <boost/accumulators/accumulators.hpp>
+
+#include <boost/accumulators/statistics.hpp>
+
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include <netinet/tcp.h>
+#include <boost/array.hpp>
+#include <boost/program_options.hpp>
+
+
+StatBag S;
+namespace po = boost::program_options;
+
+po::variables_map g_vm;
+bool g_verbose;
+bool g_onlyTCP;
+bool g_tcpNoDelay;
+unsigned int g_timeoutMsec;
+AtomicCounter g_networkErrors, g_otherErrors, g_OK, g_truncates, g_authAnswers, g_timeOuts;
+ComboAddress g_dest;
+
+unsigned int makeUsec(const struct timeval& tv)
+{
+ return 1000000*tv.tv_sec + tv.tv_usec;
+}
+
+/* On Linux, run echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle
+ to prevent running out of free TCP ports */
+
+struct BenchQuery
+{
+ BenchQuery(const std::string& qname_, uint16_t qtype_) : qname(qname_), qtype(qtype_), udpUsec(0), tcpUsec(0), answerSecond(0) {}
+ BenchQuery(){}
+ DNSName qname;
+ uint16_t qtype;
+ uint32_t udpUsec, tcpUsec;
+ time_t answerSecond;
+};
+
+void doQuery(BenchQuery* q)
+try
+{
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, q->qname, q->qtype);
+ int res;
+ string reply;
+
+ struct timeval tv, now;
+ gettimeofday(&tv, 0);
+
+ if(!g_onlyTCP) {
+ Socket udpsock(g_dest.sin4.sin_family, SOCK_DGRAM);
+
+ udpsock.sendTo(string((char*)&*packet.begin(), (char*)&*packet.end()), g_dest);
+ ComboAddress origin;
+ res = waitForData(udpsock.getHandle(), 0, 1000 * g_timeoutMsec);
+ if(res < 0)
+ throw NetworkError("Error waiting for response");
+ if(!res) {
+ g_timeOuts++;
+ return;
+ }
+
+ udpsock.recvFrom(reply, origin);
+
+ gettimeofday(&now, 0);
+ q->udpUsec = makeUsec(now - tv);
+ tv=now;
+
+ MOADNSParser mdp(false, reply);
+ if(!mdp.d_header.tc)
+ return;
+ g_truncates++;
+ }
+
+ Socket sock(g_dest.sin4.sin_family, SOCK_STREAM);
+ int tmp=1;
+ if(setsockopt(sock.getHandle(),SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
+ throw runtime_error("Unable to set socket reuse: "+string(strerror(errno)));
+
+ if(g_tcpNoDelay && setsockopt(sock.getHandle(), IPPROTO_TCP, TCP_NODELAY,(char*)&tmp,sizeof tmp)<0)
+ throw runtime_error("Unable to set socket no delay: "+string(strerror(errno)));
+
+ sock.connect(g_dest);
+ uint16_t len = htons(packet.size());
+ string tcppacket((char*)& len, 2);
+ tcppacket.append((char*)&*packet.begin(), (char*)&*packet.end());
+
+ sock.writen(tcppacket);
+
+ res = waitForData(sock.getHandle(), 0, 1000 * g_timeoutMsec);
+ if(res < 0)
+ throw NetworkError("Error waiting for response");
+ if(!res) {
+ g_timeOuts++;
+ return;
+ }
+
+ if(sock.read((char *) &len, 2) != 2)
+ throw PDNSException("tcp read failed");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=sock.read(creply+n, len-n);
+ if(numread<0)
+ throw PDNSException("tcp read failed");
+ n+=numread;
+ }
+
+ reply=string(creply, len);
+ delete[] creply;
+
+ gettimeofday(&now, 0);
+ q->tcpUsec = makeUsec(now - tv);
+ q->answerSecond = now.tv_sec;
+
+ MOADNSParser mdp(false, reply);
+ // cout<<"Had correct TCP/IP response, "<<mdp.d_answers.size()<<" answers, aabit="<<mdp.d_header.aa<<endl;
+ if(mdp.d_header.aa)
+ g_authAnswers++;
+ g_OK++;
+}
+catch(NetworkError& ne)
+{
+ cerr<<"Network error: "<<ne.what()<<endl;
+ g_networkErrors++;
+}
+catch(...)
+{
+ g_otherErrors++;
+}
+
+/* read queries from stdin, put in vector
+ launch n worker threads, each picks a query using AtomicCounter
+ If a worker reaches the end of its queue, it stops */
+
+AtomicCounter g_pos;
+
+vector<BenchQuery> g_queries;
+
+static void* worker(void*)
+{
+ for(;;) {
+ unsigned int pos = g_pos++;
+ if(pos >= g_queries.size())
+ break;
+
+ doQuery(&g_queries[pos]); // this is safe as long as nobody *inserts* to g_queries
+ }
+ return 0;
+}
+
+void usage(po::options_description &desc) {
+ cerr<<"Syntax: dnstcpbench REMOTE [PORT] < QUERIES"<<endl;
+ cerr<<"Where QUERIES is one query per line, format: qname qtype, just 1 space"<<endl;
+ cerr<<desc<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ po::options_description desc("Allowed options"), hidden, alloptions;
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("version", "print version number")
+ ("verbose,v", "be verbose")
+ ("udp-first,u", "try UDP first")
+ ("file,f", po::value<string>(), "source file - if not specified, defaults to stdin")
+ ("tcp-no-delay", po::value<bool>()->default_value(true), "use TCP_NODELAY socket option")
+ ("timeout-msec", po::value<int>()->default_value(10), "wait for this amount of milliseconds for an answer")
+ ("workers", po::value<int>()->default_value(100), "number of parallel workers");
+
+ hidden.add_options()
+ ("remote-host", po::value<string>(), "remote-host")
+ ("remote-port", po::value<int>()->default_value(53), "remote-port");
+ alloptions.add(desc).add(hidden);
+
+ po::positional_options_description p;
+ p.add("remote-host", 1);
+ p.add("remote-port", 1);
+
+ po::store(po::command_line_parser(argc, argv).options(alloptions).positional(p).run(), g_vm);
+ po::notify(g_vm);
+
+ if(g_vm.count("version")) {
+ cerr<<"dnstcpbench "<<VERSION<<endl;
+ exit(EXIT_SUCCESS);
+ }
+
+ if(g_vm.count("help")) {
+ usage(desc);
+ exit(EXIT_SUCCESS);
+ }
+ g_tcpNoDelay = g_vm["tcp-no-delay"].as<bool>();
+
+ g_onlyTCP = !g_vm.count("udp-first");
+ g_verbose = g_vm.count("verbose");
+ g_timeoutMsec = g_vm["timeout-msec"].as<int>();
+
+ reportAllTypes();
+
+ if(g_vm["remote-host"].empty()) {
+ usage(desc);
+ exit(EXIT_FAILURE);
+ }
+
+ g_dest = ComboAddress(g_vm["remote-host"].as<string>().c_str(), g_vm["remote-port"].as<int>());
+
+ unsigned int numworkers=g_vm["workers"].as<int>();
+
+ if(g_verbose) {
+ cout<<"Sending queries to: "<<g_dest.toStringWithPort()<<endl;
+ cout<<"Attempting UDP first: " << (g_onlyTCP ? "no" : "yes") <<endl;
+ cout<<"Timeout: "<< g_timeoutMsec<<"msec"<<endl;
+ cout << "Using TCP_NODELAY: "<<g_tcpNoDelay<<endl;
+ }
+
+
+ pthread_t workers[numworkers];
+
+ FILE* fp;
+ if(!g_vm.count("file"))
+ fp=fdopen(0, "r");
+ else {
+ fp=fopen(g_vm["file"].as<string>().c_str(), "r");
+ if(!fp)
+ unixDie("Unable to open "+g_vm["file"].as<string>()+" for input");
+ }
+ pair<string, string> q;
+ string line;
+ while(stringfgets(fp, line)) {
+ trim_right(line);
+ q=splitField(line, ' ');
+ g_queries.push_back(BenchQuery(q.first, DNSRecordContent::TypeToNumber(q.second)));
+ }
+ fclose(fp);
+
+ for(unsigned int n = 0; n < numworkers; ++n) {
+ pthread_create(&workers[n], 0, worker, 0);
+ }
+ for(unsigned int n = 0; n < numworkers; ++n) {
+ void* status;
+ pthread_join(workers[n], &status);
+ }
+
+ using namespace boost::accumulators;
+ typedef accumulator_set<
+ double
+ , stats<boost::accumulators::tag::median(with_p_square_quantile),
+ boost::accumulators::tag::mean(immediate)
+ >
+ > acc_t;
+
+ acc_t udpspeeds, tcpspeeds, qps;
+
+ typedef map<time_t, uint32_t> counts_t;
+ counts_t counts;
+
+ for(const BenchQuery& bq : g_queries) {
+ counts[bq.answerSecond]++;
+ udpspeeds(bq.udpUsec);
+ tcpspeeds(bq.tcpUsec);
+ }
+
+ for(const counts_t::value_type& val : counts) {
+ qps(val.second);
+ }
+
+ cout<<"Average qps: "<<mean(qps)<<", median qps: "<<median(qps)<<endl;
+ cout<<"Average UDP latency: "<<mean(udpspeeds)<<"usec, median: "<<median(udpspeeds)<<"usec"<<endl;
+ cout<<"Average TCP latency: "<<mean(tcpspeeds)<<"usec, median: "<<median(tcpspeeds)<<"usec"<<endl;
+
+ cout<<"OK: "<<g_OK<<", network errors: "<<g_networkErrors<<", other errors: "<<g_otherErrors<<endl;
+ cout<<"Timeouts: "<<g_timeOuts<<endl;
+ cout<<"Truncateds: "<<g_truncates<<", auth answers: "<<g_authAnswers<<endl;
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+/** two modes:
+
+anonymizing and stripping tcpdumps of irrelevant traffic, so operators can send non-privacy violating dumps
+for analysis.
+
+algorithm:
+
+read a packet, check if it has the QR bit set.
+
+If the question has the response bit set, obfuscate the destination IP address
+otherwise, obfuscate the response IP address
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "statbag.hh"
+#include "dnspcap.hh"
+#include "iputils.hh"
+
+#include "namespaces.hh"
+
+StatBag S;
+
+class IPObfuscator
+{
+public:
+ IPObfuscator() : d_romap(d_ipmap), d_ro6map(d_ip6map), d_counter(0)
+ {
+ }
+
+ uint32_t obf4(uint32_t orig)
+ {
+ if(d_romap.count(orig))
+ return d_ipmap[orig];
+ else {
+ return d_ipmap[orig]=d_counter++;
+ }
+ }
+
+ struct in6_addr obf6(const struct in6_addr& orig)
+ {
+ uint32_t val;
+ if(d_ro6map.count(orig))
+ val=d_ip6map[orig];
+ else {
+ val=d_ip6map[orig]=d_counter++;
+ }
+ struct in6_addr ret;
+
+ val=htonl(val);
+ memset(&ret, 0, sizeof(ret));
+ memcpy(((char*)&ret)+12, &val, 4);
+ return ret;
+ }
+
+private:
+ map<uint32_t, uint32_t> d_ipmap;
+ const decltype(d_ipmap)& d_romap;
+
+ struct cmp {
+ bool operator()(const struct in6_addr&a , const struct in6_addr&b) const
+ {
+ return memcmp(&a, &b, sizeof(a)) < 0;
+ }
+ };
+ // For IPv6 addresses
+ map<struct in6_addr, uint32_t, cmp> d_ip6map;
+ const decltype(d_ip6map)& d_ro6map;
+
+ // The counter that we'll convert to an IP address
+ uint32_t d_counter;
+};
+
+void usage() {
+ cerr<<"Syntax: dnswasher INFILE1 [INFILE2..] OUTFILE"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ for (int i = 1; i < argc; i++) {
+ if ((string) argv[i] == "--help") {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+
+ if ((string) argv[i] == "--version") {
+ cerr<<"dnswasher "<<VERSION<<endl;
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ if(argc < 3) {
+ usage();
+ exit(1);
+ }
+
+ PcapPacketWriter pw(argv[argc-1]);
+ IPObfuscator ipo;
+ // 0 1 2 3 - argc == 4
+ // dnswasher in1 in2 out
+ for(int n=1; n < argc -1; ++n) {
+ PcapPacketReader pr(argv[n]);
+ pw.setPPR(pr);
+
+ while(pr.getUDPPacket()) {
+ if(ntohs(pr.d_udp->uh_dport)==53 || (ntohs(pr.d_udp->uh_sport)==53 && pr.d_len > sizeof(dnsheader))) {
+ dnsheader* dh=(dnsheader*)pr.d_payload;
+
+ if (pr.d_ip->ip_v == 4){
+ uint32_t *src=(uint32_t*)&pr.d_ip->ip_src;
+ uint32_t *dst=(uint32_t*)&pr.d_ip->ip_dst;
+
+ if(dh->qr)
+ *dst=htonl(ipo.obf4(*dst));
+ else
+ *src=htonl(ipo.obf4(*src));
+
+ pr.d_ip->ip_sum=0;
+ } else if (pr.d_ip->ip_v == 6) {
+ auto src=&pr.d_ip6->ip6_src;
+ auto dst=&pr.d_ip6->ip6_dst;
+
+ if(dh->qr)
+ *dst=ipo.obf6(*dst);
+ else
+ *src=ipo.obf6(*src);
+ }
+ pw.write();
+ }
+ }
+ cerr<<"Saw "<<pr.d_correctpackets<<" correct packets, "<<pr.d_runts<<" runts, "<< pr.d_oversized<<" oversize, "<<
+ pr.d_nonetheripudp<<" unknown encaps"<<endl;
+ }
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnswriter.hh"
+#include "misc.hh"
+#include "dnsparser.hh"
+
+#include <limits.h>
+
+DNSPacketWriter::DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t qtype, uint16_t qclass, uint8_t opcode)
+ : d_pos(0), d_content(content), d_qname(qname), d_canonic(false), d_lowerCase(false)
+{
+ d_content.clear();
+ dnsheader dnsheader;
+
+ memset(&dnsheader, 0, sizeof(dnsheader));
+ dnsheader.id=0;
+ dnsheader.qdcount=htons(1);
+ dnsheader.opcode=opcode;
+
+ const uint8_t* ptr=(const uint8_t*)&dnsheader;
+ uint32_t len=d_content.size();
+ d_content.resize(len + sizeof(dnsheader));
+ uint8_t* dptr=(&*d_content.begin()) + len;
+
+ memcpy(dptr, ptr, sizeof(dnsheader));
+ d_stuff=0;
+
+ xfrName(qname, false);
+
+ len=d_content.size();
+ d_content.resize(len + d_record.size() + 4);
+
+ ptr=&*d_record.begin();
+ dptr=(&*d_content.begin()) + len;
+
+ memcpy(dptr, ptr, d_record.size());
+
+ len+=d_record.size();
+ d_record.clear();
+
+ qtype=htons(qtype);
+ qclass=htons(qclass);
+
+ vector<uint8_t>::iterator i=d_content.begin()+len; // this works around a gcc 3.4 bug
+ memcpy(&*i, &qtype, 2);
+ i+=2;
+ memcpy(&*i, &qclass, 2);
+
+ d_stuff=0xffff;
+ d_labelmap.reserve(16);
+ d_truncatemarker=d_content.size();
+ d_sor = 0;
+ d_rollbackmarker = 0;
+ d_recordttl = 0;
+ d_recordqtype = 0;
+ d_recordqclass = QClass::IN;
+ d_recordplace = DNSResourceRecord::ANSWER;
+}
+
+dnsheader* DNSPacketWriter::getHeader()
+{
+ return reinterpret_cast<dnsheader*>(&*d_content.begin());
+}
+
+void DNSPacketWriter::startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl, uint16_t qclass, DNSResourceRecord::Place place, bool compress)
+{
+ if(!d_record.empty())
+ commit();
+
+ d_recordqname=name;
+ d_recordqtype=qtype;
+ d_recordqclass=qclass;
+ d_recordttl=ttl;
+ d_recordplace=place;
+
+ d_stuff = 0;
+ d_rollbackmarker=d_content.size();
+
+ if(compress && d_recordqname.countLabels() && d_qname==d_recordqname) { // don't do the whole label compression thing if we *know* we can get away with "see question" - except when compressing the root
+ static unsigned char marker[2]={0xc0, 0x0c};
+ d_content.insert(d_content.end(), (const char *) &marker[0], (const char *) &marker[2]);
+ }
+ else {
+ xfrName(d_recordqname, compress);
+ d_content.insert(d_content.end(), d_record.begin(), d_record.end());
+ d_record.clear();
+ }
+
+ d_stuff = sizeof(dnsrecordheader); // this is needed to get compressed label offsets right, the dnsrecordheader will be interspersed
+ d_sor=d_content.size() + d_stuff; // start of real record
+}
+
+void DNSPacketWriter::addOpt(uint16_t udpsize, int extRCode, int Z, const vector<pair<uint16_t,string> >& options)
+{
+ uint32_t ttl=0;
+
+ EDNS0Record stuff;
+
+ stuff.extRCode=extRCode;
+ stuff.version=0;
+ stuff.Z=htons(Z);
+
+ static_assert(sizeof(EDNS0Record) == sizeof(ttl), "sizeof(EDNS0Record) must match sizeof(ttl)");
+ memcpy(&ttl, &stuff, sizeof(stuff));
+
+ ttl=ntohl(ttl); // will be reversed later on
+
+ startRecord(DNSName("."), QType::OPT, ttl, udpsize, DNSResourceRecord::ADDITIONAL, false);
+ for(optvect_t::const_iterator iter = options.begin(); iter != options.end(); ++iter) {
+ xfr16BitInt(iter->first);
+ xfr16BitInt(iter->second.length());
+ xfrBlob(iter->second);
+ }
+}
+
+void DNSPacketWriter::xfr48BitInt(uint64_t val)
+{
+ unsigned char bytes[6];
+ uint16_t theLeft = htons((val >> 32)&0xffffU);
+ uint32_t theRight = htonl(val & 0xffffffffU);
+ memcpy(bytes, (void*)&theLeft, sizeof(theLeft));
+ memcpy(bytes+2, (void*)&theRight, sizeof(theRight));
+
+ d_record.insert(d_record.end(), bytes, bytes + sizeof(bytes));
+}
+
+
+void DNSPacketWriter::xfr32BitInt(uint32_t val)
+{
+ int rval=htonl(val);
+ uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
+ d_record.insert(d_record.end(), ptr, ptr+4);
+}
+
+void DNSPacketWriter::xfr16BitInt(uint16_t val)
+{
+ uint16_t rval=htons(val);
+ uint8_t* ptr=reinterpret_cast<uint8_t*>(&rval);
+ d_record.insert(d_record.end(), ptr, ptr+2);
+}
+
+void DNSPacketWriter::xfr8BitInt(uint8_t val)
+{
+ d_record.push_back(val);
+}
+
+
+/* input:
+ if lenField is true
+ "" -> 0
+ "blah" -> 4blah
+ "blah" "blah" -> output 4blah4blah
+ "verylongstringlongerthan256....characters" \xffverylongstring\x23characters (autosplit)
+ "blah\"blah" -> 9blah"blah
+ "blah\97" -> 5blahb
+
+ if lenField is false
+ "blah" -> blah
+ "blah\"blah" -> blah"blah
+ */
+void DNSPacketWriter::xfrText(const string& text, bool, bool lenField)
+{
+ if(text.empty()) {
+ d_record.push_back(0);
+ return;
+ }
+ vector<string> segments = segmentDNSText(text);
+ for(const string& str : segments) {
+ if(lenField)
+ d_record.push_back(str.length());
+ d_record.insert(d_record.end(), str.c_str(), str.c_str() + str.length());
+ }
+}
+
+void DNSPacketWriter::xfrUnquotedText(const string& text, bool lenField)
+{
+ if(text.empty()) {
+ d_record.push_back(0);
+ return;
+ }
+ if(lenField)
+ d_record.push_back(text.length());
+ d_record.insert(d_record.end(), text.c_str(), text.c_str() + text.length());
+}
+
+/* FIXME400: check that this beats a map */
+DNSPacketWriter::lmap_t::iterator find(DNSPacketWriter::lmap_t& nmap, const DNSName& name)
+{
+ DNSPacketWriter::lmap_t::iterator ret;
+ for(ret=nmap.begin(); ret != nmap.end(); ++ret)
+ if(ret->first == name)
+ break;
+ return ret;
+}
+
+// //! tokenize a label into parts, the parts describe a begin offset and an end offset
+// bool labeltokUnescape(labelparts_t& parts, const string& label)
+// {
+// string::size_type epos = label.size(), lpos(0), pos;
+// bool unescapedSomething = false;
+// const char* ptr=label.c_str();
+
+// parts.clear();
+
+// for(pos = 0 ; pos < epos; ++pos) {
+// if(ptr[pos]=='\\') {
+// pos++;
+// unescapedSomething = true;
+// continue;
+// }
+// if(ptr[pos]=='.') {
+// parts.push_back(make_pair(lpos, pos));
+// lpos=pos+1;
+// }
+// }
+
+// if(lpos < pos)
+// parts.push_back(make_pair(lpos, pos));
+// return unescapedSomething;
+// }
+
+// this is the absolute hottest function in the pdns recursor
+void DNSPacketWriter::xfrName(const DNSName& name, bool compress, bool)
+{
+ //cerr<<"xfrName: name=["<<name.toString()<<"] compress="<<compress<<endl;
+ // string label = d_lowerCase ? toLower(Label) : Label;
+ // FIXME400: we ignore d_lowerCase for now
+ // cerr<<"xfrName writing ["<<name.toString()<<"]"<<endl;
+ std::vector<std::string> parts = name.getRawLabels();
+ // labelparts_t parts;
+ // cerr<<"labelcount: "<<parts.size()<<endl;
+
+ if(d_canonic)
+ compress=false;
+
+ if(!parts.size()) { // otherwise we encode '..'
+ d_record.push_back(0);
+ return;
+ }
+
+ // d_stuff is amount of stuff that is yet to be written out - the dnsrecordheader for example
+ unsigned int pos=d_content.size() + d_record.size() + d_stuff;
+ // bool deDot = labellen && (label[labellen-1]=='.'); // make sure we don't store trailing dots in the labelmap
+
+ unsigned int startRecordSize=d_record.size();
+ unsigned int startPos;
+
+ DNSName towrite = name;
+ /* FIXME400: if we are not compressing, there is no reason to work per-label */
+ for(auto &label: parts) {
+ if(d_lowerCase) label=toLower(label);
+ //cerr<<"xfrName labelpart ["<<label<<"], left to write ["<<towrite.toString()<<"]"<<endl;
+
+ auto li=d_labelmap.end();
+ // see if we've written out this domain before
+ //cerr<<"compress="<<compress<<", searching? for compression pointer to '"<<towrite.toString()<<"', "<<d_labelmap.size()<<" cmp-records"<<endl;
+ if(compress && (li=find(d_labelmap, towrite))!=d_labelmap.end()) {
+ //cerr<<"doing compression, my label=["<<label<<"] found match ["<<li->first.toString()<<"]"<<endl;
+ //cerr<<"\tFound a compression pointer to '"<<towrite.toString()<<"': "<<li->second<<endl;
+ if (d_record.size() - startRecordSize + label.size() > 253) // chopped does not include a length octet for the first label and the root label
+ throw MOADNSException("DNSPacketWriter::xfrName() found overly large (compressed) name");
+ uint16_t offset=li->second;
+ offset|=0xc000;
+ d_record.push_back((char)(offset >> 8));
+ d_record.push_back((char)(offset & 0xff));
+ goto out; // skip trailing 0 in case of compression
+ }
+
+ if(li==d_labelmap.end() && pos< 16384) {
+ // cerr<<"\tStoring a compression pointer to '"<<chopped<<"': "<<pos<<endl;
+ d_labelmap.push_back(make_pair(towrite, pos)); // if untrue, we need to count - also, don't store offsets > 16384, won't work
+ //cerr<<"stored ["<<towrite.toString()<<"] at pos "<<pos<<endl;
+ }
+
+ startPos=pos;
+
+ char labelsize=label.size();
+ //cerr<<"labelsize = "<<int(labelsize)<<" for label ["<<label<<"]"<<endl;
+ d_record.push_back(labelsize);
+ unsigned int len=d_record.size();
+ d_record.resize(len + labelsize);
+ memcpy(((&*d_record.begin()) + len), label.c_str(), labelsize); // FIXME400 do not want memcpy
+ pos+=labelsize+1;
+
+ if(pos - startPos == 1)
+ throw MOADNSException("DNSPacketWriter::xfrName() found empty label in the middle of name");
+ if(pos - startPos > 64)
+ throw MOADNSException("DNSPacketWriter::xfrName() found overly large label in name");
+ towrite.chopOff(); /* FIXME400: iterating the label vector while keeping this chopoff in sync is a hack */
+ }
+ d_record.push_back(0); // insert root label
+
+ if (d_record.size() - startRecordSize > 255)
+ throw MOADNSException("DNSPacketWriter::xfrName() found overly large name");
+
+ out:;
+}
+
+void DNSPacketWriter::xfrBlob(const string& blob, int )
+{
+ const uint8_t* ptr=reinterpret_cast<const uint8_t*>(blob.c_str());
+ d_record.insert(d_record.end(), ptr, ptr+blob.size());
+}
+
+void DNSPacketWriter::xfrBlobNoSpaces(const string& blob, int )
+{
+ xfrBlob(blob);
+}
+
+void DNSPacketWriter::xfrHexBlob(const string& blob, bool keepReading)
+{
+ xfrBlob(blob);
+}
+
+void DNSPacketWriter::getRecords(string& records)
+{
+ records.assign(d_content.begin() + d_sor, d_content.end());
+}
+
+uint32_t DNSPacketWriter::size()
+{
+ return d_content.size() + d_stuff + d_record.size();
+}
+
+void DNSPacketWriter::rollback()
+{
+ d_content.resize(d_rollbackmarker);
+ d_record.clear();
+ d_stuff=0;
+}
+
+void DNSPacketWriter::truncate()
+{
+ d_content.resize(d_truncatemarker);
+ d_record.clear();
+ d_stuff=0;
+ dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
+ dh->ancount = dh->nscount = dh->arcount = 0;
+}
+
+void DNSPacketWriter::commit()
+{
+ if(d_stuff==0xffff && (d_content.size()!=d_sor || !d_record.empty()))
+ throw MOADNSException("DNSPacketWriter::commit() called without startRecord ever having been called, but a record was added");
+ // build dnsrecordheader
+ struct dnsrecordheader drh;
+ drh.d_type=htons(d_recordqtype);
+ drh.d_class=htons(d_recordqclass);
+ drh.d_ttl=htonl(d_recordttl);
+ drh.d_clen=htons(d_record.size());
+
+ // and write out the header
+ const uint8_t* ptr=(const uint8_t*)&drh;
+ d_content.insert(d_content.end(), ptr, ptr+sizeof(drh));
+
+ d_stuff=0;
+
+ // write out pending d_record
+ d_content.insert(d_content.end(), d_record.begin(), d_record.end());
+
+ dnsheader* dh=reinterpret_cast<dnsheader*>( &*d_content.begin());
+ switch(d_recordplace) {
+ case DNSResourceRecord::QUESTION:
+ dh->qdcount = htons(ntohs(dh->qdcount) + 1);
+ break;
+ case DNSResourceRecord::ANSWER:
+ dh->ancount = htons(ntohs(dh->ancount) + 1);
+ break;
+ case DNSResourceRecord::AUTHORITY:
+ dh->nscount = htons(ntohs(dh->nscount) + 1);
+ break;
+ case DNSResourceRecord::ADDITIONAL:
+ dh->arcount = htons(ntohs(dh->arcount) + 1);
+ break;
+ }
+
+ d_record.clear(); // clear d_record, ready for next record
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DNSWRITER_HH
+#define PDNS_DNSWRITER_HH
+
+#include <string>
+#include <vector>
+#include <map>
+#include "dns.hh"
+#include "dnsname.hh"
+#include "namespaces.hh"
+#include <arpa/inet.h>
+/** this class can be used to write DNS packets. It knows about DNS in the sense that it makes
+ the packet header and record headers.
+
+ The model is:
+
+ packetheader (recordheader recordcontent)*
+
+ The packetheader needs to be updated with the amount of packets of each kind (answer, auth, additional)
+
+ Each recordheader contains the length of a dns record.
+
+ Calling convention:
+
+ vector<uint8_t> content;
+ DNSPacketWriter dpw(content, const string& qname, uint16_t qtype, uint16_t qclass=QClass:IN); // sets the question
+ dpw.startrecord("this.is.an.ip.address.", ns_t_a); // does nothing, except store qname and qtype
+ dpw.xfr32BitInt(0x01020304); // adds 4 bytes (0x01020304) to the record buffer
+ dpw.startrecord("this.is.an.ip.address.", ns_t_a); // aha! writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer, which gets emptied
+ // new qname and qtype are stored
+ dpw.xfr32BitInt(0x04030201); // adds 4 bytes (0x04030201) to the record buffer
+ dpw.commit(); // writes out dnsrecord header containing qname and qtype and length 4, plus the recordbuffer
+
+ // content now contains the ready packet, with 1 question and 2 answers
+
+*/
+
+class DNSPacketWriter : public boost::noncopyable
+{
+
+public:
+ typedef vector<pair<DNSName, uint16_t> > lmap_t;
+
+ //! Start a DNS Packet in the vector passed, with question qname, qtype and qclass
+ DNSPacketWriter(vector<uint8_t>& content, const DNSName& qname, uint16_t qtype, uint16_t qclass=QClass::IN, uint8_t opcode=0);
+
+ /** Start a new DNS record within this packet for namq, qtype, ttl, class and in the requested place. Note that packets can only be written in natural order -
+ ANSWER, AUTHORITY, ADDITIONAL */
+ void startRecord(const DNSName& name, uint16_t qtype, uint32_t ttl=3600, uint16_t qclass=QClass::IN, DNSResourceRecord::Place place=DNSResourceRecord::ANSWER, bool compress=true);
+
+ /** Shorthand way to add an Opt-record, for example for EDNS0 purposes */
+ typedef vector<pair<uint16_t,std::string> > optvect_t;
+ void addOpt(uint16_t udpsize, int extRCode, int Z, const optvect_t& options=optvect_t());
+
+ /** needs to be called after the last record is added, but can be called again and again later on. Is called internally by startRecord too.
+ The content of the vector<> passed to the constructor is inconsistent until commit is called.
+ */
+ void commit();
+
+ uint32_t size(); // needs to be 32 bit because otherwise we don't see the wrap coming when it happened!
+
+ /** Should the packet have grown too big for the writer's liking, rollback removes the record currently being written */
+ void rollback();
+
+ /** Discard all content except the question section */
+ void truncate();
+
+ void xfr48BitInt(uint64_t val);
+ void xfr32BitInt(uint32_t val);
+ void xfr16BitInt(uint16_t val);
+ void xfrType(uint16_t val)
+ {
+ xfr16BitInt(val);
+ }
+ void xfrIP(const uint32_t& val)
+ {
+ xfr32BitInt(htonl(val));
+ }
+ void xfrIP6(const std::string& val)
+ {
+ xfrBlob(val,16);
+ }
+ void xfrTime(const uint32_t& val)
+ {
+ xfr32BitInt(val);
+ }
+
+ void xfr8BitInt(uint8_t val);
+
+ void xfrName(const DNSName& label, bool compress=false, bool noDot=false);
+ void xfrText(const string& text, bool multi=false, bool lenField=true);
+ void xfrUnquotedText(const string& text, bool lenField);
+ void xfrBlob(const string& blob, int len=-1);
+ void xfrBlobNoSpaces(const string& blob, int len=-1);
+ void xfrHexBlob(const string& blob, bool keepReading=false);
+
+ uint16_t d_pos;
+
+ dnsheader* getHeader();
+ void getRecords(string& records);
+ const vector<uint8_t>& getRecordBeingWritten() { return d_record; }
+
+ void setCanonic(bool val)
+ {
+ d_canonic=val;
+ }
+
+ void setLowercase(bool val)
+ {
+ d_lowerCase=val;
+ }
+ vector <uint8_t>& getContent()
+ {
+ return d_content;
+ }
+ bool eof() { return true; } // we don't know how long the record should be
+
+private:
+ // We declare 1 uint_16 in the public section, these 3 align on a 8-byte boundry
+ uint16_t d_stuff;
+ uint16_t d_sor;
+ uint16_t d_rollbackmarker; // start of last complete packet, for rollback
+
+ vector <uint8_t>& d_content;
+ vector <uint8_t> d_record;
+ DNSName d_qname;
+ DNSName d_recordqname;
+ lmap_t d_labelmap;
+
+ uint32_t d_recordttl;
+ uint16_t d_recordqtype, d_recordqclass;
+
+ uint16_t d_truncatemarker; // end of header, for truncate
+ DNSResourceRecord::Place d_recordplace;
+ bool d_canonic, d_lowerCase;
+};
+
+typedef vector<pair<string::size_type, string::size_type> > labelparts_t;
+// bool labeltokUnescape(labelparts_t& parts, const DNSName& label);
+std::vector<string> segmentDNSText(const string& text); // from dnslabeltext.rl
+std::deque<string> segmentDNSName(const string& input ); // from dnslabeltext.rl
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "iputils.hh"
+#include "sstuff.hh"
+#include "statbag.hh"
+#include <atomic>
+#include <sys/mman.h>
+#include <thread>
+StatBag S;
+
+std::atomic<uint64_t>* g_counter;
+
+void printStatus()
+{
+ auto prev= g_counter->load();
+ for(;;) {
+ sleep(1);
+ cout<<g_counter->load()-prev<<"\t"<<g_counter->load()<<endl;
+ prev=g_counter->load();
+ }
+}
+
+void usage() {
+ cerr<<"Syntax: dumresp LOCAL-ADDRESS LOCAL-PORT NUMBER-OF-PROCESSES"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ for(int i = 1; i < argc; i++) {
+ if((string) argv[i] == "--help"){
+ usage();
+ return(EXIT_SUCCESS);
+ }
+
+ if((string) argv[i] == "--version"){
+ cerr<<"dumresp "<<VERSION<<endl;
+ return(EXIT_SUCCESS);
+ }
+ }
+
+ if(argc != 4) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+ auto ptr = mmap(NULL, sizeof(std::atomic<uint64_t>), PROT_READ | PROT_WRITE,
+ MAP_SHARED | MAP_ANONYMOUS, -1, 0);
+
+ g_counter = new(ptr) std::atomic<uint64_t>();
+
+ int i=1;
+ for(; i < atoi(argv[3]); ++i) {
+ if(!fork())
+ break;
+ }
+ if(i==1) {
+ std::thread t(printStatus);
+ t.detach();
+ }
+
+ ComboAddress local(argv[1], atoi(argv[2]));
+ Socket s(local.sin4.sin_family, SOCK_DGRAM);
+#ifdef SO_REUSEPORT
+ int one=1;
+ if(setsockopt(s.getHandle(), SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) < 0)
+ unixDie("setsockopt for REUSEPORT");
+#endif
+
+ s.bind(local);
+ cout<<"Bound to "<<local.toStringWithPort()<<endl;
+ char buffer[1500];
+ struct dnsheader* dh = (struct dnsheader*)buffer;
+ int len;
+ ComboAddress rem=local;
+ socklen_t socklen = rem.getSocklen();
+ for(;;) {
+ len=recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, (struct sockaddr*)&rem, &socklen);
+ (*g_counter)++;
+ if(len < 0)
+ unixDie("recvfrom");
+
+ if(dh->qr)
+ continue;
+ dh->qr=1;
+ dh->ad=0;
+ if(sendto(s.getHandle(), buffer, len, 0, (struct sockaddr*)&rem, socklen) < 0)
+ unixDie("sendto");
+
+ }
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal error: "<<e.what()<<endl;
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include "dynhandler.hh"
+#include "statbag.hh"
+#include "logger.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include <signal.h>
+#include "misc.hh"
+#include "communicator.hh"
+#include "dnsseckeeper.hh"
+#include "nameserver.hh"
+#include "responsestats.hh"
+#include "ueberbackend.hh"
+#include "common_startup.hh"
+
+extern ResponseStats g_rs;
+
+static bool s_pleasequit;
+static string d_status;
+
+bool DLQuitPlease()
+{
+ return s_pleasequit;
+}
+
+string DLQuitHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ string ret="No return value";
+ if(parts[0]=="QUIT") {
+ s_pleasequit=true;
+ ret="Scheduling exit";
+ L<<Logger::Error<<"Scheduling exit on remote request"<<endl;
+ }
+ return ret;
+}
+
+static void dokill(int)
+{
+ exit(0);
+}
+
+string DLCurrentConfigHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ return ::arg().configstring(true);
+}
+
+string DLRQuitHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ signal(SIGALRM, dokill);
+ alarm(1);
+ return "Exiting";
+}
+
+string DLPingHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ return "PONG";
+}
+
+string DLShowHandler(const vector<string>&parts, Utility::pid_t ppid)
+try
+{
+ extern StatBag S;
+ string ret("Wrong number of parameters");
+ if(parts.size()==2) {
+ if(parts[1]=="*")
+ ret=S.directory();
+ else
+ ret=S.getValueStr(parts[1]);
+ }
+
+ return ret;
+}
+catch(...)
+{
+ return "Unknown";
+}
+
+void setStatus(const string &str)
+{
+ d_status=str;
+}
+
+string DLStatusHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ ostringstream os;
+ os<<ppid<<": "<<d_status;
+ return os.str();
+}
+
+string DLUptimeHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ ostringstream os;
+ os<<humanDuration(time(0)-s_starttime);
+ return os.str();
+}
+
+string DLPurgeHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern PacketCache PC;
+ DNSSECKeeper dk;
+ ostringstream os;
+ int ret=0;
+
+ if(parts.size()>1) {
+ for (vector<string>::const_iterator i=++parts.begin();i<parts.end();++i) {
+ ret+=PC.purge(*i);
+ if(!boost::ends_with(*i, "$"))
+ dk.clearCaches(DNSName(*i));
+ else
+ dk.clearAllCaches(); // at least we do what we promise.. and a bit more!
+ }
+ }
+ else {
+ ret=PC.purge();
+ dk.clearAllCaches();
+ }
+
+ os<<ret;
+ return os.str();
+}
+
+string DLCCHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern PacketCache PC;
+ map<char,int> counts=PC.getCounts();
+ ostringstream os;
+ bool first=true;
+ for(map<char,int>::const_iterator i=counts.begin();i!=counts.end();++i) {
+ if(!first)
+ os<<", ";
+ first=false;
+
+ if(i->first=='!')
+ os<<"negative queries: ";
+ else if(i->first=='Q')
+ os<<"queries: ";
+ else if(i->first=='n')
+ os<<"non-recursive packets: ";
+ else if(i->first=='r')
+ os<<"recursive packets: ";
+ else
+ os<<"unknown: ";
+
+ os<<i->second;
+ }
+
+ return os.str();
+}
+
+string DLQTypesHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ return g_rs.getQTypeReport();
+}
+
+string DLRSizesHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ typedef map<uint16_t, uint64_t> respsizes_t;
+ respsizes_t respsizes = g_rs.getSizeResponseCounts();
+ ostringstream os;
+ boost::format fmt("%d\t%d\n");
+ for(const respsizes_t::value_type& val : respsizes) {
+ os << (fmt % val.first % val.second).str();
+ }
+ return os.str();
+}
+
+string DLRemotesHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern StatBag S;
+ typedef vector<pair<string, unsigned int> > totals_t;
+ totals_t totals = S.getRing("remotes");
+ string ret;
+ boost::format fmt("%s\t%d\n");
+ for(totals_t::value_type& val : totals) {
+ ret += (fmt % val.first % val.second).str();
+ }
+ return ret;
+}
+
+string DLSettingsHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ static const char *whitelist[]={"query-logging",0};
+ const char **p;
+
+ if(parts.size()!=3) {
+ return "Syntax: set variable value";
+ }
+
+ for(p=whitelist;*p;p++)
+ if(*p==parts[1])
+ break;
+ if(*p) {
+ ::arg().set(parts[1])=parts[2];
+ return "done";
+ }
+ else
+ return "This setting cannot be changed at runtime, or no such setting";
+
+}
+
+string DLVersionHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ return VERSION;
+}
+
+string DLNotifyRetrieveHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern CommunicatorClass Communicator;
+ ostringstream os;
+ if(parts.size()!=2)
+ return "syntax: retrieve domain";
+
+ DNSName domain;
+ try {
+ domain = DNSName(parts[1]);
+ } catch (...) {
+ return "Failed to parse domain as valid DNS name";
+ }
+
+ DomainInfo di;
+ UeberBackend B;
+ if(!B.getDomainInfo(domain, di))
+ return "Domain '"+domain.toString()+"' unknown";
+
+ if(di.masters.empty())
+ return "Domain '"+domain.toString()+"' is not a slave domain (or has no master defined)";
+
+ random_shuffle(di.masters.begin(), di.masters.end());
+ Communicator.addSuckRequest(domain, di.masters.front());
+ return "Added retrieval request for '"+domain.toString()+"' from master "+di.masters.front();
+}
+
+string DLNotifyHostHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern CommunicatorClass Communicator;
+ ostringstream os;
+ if(parts.size()!=3)
+ return "syntax: notify-host domain ip";
+ if(!::arg().mustDo("master") && !::arg().mustDo("slave-renotify"))
+ return "PowerDNS not configured as master or slave with re-notifications";
+
+ DNSName domain;
+ try {
+ domain = DNSName(parts[1]);
+ } catch (...) {
+ return "Failed to parse domain as valid DNS name";
+ }
+
+ try {
+ ComboAddress ca(parts[2]);
+ } catch(...)
+ {
+ return "Unable to convert '"+parts[2]+"' to an IP address";
+ }
+
+ L<<Logger::Warning<<"Notification request to host "<<parts[2]<<" for domain '"<<domain<<"' received from operator"<<endl;
+ Communicator.notify(domain, parts[2]);
+ return "Added to queue";
+}
+
+string DLNotifyHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ extern CommunicatorClass Communicator;
+ UeberBackend B;
+ if(parts.size()!=2)
+ return "syntax: notify domain";
+ if(!::arg().mustDo("master") && !::arg().mustDo("slave-renotify"))
+ return "PowerDNS not configured as master or slave with re-notifications";
+ L<<Logger::Warning<<"Notification request for domain '"<<parts[1]<<"' received from operator"<<endl;
+
+ if (parts[1] == "*") {
+ vector<DomainInfo> domains;
+ B.getAllDomains(&domains);
+
+ int total = 0;
+ int notified = 0;
+ for (vector<DomainInfo>::const_iterator di=domains.begin(); di != domains.end(); di++) {
+ if (di->kind == 0) { // MASTER
+ total++;
+ if(Communicator.notifyDomain(di->zone))
+ notified++;
+ }
+ }
+
+ if (total != notified)
+ return itoa(notified)+" out of "+itoa(total)+" zones added to queue - see log";
+ return "Added "+itoa(total)+" MASTER zones to queue";
+ } else {
+ DNSName domain;
+ try {
+ domain = DNSName(parts[1]);
+ } catch (...) {
+ return "Failed to parse domain as valid DNS name";
+ }
+ if(!Communicator.notifyDomain(DNSName(parts[1])))
+ return "Failed to add to the queue - see log";
+ return "Added to queue";
+ }
+}
+
+string DLRediscoverHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ UeberBackend B;
+ try {
+ L<<Logger::Error<<"Rediscovery was requested"<<endl;
+ string status="Ok";
+ B.rediscover(&status);
+ return status;
+ }
+ catch(PDNSException &ae) {
+ return ae.reason;
+ }
+
+}
+
+string DLReloadHandler(const vector<string>&parts, Utility::pid_t ppid)
+{
+ UeberBackend B;
+ B.reload();
+ L<<Logger::Error<<"Reload was requested"<<endl;
+ return "Ok";
+}
+
+
+string DLListZones(const vector<string>&parts, Utility::pid_t ppid)
+{
+ UeberBackend B;
+ L<<Logger::Notice<<"Received request to list zones."<<endl;
+ vector<DomainInfo> domains;
+ B.getAllDomains(&domains);
+ ostringstream ret;
+ int kindFilter = -1;
+ if (parts.size() > 1) {
+ if (toUpper(parts[1]) == "MASTER")
+ kindFilter = 0;
+ else if (toUpper(parts[1]) == "SLAVE")
+ kindFilter = 1;
+ else if (toUpper(parts[1]) == "NATIVE")
+ kindFilter = 2;
+ }
+
+ int count = 0;
+
+ for (vector<DomainInfo>::const_iterator di=domains.begin(); di != domains.end(); di++) {
+ if (di->kind == kindFilter || kindFilter == -1) {
+ ret<<di->zone.toString()<<endl;
+ count++;
+ }
+ }
+ if (kindFilter != -1)
+ ret<<parts[1]<<" zonecount:"<<count;
+ else
+ ret<<"All zonecount:"<<count;
+
+ return ret.str();
+}
+
+string DLPolicy(const vector<string>&parts, Utility::pid_t ppid)
+{
+ if(LPE) {
+ return LPE->policycmd(parts);
+ }
+ else {
+ return "no policy script loaded";
+ }
+}
+
+#ifdef HAVE_P11KIT1
+extern bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin);
+#endif
+
+string DLTokenLogin(const vector<string>&parts, Utility::pid_t ppid)
+{
+#ifndef HAVE_P11KIT1
+ return "PKCS#11 support not compiled in";
+#else
+ if (parts.size() != 4) {
+ return "invalid number of parameters, needs 4, got " + std::to_string(parts.size());
+ }
+
+ if (PKCS11ModuleSlotLogin(parts[1], parts[2], parts[3])) {
+ return "logged in";
+ } else {
+ return "could not log in, check logs";
+ }
+#endif
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DYNHANDLER_HH
+#define PDNS_DYNHANDLER_HH
+
+#include <vector>
+#include <string>
+#include <stdlib.h>
+#include <sys/types.h>
+
+#include <unistd.h>
+
+#include "namespaces.hh"
+
+
+bool DLQuitPlease();
+void setStatus(const string &str);
+string DLQuitHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLRQuitHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLPingHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLShowHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLUptimeHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLSettingsHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLRespSizeHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLCCHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLQTypesHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLRSizesHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLRemotesHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLStatusHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLNotifyHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLNotifyHostHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLReloadHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLRediscoverHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLVersionHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLPurgeHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLNotifyRetrieveHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLCurrentConfigHandler(const vector<string>&parts, Utility::pid_t ppid);
+string DLListZones(const vector<string>&parts, Utility::pid_t ppid);
+string DLPolicy(const vector<string>&parts, Utility::pid_t ppid);
+string DLTokenLogin(const vector<string>&parts, Utility::pid_t ppid);
+uint64_t udpErrorStats(const std::string& str);
+#endif /* PDNS_DYNHANDLER_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <cstring>
+#include <string>
+#include <map>
+#include <sys/types.h>
+#include <sys/un.h>
+#include <dlfcn.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <boost/algorithm/string.hpp>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include <sys/types.h>
+#include <signal.h>
+
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <boost/algorithm/string.hpp>
+#include "misc.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include "dnsbackend.hh"
+#include "dynlistener.hh"
+#include "dnspacket.hh"
+#include "logger.hh"
+#include "statbag.hh"
+
+extern StatBag S;
+
+DynListener::g_funkdb_t DynListener::s_funcdb;
+DynListener::g_funk_t* DynListener::s_restfunc;
+
+DynListener::~DynListener()
+{
+ if(!d_socketname.empty())
+ unlink(d_socketname.c_str());
+}
+
+void DynListener::createSocketAndBind(int family, struct sockaddr*local, size_t len)
+{
+ d_s=socket(family, SOCK_STREAM,0);
+ setCloseOnExec(d_s);
+
+ if(d_s < 0) {
+ if (family == AF_UNIX)
+ L<<Logger::Error<<"Unable to create control socket at '"<<((struct sockaddr_un*)local)->sun_path<<"', reason: "<<strerror(errno)<<endl;
+ else
+ L<<Logger::Error<<"Unable to create control socket on '"<<((ComboAddress *)local)->toStringWithPort()<<"', reason: "<<strerror(errno)<<endl;
+ exit(1);
+ }
+
+ int tmp=1;
+ if(setsockopt(d_s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
+ throw PDNSException(string("Setsockopt failed on control socket: ")+strerror(errno));
+
+ if(bind(d_s, local, len) < 0) {
+ if (family == AF_UNIX)
+ L<<Logger::Critical<<"Unable to bind to control socket at '"<<((struct sockaddr_un*)local)->sun_path<<"', reason: "<<strerror(errno)<<endl;
+ else
+ L<<Logger::Critical<<"Unable to bind to control socket on '"<<((ComboAddress *)local)->toStringWithPort()<<"', reason: "<<strerror(errno)<<endl;
+ exit(1);
+ }
+}
+
+/* this does a simplistic check, if we can connect, we consider it live. If we can't connect because
+ of access denied, we must consider it dead, nothing we can do about it.
+*/
+bool DynListener::testLive(const string& fname)
+{
+ struct sockaddr_un addr;
+ int fd = socket(AF_UNIX, SOCK_STREAM, 0);
+ if(fd < 0) { // we'll have bigger issues down the road
+ return false;
+ }
+
+ if (makeUNsockaddr(fname, &addr)) {
+ L<<Logger::Critical<<"Unable to open controlsocket, path '"<<fname<<"' is not a valid UNIX socket path."<<endl;
+ exit(1);
+ }
+
+ int status = connect(fd, (struct sockaddr*)&addr, sizeof(addr));
+ close(fd);
+ return status==0;
+}
+
+void DynListener::listenOnUnixDomain(const string& fname)
+{
+ if(testLive(fname)) {
+ L<<Logger::Critical<<"Previous controlsocket '"<<fname<<"' is in use"<<endl;
+ exit(1);
+ }
+ int err=unlink(fname.c_str());
+ if(err < 0 && errno!=ENOENT) {
+ L<<Logger::Critical<<"Unable to remove (previous) controlsocket at '"<<fname<<"': "<<strerror(errno)<<endl;
+ exit(1);
+ }
+
+ struct sockaddr_un local;
+ if (makeUNsockaddr(fname, &local)) {
+ L<<Logger::Critical<<"Unable to bind to controlsocket, path '"<<fname<<"' is not a valid UNIX socket path."<<endl;
+ exit(1);
+ }
+
+ createSocketAndBind(AF_UNIX, (struct sockaddr*)& local, sizeof(local));
+ d_socketname=fname;
+ if(!arg()["setgid"].empty()) {
+ if(chmod(fname.c_str(),0660)<0)
+ L<<Logger::Error<<"Unable to change group access mode of controlsocket at '"<<fname<<"', reason: "<<strerror(errno)<<endl;
+ if(chown(fname.c_str(),static_cast<uid_t>(-1),Utility::makeGidNumeric(arg()["setgid"]))<0)
+ L<<Logger::Error<<"Unable to change group ownership of controlsocket at '"<<fname<<"', reason: "<<strerror(errno)<<endl;
+ }
+
+ listen(d_s, 10);
+
+ L<<Logger::Warning<<"Listening on controlsocket in '"<<fname<<"'"<<endl;
+ d_nonlocal=true;
+}
+
+void DynListener::listenOnTCP(const ComboAddress& local)
+{
+ createSocketAndBind(AF_INET, (struct sockaddr*)& local, local.getSocklen());
+ listen(d_s, 10);
+
+ d_socketaddress=local;
+ L<<Logger::Warning<<"Listening on controlsocket on '"<<local.toStringWithPort()<<"'"<<endl;
+ d_nonlocal=true;
+
+ if(!::arg()["tcp-control-range"].empty()) {
+ d_tcprange.toMasks(::arg()["tcp-control-range"]);
+ L<<Logger::Warning<<"Only allowing TCP control from: "<<d_tcprange.toString()<<endl;
+ }
+}
+
+
+DynListener::DynListener(const ComboAddress& local)
+{
+ listenOnTCP(local);
+ d_tcp=true;
+ d_client=-1;
+ d_tid=0;
+ d_ppid=0;
+}
+
+DynListener::DynListener(const string &progname)
+{
+ d_client=-1;
+ d_tid=0;
+ d_ppid=0;
+ d_s=-1;
+
+ if(!progname.empty()) {
+ string socketname = ::arg()["socket-dir"];
+ if (::arg()["socket-dir"].empty()) {
+ if (::arg()["chroot"].empty())
+ socketname = LOCALSTATEDIR;
+ else
+ socketname = ::arg()["chroot"];
+ } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
+ socketname = ::arg()["chroot"] + ::arg()["socket-dir"];
+ }
+ socketname += "/";
+ cleanSlashes(socketname);
+
+ if(!mkdir(socketname.c_str(),0700)) // make /var directory, if needed
+ L<<Logger::Warning<<"Created local state directory '"<<socketname<<"'"<<endl;
+ else if(errno!=EEXIST) {
+ L<<Logger::Critical<<"Unable to create socket directory ("<<socketname<<") and it does not exist yet"<<endl;
+ exit(1);
+ }
+
+ socketname+=progname+".controlsocket";
+ listenOnUnixDomain(socketname);
+ }
+ else
+ d_nonlocal=false; // we listen on stdin!
+ d_tcp=false;
+}
+
+void DynListener::go()
+{
+ d_ppid=getpid();
+ pthread_create(&d_tid,0,&DynListener::theListenerHelper,this);
+}
+
+void *DynListener::theListenerHelper(void *p)
+{
+ DynListener *us=static_cast<DynListener *>(p);
+ us->theListener();
+ L<<Logger::Error<<"Control listener aborted, please file a bug!"<<endl;
+ return 0;
+}
+
+string DynListener::getLine()
+{
+ vector<char> mesg;
+ mesg.resize(1024000);
+
+ int len;
+
+ ComboAddress remote;
+ socklen_t remlen=remote.getSocklen();
+
+ if(d_nonlocal) {
+ for(;;) {
+ d_client=accept(d_s,(sockaddr*)&remote,&remlen);
+ if(d_client<0) {
+ if(errno!=EINTR)
+ L<<Logger::Error<<"Unable to accept controlsocket connection ("<<d_s<<"): "<<strerror(errno)<<endl;
+ continue;
+ }
+
+ if(d_tcp && !d_tcprange.match(&remote)) { // checks if the remote is within the permitted range.
+ L<<Logger::Error<<"Access denied to remote "<<remote.toString()<<" because not allowed"<<endl;
+ writen2(d_client, "Access denied to "+remote.toString()+"\n");
+ close(d_client);
+ continue;
+ }
+
+ std::shared_ptr<FILE> fp=std::shared_ptr<FILE>(fdopen(dup(d_client), "r"), fclose);
+ if(d_tcp) {
+ if(!fgets(&mesg[0], mesg.size(), fp.get())) {
+ L<<Logger::Error<<"Unable to receive password from controlsocket ("<<d_client<<"): "<<strerror(errno)<<endl;
+ close(d_client);
+ continue;
+ }
+ string password(&mesg[0]);
+ boost::trim(password);
+ if(password.empty() || password!=arg()["tcp-control-secret"]) {
+ L<<Logger::Error<<"Wrong password on TCP control socket"<<endl;
+ writen2(d_client, "Wrong password");
+
+ close(d_client);
+ continue;
+ }
+ }
+ errno=0;
+ if(!fgets(&mesg[0], mesg.size(), fp.get())) {
+ if(errno)
+ L<<Logger::Error<<"Unable to receive line from controlsocket ("<<d_client<<"): "<<strerror(errno)<<endl;
+ close(d_client);
+ continue;
+ }
+
+ if(strlen(&mesg[0]) == mesg.size()) {
+ L<<Logger::Error<<"Line on controlsocket ("<<d_client<<") was too long"<<endl;
+ close(d_client);
+ continue;
+ }
+ break;
+ }
+ }
+ else {
+ if(isatty(0))
+ if(write(1, "% ", 2) !=2)
+ throw PDNSException("Writing to console: "+stringerror());
+ if((len=read(0, &mesg[0], mesg.size())) < 0)
+ throw PDNSException("Reading from the control pipe: "+stringerror());
+ else if(len==0)
+ throw PDNSException("Guardian exited - going down as well");
+
+ if(len == (int)mesg.size())
+ throw PDNSException("Line on control console was too long");
+
+ mesg[len]=0;
+ }
+
+ return &mesg[0];
+}
+
+void DynListener::sendlines(const string &l)
+{
+ if(d_nonlocal) {
+ unsigned int sent=0;
+ int ret;
+ while(sent < l.length()) {
+ ret=send(d_client, l.c_str()+sent, l.length()-sent, 0);
+
+ if(ret<0 || !ret) {
+ L<<Logger::Error<<"Error sending data to pdns_control: "<<stringerror()<<endl;
+ break;
+ }
+ sent+=ret;
+ }
+ close(d_client);
+ } else {
+ string lines=l;
+ if(!lines.empty() && lines[lines.length()-1] != '\n')
+ lines.append("\n");
+ lines.append(1, '\0');
+ lines.append(1, '\n');
+ if((unsigned int)write(1, lines.c_str(), lines.length()) != lines.length())
+ L<<Logger::Error<<"Error sending data to console: "<<stringerror()<<endl;
+ }
+}
+
+void DynListener::registerFunc(const string &name, g_funk_t *gf, const string &usage, const string &args)
+{
+ g_funkwithusage_t e = {gf, args, usage};
+ s_funcdb[name]=e;
+}
+
+void DynListener::registerRestFunc(g_funk_t *gf)
+{
+ s_restfunc=gf;
+}
+
+void DynListener::theListener()
+{
+ try {
+ signal(SIGPIPE,SIG_IGN);
+
+ for(int n=0;;++n) {
+ string line=getLine();
+ boost::trim_right(line);
+
+ vector<string>parts;
+ stringtok(parts,line," ");
+ if(parts.empty()) {
+ sendlines("Empty line");
+ continue;
+ }
+
+ try {
+ parts[0] = toUpper( parts[0] );
+ if(s_funcdb.count(parts[0]))
+ sendlines((*(s_funcdb[parts[0]].func))(parts,d_ppid));
+ else if (parts[0] == "HELP")
+ sendlines(getHelp());
+ else if(s_restfunc)
+ sendlines((*s_restfunc)(parts,d_ppid));
+ else
+ sendlines("Unknown command: '"+parts[0]+"'");
+ }
+ catch(PDNSException &AE) {
+ L<<Logger::Error<<"Non-fatal error in control listener command '"<<line<<"': "<<AE.reason<<endl;
+ }
+ catch(string &E) {
+ L<<Logger::Error<<"Non-fatal error 2 in control listener command '"<<line<<"': "<<E<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Non-fatal STL error in control listener command '"<<line<<"': "<<e.what()<<endl;
+ }
+ catch(...) {
+ L<<Logger::Error<<"Non-fatal error in control listener command '"<<line<<"': unknown exception occurred"<<endl;
+ }
+ }
+ }
+ catch(PDNSException &AE) {
+ L<<Logger::Error<<"Fatal error in control listener: "<<AE.reason<<endl;
+ }
+ catch(string &E) {
+ L<<Logger::Error<<"Fatal error 2 in control listener: "<<E<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Fatal STL error in control listener: "<<e.what()<<endl;
+ }
+ catch(...) {
+ L<<Logger::Error<<"Fatal: unknown exception in control listener occurred"<<endl;
+ }
+}
+
+
+string DynListener::getHelp()
+{
+ vector<string> funcs;
+ string rest;
+
+ // s_restfunc, when in guardian mode, is the function that
+ // can pass commands on to the guarded instance
+ // we just pass it HELP and merge it with our own list
+ if(s_restfunc)
+ {
+ vector<string> parts;
+ parts.push_back("HELP");
+ rest=((*s_restfunc)(parts,d_ppid));
+ boost::split(funcs, rest, boost::is_any_of("\n"));
+ }
+
+ const boost::format fmter("%|-32| %||");
+
+ for(g_funkdb_t::const_iterator i=s_funcdb.begin();i!=s_funcdb.end();++i) {
+ funcs.push_back(str(boost::format(fmter) % (toLower(i->first)+" "+i->second.args) % i->second.usage));
+ }
+ sort(funcs.begin(), funcs.end());
+
+ // hack: this removes the duplicate quit method
+ funcs.resize(unique(funcs.begin(), funcs.end()) - funcs.begin());
+ return boost::join(funcs, "\n");
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_DYNLISTENER
+#define PDNS_DYNLISTENER
+
+#include <string>
+#include <vector>
+#include <pthread.h>
+#include <sys/types.h>
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include "iputils.hh"
+#include <boost/utility.hpp>
+#include <unistd.h>
+#include <sys/un.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include "namespaces.hh"
+
+class DynListener : public boost::noncopyable
+{
+public:
+ explicit DynListener(const string &pname="");
+ explicit DynListener(const ComboAddress& addr);
+ ~DynListener();
+ void go();
+ void theListener();
+ static void *theListenerHelper(void *p);
+
+ typedef string g_funk_t(const vector<string> &parts, Utility::pid_t ppid); // guido!
+ typedef struct { g_funk_t *func; string args; string usage; } g_funkwithusage_t;
+ typedef map<string,g_funkwithusage_t> g_funkdb_t;
+
+ static void registerFunc(const string &name, g_funk_t *gf, const string &usage="", const string &args="");
+ static void registerRestFunc(g_funk_t *gf);
+ static g_funk_t* getFunc(const string& fname) { return s_funcdb[fname].func; }
+private:
+ void sendlines(const string &lines);
+ string getHelp();
+ string getLine();
+
+ void listenOnUnixDomain(const std::string& fname);
+ void listenOnTCP(const ComboAddress&);
+ void createSocketAndBind(int family, struct sockaddr*local, size_t len);
+
+ NetmaskGroup d_tcprange;
+ int d_s;
+ int d_client;
+ pthread_t d_tid;
+ bool d_nonlocal;
+ bool d_tcp;
+ pid_t d_ppid;
+
+ string d_socketname;
+ ComboAddress d_socketaddress;
+ static g_funkdb_t s_funcdb;
+ static g_funk_t* s_restfunc;
+ bool testLive(const string& fname);
+};
+#endif /* PDNS_DYNLISTENER */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <iostream>
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <unistd.h>
+#include <errno.h>
+#include <climits>
+#include <string>
+#include <map>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <sys/types.h>
+
+
+#include <sys/stat.h>
+#include "pdnsexception.hh"
+#include "misc.hh"
+#include "dynmessenger.hh"
+#include "arguments.hh"
+#include "statbag.hh"
+#include "misc.hh"
+#include "namespaces.hh"
+#include "namespaces.hh"
+
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+}
+
+StatBag S;
+
+int main(int argc, char **argv)
+{
+ string s_programname="pdns";
+
+ ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR;
+ ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
+ ::arg().set("remote-address","Remote address to query");
+ ::arg().set("remote-port","Remote port to query")="53000";
+ ::arg().set("secret","Secret needed to connect to remote PowerDNS");
+
+ ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
+ ::arg().setCmd("no-config","Don't parse configuration file");
+ ::arg().set("chroot","")="";
+ ::arg().setCmd("help","Provide a helpful message");
+ ::arg().laxParse(argc,argv);
+
+ if(::arg().mustDo("help")) {
+ cout<<"syntax:"<<endl<<endl;
+ cout<<::arg().helpstring(::arg()["help"])<<endl;
+ cout<<"In addition, 'pdns_control help' can be used to retrieve a list\nof available commands from PowerDNS"<<endl;
+ exit(0);
+ }
+
+ const vector<string>commands=::arg().getCommands();
+
+ if(commands.empty()) {
+ cerr<<"No command passed"<<endl;
+ return 0;
+ }
+
+ if(::arg()["config-name"]!="")
+ s_programname+="-"+::arg()["config-name"];
+
+ string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
+ cleanSlashes(configname);
+
+ if(!::arg().mustDo("no-config")) {
+ ::arg().laxFile(configname.c_str());
+ ::arg().laxParse(argc,argv); // reparse so the commandline still wins
+ }
+
+ string socketname=::arg()["socket-dir"];
+ if (::arg()["socket-dir"].empty()) {
+ if (::arg()["chroot"].empty())
+ socketname = LOCALSTATEDIR;
+ else
+ socketname = ::arg()["chroot"] + "/";
+ } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
+ socketname = ::arg()["chroot"] + ::arg()["socket-dir"];
+ }
+
+ socketname += "/" + s_programname + ".controlsocket";
+ cleanSlashes(socketname);
+
+ try {
+ string command=commands[0];
+ shared_ptr<DynMessenger> D;
+ if(::arg()["remote-address"].empty())
+ D=shared_ptr<DynMessenger>(new DynMessenger(socketname));
+ else {
+ uint16_t port;
+ try {
+ port = static_cast<uint16_t>(pdns_stou(::arg()["remote-port"]));
+ }
+ catch(...) {
+ cerr<<"Unable to convert '"<<::arg()["remote-port"]<<"' to a port number for connecting to remote PowerDNS\n";
+ exit(99);
+ }
+
+ D=shared_ptr<DynMessenger>(new DynMessenger(ComboAddress(::arg()["remote-address"], port), ::arg()["secret"]));
+ }
+
+ string message;
+ for(vector<string>::const_iterator i=commands.begin();i!=commands.end();++i) {
+ if(i!=commands.begin())
+ message+=" ";
+ message+=*i;
+ }
+
+ if(command=="show") {
+ message="SHOW ";
+ for(unsigned int n=1;n<commands.size();n++) {
+ message+=commands[n];
+ message+=" ";
+ }
+ }
+ else if(command=="list") {
+ message="SHOW *";
+ command="show";
+ }
+ else if(command=="quit" || command=="QUIT") {
+ message="QUIT";
+ }
+ else if(command=="status" || command=="STATUS") {
+ message="STATUS";
+ }
+ else if(command=="version" || command=="VERSION") {
+ message="VERSION";
+ }
+
+
+ if(D->send(message)<0) {
+ cerr<<"Error sending command"<<endl;
+ return 1;
+ }
+
+ string resp=D->receive();
+ if(resp.compare(0, 7, "Unknown") == 0) {
+ cerr<<resp<<endl;
+ return 1;
+ }
+
+ cout<<resp<<endl;
+ }
+ catch(TimeoutException &ae) {
+ cerr<<"Timeout error: "<<ae.reason<<endl;
+ return 2;
+ }
+ catch(PDNSException &ae) {
+ cerr<<"Fatal error: "<<ae.reason<<endl;
+ return 1;
+ }
+ catch(const std::runtime_error& e) {
+ cerr<<"Runtime error: "<<e.what()<<endl;
+ return 2;
+ }
+ return 0;
+}
+
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dynmessenger.hh"
+#include <cstdio>
+#include "utility.hh"
+#include <cstdlib>
+#include <cstring>
+#include <cerrno>
+#include <iostream>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+DynMessenger::DynMessenger(const string &fname,
+ int timeout_sec,
+ int timeout_usec)
+{
+ d_s=socket(AF_UNIX,SOCK_STREAM,0);
+ setCloseOnExec(d_s);
+
+ if(d_s<0) {
+ throw PDNSException(string("socket")+strerror(errno));
+ }
+
+ try {
+ if(makeUNsockaddr(fname, &d_remote))
+ throw PDNSException("Unable to connect to remote '"+fname+"': Path is not a valid UNIX socket path.");
+
+ struct timeval timeout;
+ timeout.tv_sec = timeout_sec;
+ timeout.tv_usec = timeout_usec;
+
+ if (setsockopt (d_s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
+ throw PDNSException("Unable to set SO_RCVTIMEO option on socket: " + stringerror());
+
+ if (setsockopt (d_s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
+ throw PDNSException("Unable to set SO_SNDTIMEO option on socket: " + stringerror());
+
+ int ret = Utility::timed_connect(d_s,(sockaddr*)&d_remote,sizeof(d_remote), timeout_sec, timeout_usec);
+
+ if (ret == 0)
+ throw TimeoutException("Unable to connect to remote '"+fname+"': "+stringerror());
+ else if (ret < 0)
+ throw PDNSException("Unable to connect to remote '"+fname+"': "+stringerror());
+
+ } catch(...) {
+ close(d_s);
+ d_s=-1;
+ throw;
+ }
+}
+
+DynMessenger::DynMessenger(const ComboAddress& remote,
+ const string &secret,
+ int timeout_sec,
+ int timeout_usec)
+{
+ d_s=socket(AF_INET, SOCK_STREAM,0);
+ setCloseOnExec(d_s);
+
+ if(d_s<0) {
+ throw PDNSException(string("socket")+strerror(errno));
+ }
+
+ try {
+ struct timeval timeout;
+ timeout.tv_sec = timeout_sec;
+ timeout.tv_usec = timeout_usec;
+
+ if (setsockopt (d_s, SOL_SOCKET, SO_RCVTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
+ throw PDNSException("Unable to set SO_RCVTIMEO option on socket: " + stringerror());
+
+ if (setsockopt (d_s, SOL_SOCKET, SO_SNDTIMEO, (char *)&timeout, sizeof(timeout)) < 0)
+ throw PDNSException("Unable to set SO_SNDTIMEO option on socket: " + stringerror());
+
+ int ret = Utility::timed_connect(d_s, (sockaddr*)&remote, remote.getSocklen(), timeout_sec, timeout_usec);
+
+ if (ret == 0)
+ throw TimeoutException("Unable to connect to remote '"+remote.toStringWithPort()+"': "+string(strerror(errno)));
+ else if (ret < 0)
+ throw PDNSException("Unable to connect to remote '"+remote.toStringWithPort()+"': "+string(strerror(errno)));
+
+ string login=secret+"\n";
+ writen2(d_s, login);
+ } catch(...) {
+ close(d_s);
+ d_s=-1;
+ throw;
+ }
+}
+
+DynMessenger::~DynMessenger()
+{
+ if (d_s > 0)
+ close(d_s);
+}
+
+int DynMessenger::send(const string &msg) const
+{
+ try {
+ writen2(d_s, msg+"\n");
+ return 0;
+ } catch(std::runtime_error& e) {
+ if (errno == EAGAIN)
+ throw TimeoutException("Error from remote in send(): " + string(e.what()));
+ else
+ throw PDNSException("Error from remote in send(): " + string(e.what()));
+ }
+}
+
+string DynMessenger::receive() const
+{
+ char buffer[1500];
+
+ int retlen;
+ string answer;
+ for(;;) {
+ retlen=recv(d_s,buffer,sizeof(buffer),0);
+ if(retlen<0) {
+ if (errno == EAGAIN)
+ throw TimeoutException("Error from remote in receive(): " + string(strerror(errno)));
+ else
+ throw PDNSException("Error from remote in receive(): " + string(strerror(errno)));
+ }
+
+ answer.append(buffer,retlen);
+ if (retlen == 0)
+ break;
+ }
+
+ return answer;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef DYNMESSENGER_HH
+#define DYNMESSENGER_HH
+
+#include <string>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <libgen.h>
+#include <errno.h>
+#include "iputils.hh"
+#include "pdnsexception.hh"
+
+#include "namespaces.hh"
+
+//! The DynMessenger can send messages to UNIX domain sockets and TCP sockets
+class DynMessenger
+{
+ int d_s;
+
+ struct sockaddr_un d_remote; // our remote address
+
+ DynMessenger(const DynMessenger &); // NOT IMPLEMENTED
+
+public:
+ // CREATORS
+
+ DynMessenger(const string &filename,
+ int timeout_sec = 7,
+ int timeout_usec = 0); //!< Create a DynMessenger sending to this file
+
+ DynMessenger(const ComboAddress& remote,
+ const string &password,
+ int timeout_sec = 7,
+ int timeout_usec = 0); //!< Create a DynMessenger sending to this file
+
+ ~DynMessenger();
+
+ // ACCESSORS
+ int send(const string &message) const; //!< Send a message to a DynListener
+ string receive() const; //!< receive an answer from a DynListener
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "dns.hh"
+#include "ednsoptions.hh"
+#include "iputils.hh"
+
+/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(char* optRR, const size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize)
+{
+ assert(optRR != NULL);
+ assert(optionValue != NULL);
+ assert(optionValueSize != NULL);
+ size_t pos = 0;
+ if (len < DNS_RDLENGTH_SIZE)
+ return EINVAL;
+
+ const uint16_t rdLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ size_t rdPos = 0;
+ pos += DNS_RDLENGTH_SIZE;
+ if ((pos + rdLen) > len) {
+ return EINVAL;
+ }
+
+ while(len >= (pos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE) &&
+ rdLen >= (rdPos + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE)) {
+ const uint16_t optionCode = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ pos += EDNS_OPTION_CODE_SIZE;
+ rdPos += EDNS_OPTION_CODE_SIZE;
+ const uint16_t optionLen = (((unsigned char) optRR[pos]) * 256) + ((unsigned char) optRR[pos+1]);
+ pos += EDNS_OPTION_LENGTH_SIZE;
+ rdPos += EDNS_OPTION_LENGTH_SIZE;
+ if (optionLen > (rdLen - rdPos) || optionLen > (len - pos))
+ return EINVAL;
+
+ if (optionCode == wantedOption) {
+ *optionValue = optRR + pos - (EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE);
+ *optionValueSize = optionLen + EDNS_OPTION_CODE_SIZE + EDNS_OPTION_LENGTH_SIZE;
+ return 0;
+ }
+ else {
+ /* skip this option */
+ pos += optionLen;
+ rdPos += optionLen;
+ }
+ }
+
+ return ENOENT;
+}
+
+void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res)
+{
+ const uint16_t ednsOptionCode = htons(optionCode);
+ const uint16_t payloadLen = htons(payload.length());
+ res.append((const char *) &ednsOptionCode, sizeof ednsOptionCode);
+ res.append((const char *) &payloadLen, sizeof payloadLen);
+ res.append(payload);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_EDNSOPTIONS_HH
+#define PDNS_EDNSOPTIONS_HH
+
+#include "namespaces.hh"
+
+struct EDNSOptionCode
+{
+ enum EDNSOptionCodeEnum {NSID=3, DAU=4, DHU=6, N3U=7, ECS=8, EXPIRE=9, COOKIE=10, TCPKEEPALIVE=11, PADDING=12, CHAIN=13};
+};
+
+/* extract a specific EDNS0 option from a pointer on the beginning rdLen of the OPT RR */
+int getEDNSOption(char* optRR, size_t len, uint16_t wantedOption, char ** optionValue, size_t * optionValueSize);
+void generateEDNSOption(uint16_t optionCode, const std::string& payload, std::string& res);
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "ednssubnet.hh"
+#include "dns.hh"
+
+namespace {
+ struct EDNSSubnetOptsWire
+ {
+ uint16_t family;
+ uint8_t sourceMask;
+ uint8_t scopeMask;
+ } GCCPACKATTRIBUTE; // BRRRRR
+
+}
+
+bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso)
+{
+ return getEDNSSubnetOptsFromString(options.c_str(), options.length(), eso);
+}
+bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso)
+{
+ //cerr<<"options.size:"<<options.size()<<endl;
+ EDNSSubnetOptsWire esow;
+ static_assert (sizeof(esow) == 4, "sizeof(EDNSSubnetOptsWire) must be 4 bytes");
+ if(len <= sizeof(esow))
+ return false;
+ memcpy(&esow, options, sizeof(esow));
+ esow.family = ntohs(esow.family);
+ //cerr<<"Family when parsing from string: "<<esow.family<<endl;
+ ComboAddress address;
+ unsigned int octetsin = ((esow.sourceMask - 1)>> 3)+1;
+ //cerr<<"octetsin:"<<octetsin<<endl;
+ if(esow.family == 1) {
+ if(len != sizeof(esow)+octetsin)
+ return false;
+ if(octetsin > sizeof(address.sin4.sin_addr.s_addr))
+ return false;
+ memset(&address, 0, sizeof(address));
+ address.sin4.sin_family = AF_INET;
+ memcpy(&address.sin4.sin_addr.s_addr, options+sizeof(esow), octetsin);
+ } else if(esow.family == 2) {
+ if(len != sizeof(esow)+octetsin)
+ return false;
+ if(octetsin > sizeof(address.sin6.sin6_addr.s6_addr))
+ return false;
+ memset(&address, 0, sizeof(address));
+ address.sin4.sin_family = AF_INET6;
+ memcpy(&address.sin6.sin6_addr.s6_addr, options+sizeof(esow), octetsin);
+ }
+ else
+ return false;
+ // cerr<<"Source address: "<<address.toString()<<", mask: "<<(int)esow.sourceMask<<endl;
+ eso->source = Netmask(address, esow.sourceMask);
+ eso->scope = Netmask(address, esow.scopeMask);
+ return true;
+}
+
+string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso)
+{
+ string ret;
+ EDNSSubnetOptsWire esow;
+ uint16_t family = htons(eso.source.getNetwork().sin4.sin_family == AF_INET ? 1 : 2);
+ esow.family = family;
+ esow.sourceMask = eso.source.getBits();
+ esow.scopeMask = eso.scope.getBits();
+ ret.assign((const char*)&esow, sizeof(esow));
+ int octetsout = ((esow.sourceMask - 1)>> 3)+1;
+
+ if(family == htons(1))
+ ret.append((const char*) &eso.source.getNetwork().sin4.sin_addr.s_addr, octetsout);
+ else
+ ret.append((const char*) &eso.source.getNetwork().sin6.sin6_addr.s6_addr, octetsout);
+ return ret;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_EDNSSUBNET_HH
+#define PDNS_EDNSSUBNET_HH
+
+#include "namespaces.hh"
+#include "iputils.hh"
+#include "dnsname.hh"
+
+extern NetmaskGroup g_ednssubnets;
+extern SuffixMatchNode g_ednsdomains;
+struct EDNSSubnetOpts
+{
+ Netmask source;
+ Netmask scope;
+};
+
+bool getEDNSSubnetOptsFromString(const string& options, EDNSSubnetOpts* eso);
+bool getEDNSSubnetOptsFromString(const char* options, unsigned int len, EDNSSubnetOpts* eso);
+string makeEDNSSubnetOptsString(const EDNSSubnetOpts& eso);
+#endif
--- /dev/null
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at https://mozilla.org/MPL/2.0/.
+
+// Please pull this list from, and only from https://publicsuffix.org/list/public_suffix_list.dat,
+// rather than any other VCS sites. Pulling from any other URL is not guaranteed to be supported.
+
+// Instructions on pulling and using this list can be found at https://publicsuffix.org/list/.
+
+// ===BEGIN ICANN DOMAINS===
+
+// ac : https://en.wikipedia.org/wiki/.ac
+ac
+com.ac
+edu.ac
+gov.ac
+net.ac
+mil.ac
+org.ac
+
+// ad : https://en.wikipedia.org/wiki/.ad
+ad
+nom.ad
+
+// ae : https://en.wikipedia.org/wiki/.ae
+// see also: "Domain Name Eligibility Policy" at http://www.aeda.ae/eng/aepolicy.php
+ae
+co.ae
+net.ae
+org.ae
+sch.ae
+ac.ae
+gov.ae
+mil.ae
+
+// aero : see https://www.information.aero/index.php?id=66
+aero
+accident-investigation.aero
+accident-prevention.aero
+aerobatic.aero
+aeroclub.aero
+aerodrome.aero
+agents.aero
+aircraft.aero
+airline.aero
+airport.aero
+air-surveillance.aero
+airtraffic.aero
+air-traffic-control.aero
+ambulance.aero
+amusement.aero
+association.aero
+author.aero
+ballooning.aero
+broker.aero
+caa.aero
+cargo.aero
+catering.aero
+certification.aero
+championship.aero
+charter.aero
+civilaviation.aero
+club.aero
+conference.aero
+consultant.aero
+consulting.aero
+control.aero
+council.aero
+crew.aero
+design.aero
+dgca.aero
+educator.aero
+emergency.aero
+engine.aero
+engineer.aero
+entertainment.aero
+equipment.aero
+exchange.aero
+express.aero
+federation.aero
+flight.aero
+freight.aero
+fuel.aero
+gliding.aero
+government.aero
+groundhandling.aero
+group.aero
+hanggliding.aero
+homebuilt.aero
+insurance.aero
+journal.aero
+journalist.aero
+leasing.aero
+logistics.aero
+magazine.aero
+maintenance.aero
+media.aero
+microlight.aero
+modelling.aero
+navigation.aero
+parachuting.aero
+paragliding.aero
+passenger-association.aero
+pilot.aero
+press.aero
+production.aero
+recreation.aero
+repbody.aero
+res.aero
+research.aero
+rotorcraft.aero
+safety.aero
+scientist.aero
+services.aero
+show.aero
+skydiving.aero
+software.aero
+student.aero
+trader.aero
+trading.aero
+trainer.aero
+union.aero
+workinggroup.aero
+works.aero
+
+// af : http://www.nic.af/help.jsp
+af
+gov.af
+com.af
+org.af
+net.af
+edu.af
+
+// ag : http://www.nic.ag/prices.htm
+ag
+com.ag
+org.ag
+net.ag
+co.ag
+nom.ag
+
+// ai : http://nic.com.ai/
+ai
+off.ai
+com.ai
+net.ai
+org.ai
+
+// al : http://www.ert.gov.al/ert_alb/faq_det.html?Id=31
+al
+com.al
+edu.al
+gov.al
+mil.al
+net.al
+org.al
+
+// am : https://en.wikipedia.org/wiki/.am
+am
+
+// ao : https://en.wikipedia.org/wiki/.ao
+// http://www.dns.ao/REGISTR.DOC
+ao
+ed.ao
+gv.ao
+og.ao
+co.ao
+pb.ao
+it.ao
+
+// aq : https://en.wikipedia.org/wiki/.aq
+aq
+
+// ar : https://nic.ar/nic-argentina/normativa-vigente
+ar
+com.ar
+edu.ar
+gob.ar
+gov.ar
+int.ar
+mil.ar
+musica.ar
+net.ar
+org.ar
+tur.ar
+
+// arpa : https://en.wikipedia.org/wiki/.arpa
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+arpa
+e164.arpa
+in-addr.arpa
+ip6.arpa
+iris.arpa
+uri.arpa
+urn.arpa
+
+// as : https://en.wikipedia.org/wiki/.as
+as
+gov.as
+
+// asia : https://en.wikipedia.org/wiki/.asia
+asia
+
+// at : https://en.wikipedia.org/wiki/.at
+// Confirmed by registry <it@nic.at> 2008-06-17
+at
+ac.at
+co.at
+gv.at
+or.at
+
+// au : https://en.wikipedia.org/wiki/.au
+// http://www.auda.org.au/
+au
+// 2LDs
+com.au
+net.au
+org.au
+edu.au
+gov.au
+asn.au
+id.au
+// Historic 2LDs (closed to new registration, but sites still exist)
+info.au
+conf.au
+oz.au
+// CGDNs - http://www.cgdn.org.au/
+act.au
+nsw.au
+nt.au
+qld.au
+sa.au
+tas.au
+vic.au
+wa.au
+// 3LDs
+act.edu.au
+nsw.edu.au
+nt.edu.au
+qld.edu.au
+sa.edu.au
+tas.edu.au
+vic.edu.au
+wa.edu.au
+// act.gov.au Bug 984824 - Removed at request of Greg Tankard
+// nsw.gov.au Bug 547985 - Removed at request of <Shae.Donelan@services.nsw.gov.au>
+// nt.gov.au Bug 940478 - Removed at request of Greg Connors <Greg.Connors@nt.gov.au>
+qld.gov.au
+sa.gov.au
+tas.gov.au
+vic.gov.au
+wa.gov.au
+
+// aw : https://en.wikipedia.org/wiki/.aw
+aw
+com.aw
+
+// ax : https://en.wikipedia.org/wiki/.ax
+ax
+
+// az : https://en.wikipedia.org/wiki/.az
+az
+com.az
+net.az
+int.az
+gov.az
+org.az
+edu.az
+info.az
+pp.az
+mil.az
+name.az
+pro.az
+biz.az
+
+// ba : http://nic.ba/users_data/files/pravilnik_o_registraciji.pdf
+ba
+com.ba
+edu.ba
+gov.ba
+mil.ba
+net.ba
+org.ba
+
+// bb : https://en.wikipedia.org/wiki/.bb
+bb
+biz.bb
+co.bb
+com.bb
+edu.bb
+gov.bb
+info.bb
+net.bb
+org.bb
+store.bb
+tv.bb
+
+// bd : https://en.wikipedia.org/wiki/.bd
+*.bd
+
+// be : https://en.wikipedia.org/wiki/.be
+// Confirmed by registry <tech@dns.be> 2008-06-08
+be
+ac.be
+
+// bf : https://en.wikipedia.org/wiki/.bf
+bf
+gov.bf
+
+// bg : https://en.wikipedia.org/wiki/.bg
+// https://www.register.bg/user/static/rules/en/index.html
+bg
+a.bg
+b.bg
+c.bg
+d.bg
+e.bg
+f.bg
+g.bg
+h.bg
+i.bg
+j.bg
+k.bg
+l.bg
+m.bg
+n.bg
+o.bg
+p.bg
+q.bg
+r.bg
+s.bg
+t.bg
+u.bg
+v.bg
+w.bg
+x.bg
+y.bg
+z.bg
+0.bg
+1.bg
+2.bg
+3.bg
+4.bg
+5.bg
+6.bg
+7.bg
+8.bg
+9.bg
+
+// bh : https://en.wikipedia.org/wiki/.bh
+bh
+com.bh
+edu.bh
+net.bh
+org.bh
+gov.bh
+
+// bi : https://en.wikipedia.org/wiki/.bi
+// http://whois.nic.bi/
+bi
+co.bi
+com.bi
+edu.bi
+or.bi
+org.bi
+
+// biz : https://en.wikipedia.org/wiki/.biz
+biz
+
+// bj : https://en.wikipedia.org/wiki/.bj
+bj
+asso.bj
+barreau.bj
+gouv.bj
+
+// bm : http://www.bermudanic.bm/dnr-text.txt
+bm
+com.bm
+edu.bm
+gov.bm
+net.bm
+org.bm
+
+// bn : https://en.wikipedia.org/wiki/.bn
+*.bn
+
+// bo : http://www.nic.bo/
+bo
+com.bo
+edu.bo
+gov.bo
+gob.bo
+int.bo
+org.bo
+net.bo
+mil.bo
+tv.bo
+
+// br : http://registro.br/dominio/categoria.html
+// Submitted by registry <fneves@registro.br>
+br
+adm.br
+adv.br
+agr.br
+am.br
+arq.br
+art.br
+ato.br
+b.br
+belem.br
+bio.br
+blog.br
+bmd.br
+cim.br
+cng.br
+cnt.br
+com.br
+coop.br
+cri.br
+def.br
+ecn.br
+eco.br
+edu.br
+emp.br
+eng.br
+esp.br
+etc.br
+eti.br
+far.br
+flog.br
+floripa.br
+fm.br
+fnd.br
+fot.br
+fst.br
+g12.br
+ggf.br
+gov.br
+// gov.br 26 states + df https://en.wikipedia.org/wiki/States_of_Brazil
+ac.gov.br
+al.gov.br
+am.gov.br
+ap.gov.br
+ba.gov.br
+ce.gov.br
+df.gov.br
+es.gov.br
+go.gov.br
+ma.gov.br
+mg.gov.br
+ms.gov.br
+mt.gov.br
+pa.gov.br
+pb.gov.br
+pe.gov.br
+pi.gov.br
+pr.gov.br
+rj.gov.br
+rn.gov.br
+ro.gov.br
+rr.gov.br
+rs.gov.br
+sc.gov.br
+se.gov.br
+sp.gov.br
+to.gov.br
+imb.br
+ind.br
+inf.br
+jampa.br
+jor.br
+jus.br
+leg.br
+lel.br
+mat.br
+med.br
+mil.br
+mp.br
+mus.br
+net.br
+*.nom.br
+not.br
+ntr.br
+odo.br
+org.br
+poa.br
+ppg.br
+pro.br
+psc.br
+psi.br
+qsl.br
+radio.br
+rec.br
+recife.br
+slg.br
+srv.br
+taxi.br
+teo.br
+tmp.br
+trd.br
+tur.br
+tv.br
+vet.br
+vix.br
+vlog.br
+wiki.br
+zlg.br
+
+// bs : http://www.nic.bs/rules.html
+bs
+com.bs
+net.bs
+org.bs
+edu.bs
+gov.bs
+
+// bt : https://en.wikipedia.org/wiki/.bt
+bt
+com.bt
+edu.bt
+gov.bt
+net.bt
+org.bt
+
+// bv : No registrations at this time.
+// Submitted by registry <jarle@uninett.no>
+bv
+
+// bw : https://en.wikipedia.org/wiki/.bw
+// http://www.gobin.info/domainname/bw.doc
+// list of other 2nd level tlds ?
+bw
+co.bw
+org.bw
+
+// by : https://en.wikipedia.org/wiki/.by
+// http://tld.by/rules_2006_en.html
+// list of other 2nd level tlds ?
+by
+gov.by
+mil.by
+// Official information does not indicate that com.by is a reserved
+// second-level domain, but it's being used as one (see www.google.com.by and
+// www.yahoo.com.by, for example), so we list it here for safety's sake.
+com.by
+
+// http://hoster.by/
+of.by
+
+// bz : https://en.wikipedia.org/wiki/.bz
+// http://www.belizenic.bz/
+bz
+com.bz
+net.bz
+org.bz
+edu.bz
+gov.bz
+
+// ca : https://en.wikipedia.org/wiki/.ca
+ca
+// ca geographical names
+ab.ca
+bc.ca
+mb.ca
+nb.ca
+nf.ca
+nl.ca
+ns.ca
+nt.ca
+nu.ca
+on.ca
+pe.ca
+qc.ca
+sk.ca
+yk.ca
+// gc.ca: https://en.wikipedia.org/wiki/.gc.ca
+// see also: http://registry.gc.ca/en/SubdomainFAQ
+gc.ca
+
+// cat : https://en.wikipedia.org/wiki/.cat
+cat
+
+// cc : https://en.wikipedia.org/wiki/.cc
+cc
+
+// cd : https://en.wikipedia.org/wiki/.cd
+// see also: https://www.nic.cd/domain/insertDomain_2.jsp?act=1
+cd
+gov.cd
+
+// cf : https://en.wikipedia.org/wiki/.cf
+cf
+
+// cg : https://en.wikipedia.org/wiki/.cg
+cg
+
+// ch : https://en.wikipedia.org/wiki/.ch
+ch
+
+// ci : https://en.wikipedia.org/wiki/.ci
+// http://www.nic.ci/index.php?page=charte
+ci
+org.ci
+or.ci
+com.ci
+co.ci
+edu.ci
+ed.ci
+ac.ci
+net.ci
+go.ci
+asso.ci
+aéroport.ci
+int.ci
+presse.ci
+md.ci
+gouv.ci
+
+// ck : https://en.wikipedia.org/wiki/.ck
+*.ck
+!www.ck
+
+// cl : https://en.wikipedia.org/wiki/.cl
+cl
+gov.cl
+gob.cl
+co.cl
+mil.cl
+
+// cm : https://en.wikipedia.org/wiki/.cm plus bug 981927
+cm
+co.cm
+com.cm
+gov.cm
+net.cm
+
+// cn : https://en.wikipedia.org/wiki/.cn
+// Submitted by registry <tanyaling@cnnic.cn>
+cn
+ac.cn
+com.cn
+edu.cn
+gov.cn
+net.cn
+org.cn
+mil.cn
+公司.cn
+网络.cn
+網絡.cn
+// cn geographic names
+ah.cn
+bj.cn
+cq.cn
+fj.cn
+gd.cn
+gs.cn
+gz.cn
+gx.cn
+ha.cn
+hb.cn
+he.cn
+hi.cn
+hl.cn
+hn.cn
+jl.cn
+js.cn
+jx.cn
+ln.cn
+nm.cn
+nx.cn
+qh.cn
+sc.cn
+sd.cn
+sh.cn
+sn.cn
+sx.cn
+tj.cn
+xj.cn
+xz.cn
+yn.cn
+zj.cn
+hk.cn
+mo.cn
+tw.cn
+
+// co : https://en.wikipedia.org/wiki/.co
+// Submitted by registry <tecnico@uniandes.edu.co>
+co
+arts.co
+com.co
+edu.co
+firm.co
+gov.co
+info.co
+int.co
+mil.co
+net.co
+nom.co
+org.co
+rec.co
+web.co
+
+// com : https://en.wikipedia.org/wiki/.com
+com
+
+// coop : https://en.wikipedia.org/wiki/.coop
+coop
+
+// cr : http://www.nic.cr/niccr_publico/showRegistroDominiosScreen.do
+cr
+ac.cr
+co.cr
+ed.cr
+fi.cr
+go.cr
+or.cr
+sa.cr
+
+// cu : https://en.wikipedia.org/wiki/.cu
+cu
+com.cu
+edu.cu
+org.cu
+net.cu
+gov.cu
+inf.cu
+
+// cv : https://en.wikipedia.org/wiki/.cv
+cv
+
+// cw : http://www.una.cw/cw_registry/
+// Confirmed by registry <registry@una.net> 2013-03-26
+cw
+com.cw
+edu.cw
+net.cw
+org.cw
+
+// cx : https://en.wikipedia.org/wiki/.cx
+// list of other 2nd level tlds ?
+cx
+gov.cx
+
+// cy : http://www.nic.cy/
+// Submitted by registry Panayiotou Fotia <cydns@ucy.ac.cy>
+cy
+ac.cy
+biz.cy
+com.cy
+ekloges.cy
+gov.cy
+ltd.cy
+name.cy
+net.cy
+org.cy
+parliament.cy
+press.cy
+pro.cy
+tm.cy
+
+// cz : https://en.wikipedia.org/wiki/.cz
+cz
+
+// de : https://en.wikipedia.org/wiki/.de
+// Confirmed by registry <ops@denic.de> (with technical
+// reservations) 2008-07-01
+de
+
+// dj : https://en.wikipedia.org/wiki/.dj
+dj
+
+// dk : https://en.wikipedia.org/wiki/.dk
+// Confirmed by registry <robert@dk-hostmaster.dk> 2008-06-17
+dk
+
+// dm : https://en.wikipedia.org/wiki/.dm
+dm
+com.dm
+net.dm
+org.dm
+edu.dm
+gov.dm
+
+// do : https://en.wikipedia.org/wiki/.do
+do
+art.do
+com.do
+edu.do
+gob.do
+gov.do
+mil.do
+net.do
+org.do
+sld.do
+web.do
+
+// dz : https://en.wikipedia.org/wiki/.dz
+dz
+com.dz
+org.dz
+net.dz
+gov.dz
+edu.dz
+asso.dz
+pol.dz
+art.dz
+
+// ec : http://www.nic.ec/reg/paso1.asp
+// Submitted by registry <vabboud@nic.ec>
+ec
+com.ec
+info.ec
+net.ec
+fin.ec
+k12.ec
+med.ec
+pro.ec
+org.ec
+edu.ec
+gov.ec
+gob.ec
+mil.ec
+
+// edu : https://en.wikipedia.org/wiki/.edu
+edu
+
+// ee : http://www.eenet.ee/EENet/dom_reeglid.html#lisa_B
+ee
+edu.ee
+gov.ee
+riik.ee
+lib.ee
+med.ee
+com.ee
+pri.ee
+aip.ee
+org.ee
+fie.ee
+
+// eg : https://en.wikipedia.org/wiki/.eg
+eg
+com.eg
+edu.eg
+eun.eg
+gov.eg
+mil.eg
+name.eg
+net.eg
+org.eg
+sci.eg
+
+// er : https://en.wikipedia.org/wiki/.er
+*.er
+
+// es : https://www.nic.es/site_ingles/ingles/dominios/index.html
+es
+com.es
+nom.es
+org.es
+gob.es
+edu.es
+
+// et : https://en.wikipedia.org/wiki/.et
+et
+com.et
+gov.et
+org.et
+edu.et
+biz.et
+name.et
+info.et
+net.et
+
+// eu : https://en.wikipedia.org/wiki/.eu
+eu
+
+// fi : https://en.wikipedia.org/wiki/.fi
+fi
+// aland.fi : https://en.wikipedia.org/wiki/.ax
+// This domain is being phased out in favor of .ax. As there are still many
+// domains under aland.fi, we still keep it on the list until aland.fi is
+// completely removed.
+// TODO: Check for updates (expected to be phased out around Q1/2009)
+aland.fi
+
+// fj : https://en.wikipedia.org/wiki/.fj
+*.fj
+
+// fk : https://en.wikipedia.org/wiki/.fk
+*.fk
+
+// fm : https://en.wikipedia.org/wiki/.fm
+fm
+
+// fo : https://en.wikipedia.org/wiki/.fo
+fo
+
+// fr : http://www.afnic.fr/
+// domaines descriptifs : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-descriptifs
+fr
+com.fr
+asso.fr
+nom.fr
+prd.fr
+presse.fr
+tm.fr
+// domaines sectoriels : http://www.afnic.fr/obtenir/chartes/nommage-fr/annexe-sectoriels
+aeroport.fr
+assedic.fr
+avocat.fr
+avoues.fr
+cci.fr
+chambagri.fr
+chirurgiens-dentistes.fr
+experts-comptables.fr
+geometre-expert.fr
+gouv.fr
+greta.fr
+huissier-justice.fr
+medecin.fr
+notaires.fr
+pharmacien.fr
+port.fr
+veterinaire.fr
+
+// ga : https://en.wikipedia.org/wiki/.ga
+ga
+
+// gb : This registry is effectively dormant
+// Submitted by registry <Damien.Shaw@ja.net>
+gb
+
+// gd : https://en.wikipedia.org/wiki/.gd
+gd
+
+// ge : http://www.nic.net.ge/policy_en.pdf
+ge
+com.ge
+edu.ge
+gov.ge
+org.ge
+mil.ge
+net.ge
+pvt.ge
+
+// gf : https://en.wikipedia.org/wiki/.gf
+gf
+
+// gg : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel@channelisles.net> 2013-11-28
+gg
+co.gg
+net.gg
+org.gg
+
+// gh : https://en.wikipedia.org/wiki/.gh
+// see also: http://www.nic.gh/reg_now.php
+// Although domains directly at second level are not possible at the moment,
+// they have been possible for some time and may come back.
+gh
+com.gh
+edu.gh
+gov.gh
+org.gh
+mil.gh
+
+// gi : http://www.nic.gi/rules.html
+gi
+com.gi
+ltd.gi
+gov.gi
+mod.gi
+edu.gi
+org.gi
+
+// gl : https://en.wikipedia.org/wiki/.gl
+// http://nic.gl
+gl
+co.gl
+com.gl
+edu.gl
+net.gl
+org.gl
+
+// gm : http://www.nic.gm/htmlpages%5Cgm-policy.htm
+gm
+
+// gn : http://psg.com/dns/gn/gn.txt
+// Submitted by registry <randy@psg.com>
+gn
+ac.gn
+com.gn
+edu.gn
+gov.gn
+org.gn
+net.gn
+
+// gov : https://en.wikipedia.org/wiki/.gov
+gov
+
+// gp : http://www.nic.gp/index.php?lang=en
+gp
+com.gp
+net.gp
+mobi.gp
+edu.gp
+org.gp
+asso.gp
+
+// gq : https://en.wikipedia.org/wiki/.gq
+gq
+
+// gr : https://grweb.ics.forth.gr/english/1617-B-2005.html
+// Submitted by registry <segred@ics.forth.gr>
+gr
+com.gr
+edu.gr
+net.gr
+org.gr
+gov.gr
+
+// gs : https://en.wikipedia.org/wiki/.gs
+gs
+
+// gt : http://www.gt/politicas_de_registro.html
+gt
+com.gt
+edu.gt
+gob.gt
+ind.gt
+mil.gt
+net.gt
+org.gt
+
+// gu : http://gadao.gov.gu/registration.txt
+*.gu
+
+// gw : https://en.wikipedia.org/wiki/.gw
+gw
+
+// gy : https://en.wikipedia.org/wiki/.gy
+// http://registry.gy/
+gy
+co.gy
+com.gy
+edu.gy
+gov.gy
+net.gy
+org.gy
+
+// hk : https://www.hkdnr.hk
+// Submitted by registry <hk.tech@hkirc.hk>
+hk
+com.hk
+edu.hk
+gov.hk
+idv.hk
+net.hk
+org.hk
+公司.hk
+教育.hk
+敎育.hk
+政府.hk
+個人.hk
+个人.hk
+箇人.hk
+網络.hk
+网络.hk
+组織.hk
+網絡.hk
+网絡.hk
+组织.hk
+組織.hk
+組织.hk
+
+// hm : https://en.wikipedia.org/wiki/.hm
+hm
+
+// hn : http://www.nic.hn/politicas/ps02,,05.html
+hn
+com.hn
+edu.hn
+org.hn
+net.hn
+mil.hn
+gob.hn
+
+// hr : http://www.dns.hr/documents/pdf/HRTLD-regulations.pdf
+hr
+iz.hr
+from.hr
+name.hr
+com.hr
+
+// ht : http://www.nic.ht/info/charte.cfm
+ht
+com.ht
+shop.ht
+firm.ht
+info.ht
+adult.ht
+net.ht
+pro.ht
+org.ht
+med.ht
+art.ht
+coop.ht
+pol.ht
+asso.ht
+edu.ht
+rel.ht
+gouv.ht
+perso.ht
+
+// hu : http://www.domain.hu/domain/English/sld.html
+// Confirmed by registry <pasztor@iszt.hu> 2008-06-12
+hu
+co.hu
+info.hu
+org.hu
+priv.hu
+sport.hu
+tm.hu
+2000.hu
+agrar.hu
+bolt.hu
+casino.hu
+city.hu
+erotica.hu
+erotika.hu
+film.hu
+forum.hu
+games.hu
+hotel.hu
+ingatlan.hu
+jogasz.hu
+konyvelo.hu
+lakas.hu
+media.hu
+news.hu
+reklam.hu
+sex.hu
+shop.hu
+suli.hu
+szex.hu
+tozsde.hu
+utazas.hu
+video.hu
+
+// id : https://register.pandi.or.id/
+id
+ac.id
+biz.id
+co.id
+desa.id
+go.id
+mil.id
+my.id
+net.id
+or.id
+sch.id
+web.id
+
+// ie : https://en.wikipedia.org/wiki/.ie
+ie
+gov.ie
+
+// il : http://www.isoc.org.il/domains/
+il
+ac.il
+co.il
+gov.il
+idf.il
+k12.il
+muni.il
+net.il
+org.il
+
+// im : https://www.nic.im/
+// Submitted by registry <info@nic.im>
+im
+ac.im
+co.im
+com.im
+ltd.co.im
+net.im
+org.im
+plc.co.im
+tt.im
+tv.im
+
+// in : https://en.wikipedia.org/wiki/.in
+// see also: https://registry.in/Policies
+// Please note, that nic.in is not an official eTLD, but used by most
+// government institutions.
+in
+co.in
+firm.in
+net.in
+org.in
+gen.in
+ind.in
+nic.in
+ac.in
+edu.in
+res.in
+gov.in
+mil.in
+
+// info : https://en.wikipedia.org/wiki/.info
+info
+
+// int : https://en.wikipedia.org/wiki/.int
+// Confirmed by registry <iana-questions@icann.org> 2008-06-18
+int
+eu.int
+
+// io : http://www.nic.io/rules.html
+// list of other 2nd level tlds ?
+io
+com.io
+
+// iq : http://www.cmc.iq/english/iq/iqregister1.htm
+iq
+gov.iq
+edu.iq
+mil.iq
+com.iq
+org.iq
+net.iq
+
+// ir : http://www.nic.ir/Terms_and_Conditions_ir,_Appendix_1_Domain_Rules
+// Also see http://www.nic.ir/Internationalized_Domain_Names
+// Two <iran>.ir entries added at request of <tech-team@nic.ir>, 2010-04-16
+ir
+ac.ir
+co.ir
+gov.ir
+id.ir
+net.ir
+org.ir
+sch.ir
+// xn--mgba3a4f16a.ir (<iran>.ir, Persian YEH)
+ایران.ir
+// xn--mgba3a4fra.ir (<iran>.ir, Arabic YEH)
+ايران.ir
+
+// is : http://www.isnic.is/domain/rules.php
+// Confirmed by registry <marius@isgate.is> 2008-12-06
+is
+net.is
+com.is
+edu.is
+gov.is
+org.is
+int.is
+
+// it : https://en.wikipedia.org/wiki/.it
+it
+gov.it
+edu.it
+// Reserved geo-names:
+// http://www.nic.it/documenti/regolamenti-e-linee-guida/regolamento-assegnazione-versione-6.0.pdf
+// There is also a list of reserved geo-names corresponding to Italian municipalities
+// http://www.nic.it/documenti/appendice-c.pdf, but it is not included here.
+// Regions
+abr.it
+abruzzo.it
+aosta-valley.it
+aostavalley.it
+bas.it
+basilicata.it
+cal.it
+calabria.it
+cam.it
+campania.it
+emilia-romagna.it
+emiliaromagna.it
+emr.it
+friuli-v-giulia.it
+friuli-ve-giulia.it
+friuli-vegiulia.it
+friuli-venezia-giulia.it
+friuli-veneziagiulia.it
+friuli-vgiulia.it
+friuliv-giulia.it
+friulive-giulia.it
+friulivegiulia.it
+friulivenezia-giulia.it
+friuliveneziagiulia.it
+friulivgiulia.it
+fvg.it
+laz.it
+lazio.it
+lig.it
+liguria.it
+lom.it
+lombardia.it
+lombardy.it
+lucania.it
+mar.it
+marche.it
+mol.it
+molise.it
+piedmont.it
+piemonte.it
+pmn.it
+pug.it
+puglia.it
+sar.it
+sardegna.it
+sardinia.it
+sic.it
+sicilia.it
+sicily.it
+taa.it
+tos.it
+toscana.it
+trentino-a-adige.it
+trentino-aadige.it
+trentino-alto-adige.it
+trentino-altoadige.it
+trentino-s-tirol.it
+trentino-stirol.it
+trentino-sud-tirol.it
+trentino-sudtirol.it
+trentino-sued-tirol.it
+trentino-suedtirol.it
+trentinoa-adige.it
+trentinoaadige.it
+trentinoalto-adige.it
+trentinoaltoadige.it
+trentinos-tirol.it
+trentinostirol.it
+trentinosud-tirol.it
+trentinosudtirol.it
+trentinosued-tirol.it
+trentinosuedtirol.it
+tuscany.it
+umb.it
+umbria.it
+val-d-aosta.it
+val-daosta.it
+vald-aosta.it
+valdaosta.it
+valle-aosta.it
+valle-d-aosta.it
+valle-daosta.it
+valleaosta.it
+valled-aosta.it
+valledaosta.it
+vallee-aoste.it
+valleeaoste.it
+vao.it
+vda.it
+ven.it
+veneto.it
+// Provinces
+ag.it
+agrigento.it
+al.it
+alessandria.it
+alto-adige.it
+altoadige.it
+an.it
+ancona.it
+andria-barletta-trani.it
+andria-trani-barletta.it
+andriabarlettatrani.it
+andriatranibarletta.it
+ao.it
+aosta.it
+aoste.it
+ap.it
+aq.it
+aquila.it
+ar.it
+arezzo.it
+ascoli-piceno.it
+ascolipiceno.it
+asti.it
+at.it
+av.it
+avellino.it
+ba.it
+balsan.it
+bari.it
+barletta-trani-andria.it
+barlettatraniandria.it
+belluno.it
+benevento.it
+bergamo.it
+bg.it
+bi.it
+biella.it
+bl.it
+bn.it
+bo.it
+bologna.it
+bolzano.it
+bozen.it
+br.it
+brescia.it
+brindisi.it
+bs.it
+bt.it
+bz.it
+ca.it
+cagliari.it
+caltanissetta.it
+campidano-medio.it
+campidanomedio.it
+campobasso.it
+carbonia-iglesias.it
+carboniaiglesias.it
+carrara-massa.it
+carraramassa.it
+caserta.it
+catania.it
+catanzaro.it
+cb.it
+ce.it
+cesena-forli.it
+cesenaforli.it
+ch.it
+chieti.it
+ci.it
+cl.it
+cn.it
+co.it
+como.it
+cosenza.it
+cr.it
+cremona.it
+crotone.it
+cs.it
+ct.it
+cuneo.it
+cz.it
+dell-ogliastra.it
+dellogliastra.it
+en.it
+enna.it
+fc.it
+fe.it
+fermo.it
+ferrara.it
+fg.it
+fi.it
+firenze.it
+florence.it
+fm.it
+foggia.it
+forli-cesena.it
+forlicesena.it
+fr.it
+frosinone.it
+ge.it
+genoa.it
+genova.it
+go.it
+gorizia.it
+gr.it
+grosseto.it
+iglesias-carbonia.it
+iglesiascarbonia.it
+im.it
+imperia.it
+is.it
+isernia.it
+kr.it
+la-spezia.it
+laquila.it
+laspezia.it
+latina.it
+lc.it
+le.it
+lecce.it
+lecco.it
+li.it
+livorno.it
+lo.it
+lodi.it
+lt.it
+lu.it
+lucca.it
+macerata.it
+mantova.it
+massa-carrara.it
+massacarrara.it
+matera.it
+mb.it
+mc.it
+me.it
+medio-campidano.it
+mediocampidano.it
+messina.it
+mi.it
+milan.it
+milano.it
+mn.it
+mo.it
+modena.it
+monza-brianza.it
+monza-e-della-brianza.it
+monza.it
+monzabrianza.it
+monzaebrianza.it
+monzaedellabrianza.it
+ms.it
+mt.it
+na.it
+naples.it
+napoli.it
+no.it
+novara.it
+nu.it
+nuoro.it
+og.it
+ogliastra.it
+olbia-tempio.it
+olbiatempio.it
+or.it
+oristano.it
+ot.it
+pa.it
+padova.it
+padua.it
+palermo.it
+parma.it
+pavia.it
+pc.it
+pd.it
+pe.it
+perugia.it
+pesaro-urbino.it
+pesarourbino.it
+pescara.it
+pg.it
+pi.it
+piacenza.it
+pisa.it
+pistoia.it
+pn.it
+po.it
+pordenone.it
+potenza.it
+pr.it
+prato.it
+pt.it
+pu.it
+pv.it
+pz.it
+ra.it
+ragusa.it
+ravenna.it
+rc.it
+re.it
+reggio-calabria.it
+reggio-emilia.it
+reggiocalabria.it
+reggioemilia.it
+rg.it
+ri.it
+rieti.it
+rimini.it
+rm.it
+rn.it
+ro.it
+roma.it
+rome.it
+rovigo.it
+sa.it
+salerno.it
+sassari.it
+savona.it
+si.it
+siena.it
+siracusa.it
+so.it
+sondrio.it
+sp.it
+sr.it
+ss.it
+suedtirol.it
+sv.it
+ta.it
+taranto.it
+te.it
+tempio-olbia.it
+tempioolbia.it
+teramo.it
+terni.it
+tn.it
+to.it
+torino.it
+tp.it
+tr.it
+trani-andria-barletta.it
+trani-barletta-andria.it
+traniandriabarletta.it
+tranibarlettaandria.it
+trapani.it
+trentino.it
+trento.it
+treviso.it
+trieste.it
+ts.it
+turin.it
+tv.it
+ud.it
+udine.it
+urbino-pesaro.it
+urbinopesaro.it
+va.it
+varese.it
+vb.it
+vc.it
+ve.it
+venezia.it
+venice.it
+verbania.it
+vercelli.it
+verona.it
+vi.it
+vibo-valentia.it
+vibovalentia.it
+vicenza.it
+viterbo.it
+vr.it
+vs.it
+vt.it
+vv.it
+
+// je : http://www.channelisles.net/register-domains/
+// Confirmed by registry <nigel@channelisles.net> 2013-11-28
+je
+co.je
+net.je
+org.je
+
+// jm : http://www.com.jm/register.html
+*.jm
+
+// jo : http://www.dns.jo/Registration_policy.aspx
+jo
+com.jo
+org.jo
+net.jo
+edu.jo
+sch.jo
+gov.jo
+mil.jo
+name.jo
+
+// jobs : https://en.wikipedia.org/wiki/.jobs
+jobs
+
+// jp : https://en.wikipedia.org/wiki/.jp
+// http://jprs.co.jp/en/jpdomain.html
+// Submitted by registry <info@jprs.jp>
+jp
+// jp organizational type names
+ac.jp
+ad.jp
+co.jp
+ed.jp
+go.jp
+gr.jp
+lg.jp
+ne.jp
+or.jp
+// jp prefecture type names
+aichi.jp
+akita.jp
+aomori.jp
+chiba.jp
+ehime.jp
+fukui.jp
+fukuoka.jp
+fukushima.jp
+gifu.jp
+gunma.jp
+hiroshima.jp
+hokkaido.jp
+hyogo.jp
+ibaraki.jp
+ishikawa.jp
+iwate.jp
+kagawa.jp
+kagoshima.jp
+kanagawa.jp
+kochi.jp
+kumamoto.jp
+kyoto.jp
+mie.jp
+miyagi.jp
+miyazaki.jp
+nagano.jp
+nagasaki.jp
+nara.jp
+niigata.jp
+oita.jp
+okayama.jp
+okinawa.jp
+osaka.jp
+saga.jp
+saitama.jp
+shiga.jp
+shimane.jp
+shizuoka.jp
+tochigi.jp
+tokushima.jp
+tokyo.jp
+tottori.jp
+toyama.jp
+wakayama.jp
+yamagata.jp
+yamaguchi.jp
+yamanashi.jp
+栃木.jp
+愛知.jp
+愛媛.jp
+兵庫.jp
+熊本.jp
+茨城.jp
+北海道.jp
+千葉.jp
+和歌山.jp
+長崎.jp
+長野.jp
+新潟.jp
+青森.jp
+静岡.jp
+東京.jp
+石川.jp
+埼玉.jp
+三重.jp
+京都.jp
+佐賀.jp
+大分.jp
+大阪.jp
+奈良.jp
+宮城.jp
+宮崎.jp
+富山.jp
+山口.jp
+山形.jp
+山梨.jp
+岩手.jp
+岐阜.jp
+岡山.jp
+島根.jp
+広島.jp
+徳島.jp
+沖縄.jp
+滋賀.jp
+神奈川.jp
+福井.jp
+福岡.jp
+福島.jp
+秋田.jp
+群馬.jp
+香川.jp
+高知.jp
+鳥取.jp
+鹿児島.jp
+// jp geographic type names
+// http://jprs.jp/doc/rule/saisoku-1.html
+*.kawasaki.jp
+*.kitakyushu.jp
+*.kobe.jp
+*.nagoya.jp
+*.sapporo.jp
+*.sendai.jp
+*.yokohama.jp
+!city.kawasaki.jp
+!city.kitakyushu.jp
+!city.kobe.jp
+!city.nagoya.jp
+!city.sapporo.jp
+!city.sendai.jp
+!city.yokohama.jp
+// 4th level registration
+aisai.aichi.jp
+ama.aichi.jp
+anjo.aichi.jp
+asuke.aichi.jp
+chiryu.aichi.jp
+chita.aichi.jp
+fuso.aichi.jp
+gamagori.aichi.jp
+handa.aichi.jp
+hazu.aichi.jp
+hekinan.aichi.jp
+higashiura.aichi.jp
+ichinomiya.aichi.jp
+inazawa.aichi.jp
+inuyama.aichi.jp
+isshiki.aichi.jp
+iwakura.aichi.jp
+kanie.aichi.jp
+kariya.aichi.jp
+kasugai.aichi.jp
+kira.aichi.jp
+kiyosu.aichi.jp
+komaki.aichi.jp
+konan.aichi.jp
+kota.aichi.jp
+mihama.aichi.jp
+miyoshi.aichi.jp
+nishio.aichi.jp
+nisshin.aichi.jp
+obu.aichi.jp
+oguchi.aichi.jp
+oharu.aichi.jp
+okazaki.aichi.jp
+owariasahi.aichi.jp
+seto.aichi.jp
+shikatsu.aichi.jp
+shinshiro.aichi.jp
+shitara.aichi.jp
+tahara.aichi.jp
+takahama.aichi.jp
+tobishima.aichi.jp
+toei.aichi.jp
+togo.aichi.jp
+tokai.aichi.jp
+tokoname.aichi.jp
+toyoake.aichi.jp
+toyohashi.aichi.jp
+toyokawa.aichi.jp
+toyone.aichi.jp
+toyota.aichi.jp
+tsushima.aichi.jp
+yatomi.aichi.jp
+akita.akita.jp
+daisen.akita.jp
+fujisato.akita.jp
+gojome.akita.jp
+hachirogata.akita.jp
+happou.akita.jp
+higashinaruse.akita.jp
+honjo.akita.jp
+honjyo.akita.jp
+ikawa.akita.jp
+kamikoani.akita.jp
+kamioka.akita.jp
+katagami.akita.jp
+kazuno.akita.jp
+kitaakita.akita.jp
+kosaka.akita.jp
+kyowa.akita.jp
+misato.akita.jp
+mitane.akita.jp
+moriyoshi.akita.jp
+nikaho.akita.jp
+noshiro.akita.jp
+odate.akita.jp
+oga.akita.jp
+ogata.akita.jp
+semboku.akita.jp
+yokote.akita.jp
+yurihonjo.akita.jp
+aomori.aomori.jp
+gonohe.aomori.jp
+hachinohe.aomori.jp
+hashikami.aomori.jp
+hiranai.aomori.jp
+hirosaki.aomori.jp
+itayanagi.aomori.jp
+kuroishi.aomori.jp
+misawa.aomori.jp
+mutsu.aomori.jp
+nakadomari.aomori.jp
+noheji.aomori.jp
+oirase.aomori.jp
+owani.aomori.jp
+rokunohe.aomori.jp
+sannohe.aomori.jp
+shichinohe.aomori.jp
+shingo.aomori.jp
+takko.aomori.jp
+towada.aomori.jp
+tsugaru.aomori.jp
+tsuruta.aomori.jp
+abiko.chiba.jp
+asahi.chiba.jp
+chonan.chiba.jp
+chosei.chiba.jp
+choshi.chiba.jp
+chuo.chiba.jp
+funabashi.chiba.jp
+futtsu.chiba.jp
+hanamigawa.chiba.jp
+ichihara.chiba.jp
+ichikawa.chiba.jp
+ichinomiya.chiba.jp
+inzai.chiba.jp
+isumi.chiba.jp
+kamagaya.chiba.jp
+kamogawa.chiba.jp
+kashiwa.chiba.jp
+katori.chiba.jp
+katsuura.chiba.jp
+kimitsu.chiba.jp
+kisarazu.chiba.jp
+kozaki.chiba.jp
+kujukuri.chiba.jp
+kyonan.chiba.jp
+matsudo.chiba.jp
+midori.chiba.jp
+mihama.chiba.jp
+minamiboso.chiba.jp
+mobara.chiba.jp
+mutsuzawa.chiba.jp
+nagara.chiba.jp
+nagareyama.chiba.jp
+narashino.chiba.jp
+narita.chiba.jp
+noda.chiba.jp
+oamishirasato.chiba.jp
+omigawa.chiba.jp
+onjuku.chiba.jp
+otaki.chiba.jp
+sakae.chiba.jp
+sakura.chiba.jp
+shimofusa.chiba.jp
+shirako.chiba.jp
+shiroi.chiba.jp
+shisui.chiba.jp
+sodegaura.chiba.jp
+sosa.chiba.jp
+tako.chiba.jp
+tateyama.chiba.jp
+togane.chiba.jp
+tohnosho.chiba.jp
+tomisato.chiba.jp
+urayasu.chiba.jp
+yachimata.chiba.jp
+yachiyo.chiba.jp
+yokaichiba.chiba.jp
+yokoshibahikari.chiba.jp
+yotsukaido.chiba.jp
+ainan.ehime.jp
+honai.ehime.jp
+ikata.ehime.jp
+imabari.ehime.jp
+iyo.ehime.jp
+kamijima.ehime.jp
+kihoku.ehime.jp
+kumakogen.ehime.jp
+masaki.ehime.jp
+matsuno.ehime.jp
+matsuyama.ehime.jp
+namikata.ehime.jp
+niihama.ehime.jp
+ozu.ehime.jp
+saijo.ehime.jp
+seiyo.ehime.jp
+shikokuchuo.ehime.jp
+tobe.ehime.jp
+toon.ehime.jp
+uchiko.ehime.jp
+uwajima.ehime.jp
+yawatahama.ehime.jp
+echizen.fukui.jp
+eiheiji.fukui.jp
+fukui.fukui.jp
+ikeda.fukui.jp
+katsuyama.fukui.jp
+mihama.fukui.jp
+minamiechizen.fukui.jp
+obama.fukui.jp
+ohi.fukui.jp
+ono.fukui.jp
+sabae.fukui.jp
+sakai.fukui.jp
+takahama.fukui.jp
+tsuruga.fukui.jp
+wakasa.fukui.jp
+ashiya.fukuoka.jp
+buzen.fukuoka.jp
+chikugo.fukuoka.jp
+chikuho.fukuoka.jp
+chikujo.fukuoka.jp
+chikushino.fukuoka.jp
+chikuzen.fukuoka.jp
+chuo.fukuoka.jp
+dazaifu.fukuoka.jp
+fukuchi.fukuoka.jp
+hakata.fukuoka.jp
+higashi.fukuoka.jp
+hirokawa.fukuoka.jp
+hisayama.fukuoka.jp
+iizuka.fukuoka.jp
+inatsuki.fukuoka.jp
+kaho.fukuoka.jp
+kasuga.fukuoka.jp
+kasuya.fukuoka.jp
+kawara.fukuoka.jp
+keisen.fukuoka.jp
+koga.fukuoka.jp
+kurate.fukuoka.jp
+kurogi.fukuoka.jp
+kurume.fukuoka.jp
+minami.fukuoka.jp
+miyako.fukuoka.jp
+miyama.fukuoka.jp
+miyawaka.fukuoka.jp
+mizumaki.fukuoka.jp
+munakata.fukuoka.jp
+nakagawa.fukuoka.jp
+nakama.fukuoka.jp
+nishi.fukuoka.jp
+nogata.fukuoka.jp
+ogori.fukuoka.jp
+okagaki.fukuoka.jp
+okawa.fukuoka.jp
+oki.fukuoka.jp
+omuta.fukuoka.jp
+onga.fukuoka.jp
+onojo.fukuoka.jp
+oto.fukuoka.jp
+saigawa.fukuoka.jp
+sasaguri.fukuoka.jp
+shingu.fukuoka.jp
+shinyoshitomi.fukuoka.jp
+shonai.fukuoka.jp
+soeda.fukuoka.jp
+sue.fukuoka.jp
+tachiarai.fukuoka.jp
+tagawa.fukuoka.jp
+takata.fukuoka.jp
+toho.fukuoka.jp
+toyotsu.fukuoka.jp
+tsuiki.fukuoka.jp
+ukiha.fukuoka.jp
+umi.fukuoka.jp
+usui.fukuoka.jp
+yamada.fukuoka.jp
+yame.fukuoka.jp
+yanagawa.fukuoka.jp
+yukuhashi.fukuoka.jp
+aizubange.fukushima.jp
+aizumisato.fukushima.jp
+aizuwakamatsu.fukushima.jp
+asakawa.fukushima.jp
+bandai.fukushima.jp
+date.fukushima.jp
+fukushima.fukushima.jp
+furudono.fukushima.jp
+futaba.fukushima.jp
+hanawa.fukushima.jp
+higashi.fukushima.jp
+hirata.fukushima.jp
+hirono.fukushima.jp
+iitate.fukushima.jp
+inawashiro.fukushima.jp
+ishikawa.fukushima.jp
+iwaki.fukushima.jp
+izumizaki.fukushima.jp
+kagamiishi.fukushima.jp
+kaneyama.fukushima.jp
+kawamata.fukushima.jp
+kitakata.fukushima.jp
+kitashiobara.fukushima.jp
+koori.fukushima.jp
+koriyama.fukushima.jp
+kunimi.fukushima.jp
+miharu.fukushima.jp
+mishima.fukushima.jp
+namie.fukushima.jp
+nango.fukushima.jp
+nishiaizu.fukushima.jp
+nishigo.fukushima.jp
+okuma.fukushima.jp
+omotego.fukushima.jp
+ono.fukushima.jp
+otama.fukushima.jp
+samegawa.fukushima.jp
+shimogo.fukushima.jp
+shirakawa.fukushima.jp
+showa.fukushima.jp
+soma.fukushima.jp
+sukagawa.fukushima.jp
+taishin.fukushima.jp
+tamakawa.fukushima.jp
+tanagura.fukushima.jp
+tenei.fukushima.jp
+yabuki.fukushima.jp
+yamato.fukushima.jp
+yamatsuri.fukushima.jp
+yanaizu.fukushima.jp
+yugawa.fukushima.jp
+anpachi.gifu.jp
+ena.gifu.jp
+gifu.gifu.jp
+ginan.gifu.jp
+godo.gifu.jp
+gujo.gifu.jp
+hashima.gifu.jp
+hichiso.gifu.jp
+hida.gifu.jp
+higashishirakawa.gifu.jp
+ibigawa.gifu.jp
+ikeda.gifu.jp
+kakamigahara.gifu.jp
+kani.gifu.jp
+kasahara.gifu.jp
+kasamatsu.gifu.jp
+kawaue.gifu.jp
+kitagata.gifu.jp
+mino.gifu.jp
+minokamo.gifu.jp
+mitake.gifu.jp
+mizunami.gifu.jp
+motosu.gifu.jp
+nakatsugawa.gifu.jp
+ogaki.gifu.jp
+sakahogi.gifu.jp
+seki.gifu.jp
+sekigahara.gifu.jp
+shirakawa.gifu.jp
+tajimi.gifu.jp
+takayama.gifu.jp
+tarui.gifu.jp
+toki.gifu.jp
+tomika.gifu.jp
+wanouchi.gifu.jp
+yamagata.gifu.jp
+yaotsu.gifu.jp
+yoro.gifu.jp
+annaka.gunma.jp
+chiyoda.gunma.jp
+fujioka.gunma.jp
+higashiagatsuma.gunma.jp
+isesaki.gunma.jp
+itakura.gunma.jp
+kanna.gunma.jp
+kanra.gunma.jp
+katashina.gunma.jp
+kawaba.gunma.jp
+kiryu.gunma.jp
+kusatsu.gunma.jp
+maebashi.gunma.jp
+meiwa.gunma.jp
+midori.gunma.jp
+minakami.gunma.jp
+naganohara.gunma.jp
+nakanojo.gunma.jp
+nanmoku.gunma.jp
+numata.gunma.jp
+oizumi.gunma.jp
+ora.gunma.jp
+ota.gunma.jp
+shibukawa.gunma.jp
+shimonita.gunma.jp
+shinto.gunma.jp
+showa.gunma.jp
+takasaki.gunma.jp
+takayama.gunma.jp
+tamamura.gunma.jp
+tatebayashi.gunma.jp
+tomioka.gunma.jp
+tsukiyono.gunma.jp
+tsumagoi.gunma.jp
+ueno.gunma.jp
+yoshioka.gunma.jp
+asaminami.hiroshima.jp
+daiwa.hiroshima.jp
+etajima.hiroshima.jp
+fuchu.hiroshima.jp
+fukuyama.hiroshima.jp
+hatsukaichi.hiroshima.jp
+higashihiroshima.hiroshima.jp
+hongo.hiroshima.jp
+jinsekikogen.hiroshima.jp
+kaita.hiroshima.jp
+kui.hiroshima.jp
+kumano.hiroshima.jp
+kure.hiroshima.jp
+mihara.hiroshima.jp
+miyoshi.hiroshima.jp
+naka.hiroshima.jp
+onomichi.hiroshima.jp
+osakikamijima.hiroshima.jp
+otake.hiroshima.jp
+saka.hiroshima.jp
+sera.hiroshima.jp
+seranishi.hiroshima.jp
+shinichi.hiroshima.jp
+shobara.hiroshima.jp
+takehara.hiroshima.jp
+abashiri.hokkaido.jp
+abira.hokkaido.jp
+aibetsu.hokkaido.jp
+akabira.hokkaido.jp
+akkeshi.hokkaido.jp
+asahikawa.hokkaido.jp
+ashibetsu.hokkaido.jp
+ashoro.hokkaido.jp
+assabu.hokkaido.jp
+atsuma.hokkaido.jp
+bibai.hokkaido.jp
+biei.hokkaido.jp
+bifuka.hokkaido.jp
+bihoro.hokkaido.jp
+biratori.hokkaido.jp
+chippubetsu.hokkaido.jp
+chitose.hokkaido.jp
+date.hokkaido.jp
+ebetsu.hokkaido.jp
+embetsu.hokkaido.jp
+eniwa.hokkaido.jp
+erimo.hokkaido.jp
+esan.hokkaido.jp
+esashi.hokkaido.jp
+fukagawa.hokkaido.jp
+fukushima.hokkaido.jp
+furano.hokkaido.jp
+furubira.hokkaido.jp
+haboro.hokkaido.jp
+hakodate.hokkaido.jp
+hamatonbetsu.hokkaido.jp
+hidaka.hokkaido.jp
+higashikagura.hokkaido.jp
+higashikawa.hokkaido.jp
+hiroo.hokkaido.jp
+hokuryu.hokkaido.jp
+hokuto.hokkaido.jp
+honbetsu.hokkaido.jp
+horokanai.hokkaido.jp
+horonobe.hokkaido.jp
+ikeda.hokkaido.jp
+imakane.hokkaido.jp
+ishikari.hokkaido.jp
+iwamizawa.hokkaido.jp
+iwanai.hokkaido.jp
+kamifurano.hokkaido.jp
+kamikawa.hokkaido.jp
+kamishihoro.hokkaido.jp
+kamisunagawa.hokkaido.jp
+kamoenai.hokkaido.jp
+kayabe.hokkaido.jp
+kembuchi.hokkaido.jp
+kikonai.hokkaido.jp
+kimobetsu.hokkaido.jp
+kitahiroshima.hokkaido.jp
+kitami.hokkaido.jp
+kiyosato.hokkaido.jp
+koshimizu.hokkaido.jp
+kunneppu.hokkaido.jp
+kuriyama.hokkaido.jp
+kuromatsunai.hokkaido.jp
+kushiro.hokkaido.jp
+kutchan.hokkaido.jp
+kyowa.hokkaido.jp
+mashike.hokkaido.jp
+matsumae.hokkaido.jp
+mikasa.hokkaido.jp
+minamifurano.hokkaido.jp
+mombetsu.hokkaido.jp
+moseushi.hokkaido.jp
+mukawa.hokkaido.jp
+muroran.hokkaido.jp
+naie.hokkaido.jp
+nakagawa.hokkaido.jp
+nakasatsunai.hokkaido.jp
+nakatombetsu.hokkaido.jp
+nanae.hokkaido.jp
+nanporo.hokkaido.jp
+nayoro.hokkaido.jp
+nemuro.hokkaido.jp
+niikappu.hokkaido.jp
+niki.hokkaido.jp
+nishiokoppe.hokkaido.jp
+noboribetsu.hokkaido.jp
+numata.hokkaido.jp
+obihiro.hokkaido.jp
+obira.hokkaido.jp
+oketo.hokkaido.jp
+okoppe.hokkaido.jp
+otaru.hokkaido.jp
+otobe.hokkaido.jp
+otofuke.hokkaido.jp
+otoineppu.hokkaido.jp
+oumu.hokkaido.jp
+ozora.hokkaido.jp
+pippu.hokkaido.jp
+rankoshi.hokkaido.jp
+rebun.hokkaido.jp
+rikubetsu.hokkaido.jp
+rishiri.hokkaido.jp
+rishirifuji.hokkaido.jp
+saroma.hokkaido.jp
+sarufutsu.hokkaido.jp
+shakotan.hokkaido.jp
+shari.hokkaido.jp
+shibecha.hokkaido.jp
+shibetsu.hokkaido.jp
+shikabe.hokkaido.jp
+shikaoi.hokkaido.jp
+shimamaki.hokkaido.jp
+shimizu.hokkaido.jp
+shimokawa.hokkaido.jp
+shinshinotsu.hokkaido.jp
+shintoku.hokkaido.jp
+shiranuka.hokkaido.jp
+shiraoi.hokkaido.jp
+shiriuchi.hokkaido.jp
+sobetsu.hokkaido.jp
+sunagawa.hokkaido.jp
+taiki.hokkaido.jp
+takasu.hokkaido.jp
+takikawa.hokkaido.jp
+takinoue.hokkaido.jp
+teshikaga.hokkaido.jp
+tobetsu.hokkaido.jp
+tohma.hokkaido.jp
+tomakomai.hokkaido.jp
+tomari.hokkaido.jp
+toya.hokkaido.jp
+toyako.hokkaido.jp
+toyotomi.hokkaido.jp
+toyoura.hokkaido.jp
+tsubetsu.hokkaido.jp
+tsukigata.hokkaido.jp
+urakawa.hokkaido.jp
+urausu.hokkaido.jp
+uryu.hokkaido.jp
+utashinai.hokkaido.jp
+wakkanai.hokkaido.jp
+wassamu.hokkaido.jp
+yakumo.hokkaido.jp
+yoichi.hokkaido.jp
+aioi.hyogo.jp
+akashi.hyogo.jp
+ako.hyogo.jp
+amagasaki.hyogo.jp
+aogaki.hyogo.jp
+asago.hyogo.jp
+ashiya.hyogo.jp
+awaji.hyogo.jp
+fukusaki.hyogo.jp
+goshiki.hyogo.jp
+harima.hyogo.jp
+himeji.hyogo.jp
+ichikawa.hyogo.jp
+inagawa.hyogo.jp
+itami.hyogo.jp
+kakogawa.hyogo.jp
+kamigori.hyogo.jp
+kamikawa.hyogo.jp
+kasai.hyogo.jp
+kasuga.hyogo.jp
+kawanishi.hyogo.jp
+miki.hyogo.jp
+minamiawaji.hyogo.jp
+nishinomiya.hyogo.jp
+nishiwaki.hyogo.jp
+ono.hyogo.jp
+sanda.hyogo.jp
+sannan.hyogo.jp
+sasayama.hyogo.jp
+sayo.hyogo.jp
+shingu.hyogo.jp
+shinonsen.hyogo.jp
+shiso.hyogo.jp
+sumoto.hyogo.jp
+taishi.hyogo.jp
+taka.hyogo.jp
+takarazuka.hyogo.jp
+takasago.hyogo.jp
+takino.hyogo.jp
+tamba.hyogo.jp
+tatsuno.hyogo.jp
+toyooka.hyogo.jp
+yabu.hyogo.jp
+yashiro.hyogo.jp
+yoka.hyogo.jp
+yokawa.hyogo.jp
+ami.ibaraki.jp
+asahi.ibaraki.jp
+bando.ibaraki.jp
+chikusei.ibaraki.jp
+daigo.ibaraki.jp
+fujishiro.ibaraki.jp
+hitachi.ibaraki.jp
+hitachinaka.ibaraki.jp
+hitachiomiya.ibaraki.jp
+hitachiota.ibaraki.jp
+ibaraki.ibaraki.jp
+ina.ibaraki.jp
+inashiki.ibaraki.jp
+itako.ibaraki.jp
+iwama.ibaraki.jp
+joso.ibaraki.jp
+kamisu.ibaraki.jp
+kasama.ibaraki.jp
+kashima.ibaraki.jp
+kasumigaura.ibaraki.jp
+koga.ibaraki.jp
+miho.ibaraki.jp
+mito.ibaraki.jp
+moriya.ibaraki.jp
+naka.ibaraki.jp
+namegata.ibaraki.jp
+oarai.ibaraki.jp
+ogawa.ibaraki.jp
+omitama.ibaraki.jp
+ryugasaki.ibaraki.jp
+sakai.ibaraki.jp
+sakuragawa.ibaraki.jp
+shimodate.ibaraki.jp
+shimotsuma.ibaraki.jp
+shirosato.ibaraki.jp
+sowa.ibaraki.jp
+suifu.ibaraki.jp
+takahagi.ibaraki.jp
+tamatsukuri.ibaraki.jp
+tokai.ibaraki.jp
+tomobe.ibaraki.jp
+tone.ibaraki.jp
+toride.ibaraki.jp
+tsuchiura.ibaraki.jp
+tsukuba.ibaraki.jp
+uchihara.ibaraki.jp
+ushiku.ibaraki.jp
+yachiyo.ibaraki.jp
+yamagata.ibaraki.jp
+yawara.ibaraki.jp
+yuki.ibaraki.jp
+anamizu.ishikawa.jp
+hakui.ishikawa.jp
+hakusan.ishikawa.jp
+kaga.ishikawa.jp
+kahoku.ishikawa.jp
+kanazawa.ishikawa.jp
+kawakita.ishikawa.jp
+komatsu.ishikawa.jp
+nakanoto.ishikawa.jp
+nanao.ishikawa.jp
+nomi.ishikawa.jp
+nonoichi.ishikawa.jp
+noto.ishikawa.jp
+shika.ishikawa.jp
+suzu.ishikawa.jp
+tsubata.ishikawa.jp
+tsurugi.ishikawa.jp
+uchinada.ishikawa.jp
+wajima.ishikawa.jp
+fudai.iwate.jp
+fujisawa.iwate.jp
+hanamaki.iwate.jp
+hiraizumi.iwate.jp
+hirono.iwate.jp
+ichinohe.iwate.jp
+ichinoseki.iwate.jp
+iwaizumi.iwate.jp
+iwate.iwate.jp
+joboji.iwate.jp
+kamaishi.iwate.jp
+kanegasaki.iwate.jp
+karumai.iwate.jp
+kawai.iwate.jp
+kitakami.iwate.jp
+kuji.iwate.jp
+kunohe.iwate.jp
+kuzumaki.iwate.jp
+miyako.iwate.jp
+mizusawa.iwate.jp
+morioka.iwate.jp
+ninohe.iwate.jp
+noda.iwate.jp
+ofunato.iwate.jp
+oshu.iwate.jp
+otsuchi.iwate.jp
+rikuzentakata.iwate.jp
+shiwa.iwate.jp
+shizukuishi.iwate.jp
+sumita.iwate.jp
+tanohata.iwate.jp
+tono.iwate.jp
+yahaba.iwate.jp
+yamada.iwate.jp
+ayagawa.kagawa.jp
+higashikagawa.kagawa.jp
+kanonji.kagawa.jp
+kotohira.kagawa.jp
+manno.kagawa.jp
+marugame.kagawa.jp
+mitoyo.kagawa.jp
+naoshima.kagawa.jp
+sanuki.kagawa.jp
+tadotsu.kagawa.jp
+takamatsu.kagawa.jp
+tonosho.kagawa.jp
+uchinomi.kagawa.jp
+utazu.kagawa.jp
+zentsuji.kagawa.jp
+akune.kagoshima.jp
+amami.kagoshima.jp
+hioki.kagoshima.jp
+isa.kagoshima.jp
+isen.kagoshima.jp
+izumi.kagoshima.jp
+kagoshima.kagoshima.jp
+kanoya.kagoshima.jp
+kawanabe.kagoshima.jp
+kinko.kagoshima.jp
+kouyama.kagoshima.jp
+makurazaki.kagoshima.jp
+matsumoto.kagoshima.jp
+minamitane.kagoshima.jp
+nakatane.kagoshima.jp
+nishinoomote.kagoshima.jp
+satsumasendai.kagoshima.jp
+soo.kagoshima.jp
+tarumizu.kagoshima.jp
+yusui.kagoshima.jp
+aikawa.kanagawa.jp
+atsugi.kanagawa.jp
+ayase.kanagawa.jp
+chigasaki.kanagawa.jp
+ebina.kanagawa.jp
+fujisawa.kanagawa.jp
+hadano.kanagawa.jp
+hakone.kanagawa.jp
+hiratsuka.kanagawa.jp
+isehara.kanagawa.jp
+kaisei.kanagawa.jp
+kamakura.kanagawa.jp
+kiyokawa.kanagawa.jp
+matsuda.kanagawa.jp
+minamiashigara.kanagawa.jp
+miura.kanagawa.jp
+nakai.kanagawa.jp
+ninomiya.kanagawa.jp
+odawara.kanagawa.jp
+oi.kanagawa.jp
+oiso.kanagawa.jp
+sagamihara.kanagawa.jp
+samukawa.kanagawa.jp
+tsukui.kanagawa.jp
+yamakita.kanagawa.jp
+yamato.kanagawa.jp
+yokosuka.kanagawa.jp
+yugawara.kanagawa.jp
+zama.kanagawa.jp
+zushi.kanagawa.jp
+aki.kochi.jp
+geisei.kochi.jp
+hidaka.kochi.jp
+higashitsuno.kochi.jp
+ino.kochi.jp
+kagami.kochi.jp
+kami.kochi.jp
+kitagawa.kochi.jp
+kochi.kochi.jp
+mihara.kochi.jp
+motoyama.kochi.jp
+muroto.kochi.jp
+nahari.kochi.jp
+nakamura.kochi.jp
+nankoku.kochi.jp
+nishitosa.kochi.jp
+niyodogawa.kochi.jp
+ochi.kochi.jp
+okawa.kochi.jp
+otoyo.kochi.jp
+otsuki.kochi.jp
+sakawa.kochi.jp
+sukumo.kochi.jp
+susaki.kochi.jp
+tosa.kochi.jp
+tosashimizu.kochi.jp
+toyo.kochi.jp
+tsuno.kochi.jp
+umaji.kochi.jp
+yasuda.kochi.jp
+yusuhara.kochi.jp
+amakusa.kumamoto.jp
+arao.kumamoto.jp
+aso.kumamoto.jp
+choyo.kumamoto.jp
+gyokuto.kumamoto.jp
+kamiamakusa.kumamoto.jp
+kikuchi.kumamoto.jp
+kumamoto.kumamoto.jp
+mashiki.kumamoto.jp
+mifune.kumamoto.jp
+minamata.kumamoto.jp
+minamioguni.kumamoto.jp
+nagasu.kumamoto.jp
+nishihara.kumamoto.jp
+oguni.kumamoto.jp
+ozu.kumamoto.jp
+sumoto.kumamoto.jp
+takamori.kumamoto.jp
+uki.kumamoto.jp
+uto.kumamoto.jp
+yamaga.kumamoto.jp
+yamato.kumamoto.jp
+yatsushiro.kumamoto.jp
+ayabe.kyoto.jp
+fukuchiyama.kyoto.jp
+higashiyama.kyoto.jp
+ide.kyoto.jp
+ine.kyoto.jp
+joyo.kyoto.jp
+kameoka.kyoto.jp
+kamo.kyoto.jp
+kita.kyoto.jp
+kizu.kyoto.jp
+kumiyama.kyoto.jp
+kyotamba.kyoto.jp
+kyotanabe.kyoto.jp
+kyotango.kyoto.jp
+maizuru.kyoto.jp
+minami.kyoto.jp
+minamiyamashiro.kyoto.jp
+miyazu.kyoto.jp
+muko.kyoto.jp
+nagaokakyo.kyoto.jp
+nakagyo.kyoto.jp
+nantan.kyoto.jp
+oyamazaki.kyoto.jp
+sakyo.kyoto.jp
+seika.kyoto.jp
+tanabe.kyoto.jp
+uji.kyoto.jp
+ujitawara.kyoto.jp
+wazuka.kyoto.jp
+yamashina.kyoto.jp
+yawata.kyoto.jp
+asahi.mie.jp
+inabe.mie.jp
+ise.mie.jp
+kameyama.mie.jp
+kawagoe.mie.jp
+kiho.mie.jp
+kisosaki.mie.jp
+kiwa.mie.jp
+komono.mie.jp
+kumano.mie.jp
+kuwana.mie.jp
+matsusaka.mie.jp
+meiwa.mie.jp
+mihama.mie.jp
+minamiise.mie.jp
+misugi.mie.jp
+miyama.mie.jp
+nabari.mie.jp
+shima.mie.jp
+suzuka.mie.jp
+tado.mie.jp
+taiki.mie.jp
+taki.mie.jp
+tamaki.mie.jp
+toba.mie.jp
+tsu.mie.jp
+udono.mie.jp
+ureshino.mie.jp
+watarai.mie.jp
+yokkaichi.mie.jp
+furukawa.miyagi.jp
+higashimatsushima.miyagi.jp
+ishinomaki.miyagi.jp
+iwanuma.miyagi.jp
+kakuda.miyagi.jp
+kami.miyagi.jp
+kawasaki.miyagi.jp
+marumori.miyagi.jp
+matsushima.miyagi.jp
+minamisanriku.miyagi.jp
+misato.miyagi.jp
+murata.miyagi.jp
+natori.miyagi.jp
+ogawara.miyagi.jp
+ohira.miyagi.jp
+onagawa.miyagi.jp
+osaki.miyagi.jp
+rifu.miyagi.jp
+semine.miyagi.jp
+shibata.miyagi.jp
+shichikashuku.miyagi.jp
+shikama.miyagi.jp
+shiogama.miyagi.jp
+shiroishi.miyagi.jp
+tagajo.miyagi.jp
+taiwa.miyagi.jp
+tome.miyagi.jp
+tomiya.miyagi.jp
+wakuya.miyagi.jp
+watari.miyagi.jp
+yamamoto.miyagi.jp
+zao.miyagi.jp
+aya.miyazaki.jp
+ebino.miyazaki.jp
+gokase.miyazaki.jp
+hyuga.miyazaki.jp
+kadogawa.miyazaki.jp
+kawaminami.miyazaki.jp
+kijo.miyazaki.jp
+kitagawa.miyazaki.jp
+kitakata.miyazaki.jp
+kitaura.miyazaki.jp
+kobayashi.miyazaki.jp
+kunitomi.miyazaki.jp
+kushima.miyazaki.jp
+mimata.miyazaki.jp
+miyakonojo.miyazaki.jp
+miyazaki.miyazaki.jp
+morotsuka.miyazaki.jp
+nichinan.miyazaki.jp
+nishimera.miyazaki.jp
+nobeoka.miyazaki.jp
+saito.miyazaki.jp
+shiiba.miyazaki.jp
+shintomi.miyazaki.jp
+takaharu.miyazaki.jp
+takanabe.miyazaki.jp
+takazaki.miyazaki.jp
+tsuno.miyazaki.jp
+achi.nagano.jp
+agematsu.nagano.jp
+anan.nagano.jp
+aoki.nagano.jp
+asahi.nagano.jp
+azumino.nagano.jp
+chikuhoku.nagano.jp
+chikuma.nagano.jp
+chino.nagano.jp
+fujimi.nagano.jp
+hakuba.nagano.jp
+hara.nagano.jp
+hiraya.nagano.jp
+iida.nagano.jp
+iijima.nagano.jp
+iiyama.nagano.jp
+iizuna.nagano.jp
+ikeda.nagano.jp
+ikusaka.nagano.jp
+ina.nagano.jp
+karuizawa.nagano.jp
+kawakami.nagano.jp
+kiso.nagano.jp
+kisofukushima.nagano.jp
+kitaaiki.nagano.jp
+komagane.nagano.jp
+komoro.nagano.jp
+matsukawa.nagano.jp
+matsumoto.nagano.jp
+miasa.nagano.jp
+minamiaiki.nagano.jp
+minamimaki.nagano.jp
+minamiminowa.nagano.jp
+minowa.nagano.jp
+miyada.nagano.jp
+miyota.nagano.jp
+mochizuki.nagano.jp
+nagano.nagano.jp
+nagawa.nagano.jp
+nagiso.nagano.jp
+nakagawa.nagano.jp
+nakano.nagano.jp
+nozawaonsen.nagano.jp
+obuse.nagano.jp
+ogawa.nagano.jp
+okaya.nagano.jp
+omachi.nagano.jp
+omi.nagano.jp
+ookuwa.nagano.jp
+ooshika.nagano.jp
+otaki.nagano.jp
+otari.nagano.jp
+sakae.nagano.jp
+sakaki.nagano.jp
+saku.nagano.jp
+sakuho.nagano.jp
+shimosuwa.nagano.jp
+shinanomachi.nagano.jp
+shiojiri.nagano.jp
+suwa.nagano.jp
+suzaka.nagano.jp
+takagi.nagano.jp
+takamori.nagano.jp
+takayama.nagano.jp
+tateshina.nagano.jp
+tatsuno.nagano.jp
+togakushi.nagano.jp
+togura.nagano.jp
+tomi.nagano.jp
+ueda.nagano.jp
+wada.nagano.jp
+yamagata.nagano.jp
+yamanouchi.nagano.jp
+yasaka.nagano.jp
+yasuoka.nagano.jp
+chijiwa.nagasaki.jp
+futsu.nagasaki.jp
+goto.nagasaki.jp
+hasami.nagasaki.jp
+hirado.nagasaki.jp
+iki.nagasaki.jp
+isahaya.nagasaki.jp
+kawatana.nagasaki.jp
+kuchinotsu.nagasaki.jp
+matsuura.nagasaki.jp
+nagasaki.nagasaki.jp
+obama.nagasaki.jp
+omura.nagasaki.jp
+oseto.nagasaki.jp
+saikai.nagasaki.jp
+sasebo.nagasaki.jp
+seihi.nagasaki.jp
+shimabara.nagasaki.jp
+shinkamigoto.nagasaki.jp
+togitsu.nagasaki.jp
+tsushima.nagasaki.jp
+unzen.nagasaki.jp
+ando.nara.jp
+gose.nara.jp
+heguri.nara.jp
+higashiyoshino.nara.jp
+ikaruga.nara.jp
+ikoma.nara.jp
+kamikitayama.nara.jp
+kanmaki.nara.jp
+kashiba.nara.jp
+kashihara.nara.jp
+katsuragi.nara.jp
+kawai.nara.jp
+kawakami.nara.jp
+kawanishi.nara.jp
+koryo.nara.jp
+kurotaki.nara.jp
+mitsue.nara.jp
+miyake.nara.jp
+nara.nara.jp
+nosegawa.nara.jp
+oji.nara.jp
+ouda.nara.jp
+oyodo.nara.jp
+sakurai.nara.jp
+sango.nara.jp
+shimoichi.nara.jp
+shimokitayama.nara.jp
+shinjo.nara.jp
+soni.nara.jp
+takatori.nara.jp
+tawaramoto.nara.jp
+tenkawa.nara.jp
+tenri.nara.jp
+uda.nara.jp
+yamatokoriyama.nara.jp
+yamatotakada.nara.jp
+yamazoe.nara.jp
+yoshino.nara.jp
+aga.niigata.jp
+agano.niigata.jp
+gosen.niigata.jp
+itoigawa.niigata.jp
+izumozaki.niigata.jp
+joetsu.niigata.jp
+kamo.niigata.jp
+kariwa.niigata.jp
+kashiwazaki.niigata.jp
+minamiuonuma.niigata.jp
+mitsuke.niigata.jp
+muika.niigata.jp
+murakami.niigata.jp
+myoko.niigata.jp
+nagaoka.niigata.jp
+niigata.niigata.jp
+ojiya.niigata.jp
+omi.niigata.jp
+sado.niigata.jp
+sanjo.niigata.jp
+seiro.niigata.jp
+seirou.niigata.jp
+sekikawa.niigata.jp
+shibata.niigata.jp
+tagami.niigata.jp
+tainai.niigata.jp
+tochio.niigata.jp
+tokamachi.niigata.jp
+tsubame.niigata.jp
+tsunan.niigata.jp
+uonuma.niigata.jp
+yahiko.niigata.jp
+yoita.niigata.jp
+yuzawa.niigata.jp
+beppu.oita.jp
+bungoono.oita.jp
+bungotakada.oita.jp
+hasama.oita.jp
+hiji.oita.jp
+himeshima.oita.jp
+hita.oita.jp
+kamitsue.oita.jp
+kokonoe.oita.jp
+kuju.oita.jp
+kunisaki.oita.jp
+kusu.oita.jp
+oita.oita.jp
+saiki.oita.jp
+taketa.oita.jp
+tsukumi.oita.jp
+usa.oita.jp
+usuki.oita.jp
+yufu.oita.jp
+akaiwa.okayama.jp
+asakuchi.okayama.jp
+bizen.okayama.jp
+hayashima.okayama.jp
+ibara.okayama.jp
+kagamino.okayama.jp
+kasaoka.okayama.jp
+kibichuo.okayama.jp
+kumenan.okayama.jp
+kurashiki.okayama.jp
+maniwa.okayama.jp
+misaki.okayama.jp
+nagi.okayama.jp
+niimi.okayama.jp
+nishiawakura.okayama.jp
+okayama.okayama.jp
+satosho.okayama.jp
+setouchi.okayama.jp
+shinjo.okayama.jp
+shoo.okayama.jp
+soja.okayama.jp
+takahashi.okayama.jp
+tamano.okayama.jp
+tsuyama.okayama.jp
+wake.okayama.jp
+yakage.okayama.jp
+aguni.okinawa.jp
+ginowan.okinawa.jp
+ginoza.okinawa.jp
+gushikami.okinawa.jp
+haebaru.okinawa.jp
+higashi.okinawa.jp
+hirara.okinawa.jp
+iheya.okinawa.jp
+ishigaki.okinawa.jp
+ishikawa.okinawa.jp
+itoman.okinawa.jp
+izena.okinawa.jp
+kadena.okinawa.jp
+kin.okinawa.jp
+kitadaito.okinawa.jp
+kitanakagusuku.okinawa.jp
+kumejima.okinawa.jp
+kunigami.okinawa.jp
+minamidaito.okinawa.jp
+motobu.okinawa.jp
+nago.okinawa.jp
+naha.okinawa.jp
+nakagusuku.okinawa.jp
+nakijin.okinawa.jp
+nanjo.okinawa.jp
+nishihara.okinawa.jp
+ogimi.okinawa.jp
+okinawa.okinawa.jp
+onna.okinawa.jp
+shimoji.okinawa.jp
+taketomi.okinawa.jp
+tarama.okinawa.jp
+tokashiki.okinawa.jp
+tomigusuku.okinawa.jp
+tonaki.okinawa.jp
+urasoe.okinawa.jp
+uruma.okinawa.jp
+yaese.okinawa.jp
+yomitan.okinawa.jp
+yonabaru.okinawa.jp
+yonaguni.okinawa.jp
+zamami.okinawa.jp
+abeno.osaka.jp
+chihayaakasaka.osaka.jp
+chuo.osaka.jp
+daito.osaka.jp
+fujiidera.osaka.jp
+habikino.osaka.jp
+hannan.osaka.jp
+higashiosaka.osaka.jp
+higashisumiyoshi.osaka.jp
+higashiyodogawa.osaka.jp
+hirakata.osaka.jp
+ibaraki.osaka.jp
+ikeda.osaka.jp
+izumi.osaka.jp
+izumiotsu.osaka.jp
+izumisano.osaka.jp
+kadoma.osaka.jp
+kaizuka.osaka.jp
+kanan.osaka.jp
+kashiwara.osaka.jp
+katano.osaka.jp
+kawachinagano.osaka.jp
+kishiwada.osaka.jp
+kita.osaka.jp
+kumatori.osaka.jp
+matsubara.osaka.jp
+minato.osaka.jp
+minoh.osaka.jp
+misaki.osaka.jp
+moriguchi.osaka.jp
+neyagawa.osaka.jp
+nishi.osaka.jp
+nose.osaka.jp
+osakasayama.osaka.jp
+sakai.osaka.jp
+sayama.osaka.jp
+sennan.osaka.jp
+settsu.osaka.jp
+shijonawate.osaka.jp
+shimamoto.osaka.jp
+suita.osaka.jp
+tadaoka.osaka.jp
+taishi.osaka.jp
+tajiri.osaka.jp
+takaishi.osaka.jp
+takatsuki.osaka.jp
+tondabayashi.osaka.jp
+toyonaka.osaka.jp
+toyono.osaka.jp
+yao.osaka.jp
+ariake.saga.jp
+arita.saga.jp
+fukudomi.saga.jp
+genkai.saga.jp
+hamatama.saga.jp
+hizen.saga.jp
+imari.saga.jp
+kamimine.saga.jp
+kanzaki.saga.jp
+karatsu.saga.jp
+kashima.saga.jp
+kitagata.saga.jp
+kitahata.saga.jp
+kiyama.saga.jp
+kouhoku.saga.jp
+kyuragi.saga.jp
+nishiarita.saga.jp
+ogi.saga.jp
+omachi.saga.jp
+ouchi.saga.jp
+saga.saga.jp
+shiroishi.saga.jp
+taku.saga.jp
+tara.saga.jp
+tosu.saga.jp
+yoshinogari.saga.jp
+arakawa.saitama.jp
+asaka.saitama.jp
+chichibu.saitama.jp
+fujimi.saitama.jp
+fujimino.saitama.jp
+fukaya.saitama.jp
+hanno.saitama.jp
+hanyu.saitama.jp
+hasuda.saitama.jp
+hatogaya.saitama.jp
+hatoyama.saitama.jp
+hidaka.saitama.jp
+higashichichibu.saitama.jp
+higashimatsuyama.saitama.jp
+honjo.saitama.jp
+ina.saitama.jp
+iruma.saitama.jp
+iwatsuki.saitama.jp
+kamiizumi.saitama.jp
+kamikawa.saitama.jp
+kamisato.saitama.jp
+kasukabe.saitama.jp
+kawagoe.saitama.jp
+kawaguchi.saitama.jp
+kawajima.saitama.jp
+kazo.saitama.jp
+kitamoto.saitama.jp
+koshigaya.saitama.jp
+kounosu.saitama.jp
+kuki.saitama.jp
+kumagaya.saitama.jp
+matsubushi.saitama.jp
+minano.saitama.jp
+misato.saitama.jp
+miyashiro.saitama.jp
+miyoshi.saitama.jp
+moroyama.saitama.jp
+nagatoro.saitama.jp
+namegawa.saitama.jp
+niiza.saitama.jp
+ogano.saitama.jp
+ogawa.saitama.jp
+ogose.saitama.jp
+okegawa.saitama.jp
+omiya.saitama.jp
+otaki.saitama.jp
+ranzan.saitama.jp
+ryokami.saitama.jp
+saitama.saitama.jp
+sakado.saitama.jp
+satte.saitama.jp
+sayama.saitama.jp
+shiki.saitama.jp
+shiraoka.saitama.jp
+soka.saitama.jp
+sugito.saitama.jp
+toda.saitama.jp
+tokigawa.saitama.jp
+tokorozawa.saitama.jp
+tsurugashima.saitama.jp
+urawa.saitama.jp
+warabi.saitama.jp
+yashio.saitama.jp
+yokoze.saitama.jp
+yono.saitama.jp
+yorii.saitama.jp
+yoshida.saitama.jp
+yoshikawa.saitama.jp
+yoshimi.saitama.jp
+aisho.shiga.jp
+gamo.shiga.jp
+higashiomi.shiga.jp
+hikone.shiga.jp
+koka.shiga.jp
+konan.shiga.jp
+kosei.shiga.jp
+koto.shiga.jp
+kusatsu.shiga.jp
+maibara.shiga.jp
+moriyama.shiga.jp
+nagahama.shiga.jp
+nishiazai.shiga.jp
+notogawa.shiga.jp
+omihachiman.shiga.jp
+otsu.shiga.jp
+ritto.shiga.jp
+ryuoh.shiga.jp
+takashima.shiga.jp
+takatsuki.shiga.jp
+torahime.shiga.jp
+toyosato.shiga.jp
+yasu.shiga.jp
+akagi.shimane.jp
+ama.shimane.jp
+gotsu.shimane.jp
+hamada.shimane.jp
+higashiizumo.shimane.jp
+hikawa.shimane.jp
+hikimi.shimane.jp
+izumo.shimane.jp
+kakinoki.shimane.jp
+masuda.shimane.jp
+matsue.shimane.jp
+misato.shimane.jp
+nishinoshima.shimane.jp
+ohda.shimane.jp
+okinoshima.shimane.jp
+okuizumo.shimane.jp
+shimane.shimane.jp
+tamayu.shimane.jp
+tsuwano.shimane.jp
+unnan.shimane.jp
+yakumo.shimane.jp
+yasugi.shimane.jp
+yatsuka.shimane.jp
+arai.shizuoka.jp
+atami.shizuoka.jp
+fuji.shizuoka.jp
+fujieda.shizuoka.jp
+fujikawa.shizuoka.jp
+fujinomiya.shizuoka.jp
+fukuroi.shizuoka.jp
+gotemba.shizuoka.jp
+haibara.shizuoka.jp
+hamamatsu.shizuoka.jp
+higashiizu.shizuoka.jp
+ito.shizuoka.jp
+iwata.shizuoka.jp
+izu.shizuoka.jp
+izunokuni.shizuoka.jp
+kakegawa.shizuoka.jp
+kannami.shizuoka.jp
+kawanehon.shizuoka.jp
+kawazu.shizuoka.jp
+kikugawa.shizuoka.jp
+kosai.shizuoka.jp
+makinohara.shizuoka.jp
+matsuzaki.shizuoka.jp
+minamiizu.shizuoka.jp
+mishima.shizuoka.jp
+morimachi.shizuoka.jp
+nishiizu.shizuoka.jp
+numazu.shizuoka.jp
+omaezaki.shizuoka.jp
+shimada.shizuoka.jp
+shimizu.shizuoka.jp
+shimoda.shizuoka.jp
+shizuoka.shizuoka.jp
+susono.shizuoka.jp
+yaizu.shizuoka.jp
+yoshida.shizuoka.jp
+ashikaga.tochigi.jp
+bato.tochigi.jp
+haga.tochigi.jp
+ichikai.tochigi.jp
+iwafune.tochigi.jp
+kaminokawa.tochigi.jp
+kanuma.tochigi.jp
+karasuyama.tochigi.jp
+kuroiso.tochigi.jp
+mashiko.tochigi.jp
+mibu.tochigi.jp
+moka.tochigi.jp
+motegi.tochigi.jp
+nasu.tochigi.jp
+nasushiobara.tochigi.jp
+nikko.tochigi.jp
+nishikata.tochigi.jp
+nogi.tochigi.jp
+ohira.tochigi.jp
+ohtawara.tochigi.jp
+oyama.tochigi.jp
+sakura.tochigi.jp
+sano.tochigi.jp
+shimotsuke.tochigi.jp
+shioya.tochigi.jp
+takanezawa.tochigi.jp
+tochigi.tochigi.jp
+tsuga.tochigi.jp
+ujiie.tochigi.jp
+utsunomiya.tochigi.jp
+yaita.tochigi.jp
+aizumi.tokushima.jp
+anan.tokushima.jp
+ichiba.tokushima.jp
+itano.tokushima.jp
+kainan.tokushima.jp
+komatsushima.tokushima.jp
+matsushige.tokushima.jp
+mima.tokushima.jp
+minami.tokushima.jp
+miyoshi.tokushima.jp
+mugi.tokushima.jp
+nakagawa.tokushima.jp
+naruto.tokushima.jp
+sanagochi.tokushima.jp
+shishikui.tokushima.jp
+tokushima.tokushima.jp
+wajiki.tokushima.jp
+adachi.tokyo.jp
+akiruno.tokyo.jp
+akishima.tokyo.jp
+aogashima.tokyo.jp
+arakawa.tokyo.jp
+bunkyo.tokyo.jp
+chiyoda.tokyo.jp
+chofu.tokyo.jp
+chuo.tokyo.jp
+edogawa.tokyo.jp
+fuchu.tokyo.jp
+fussa.tokyo.jp
+hachijo.tokyo.jp
+hachioji.tokyo.jp
+hamura.tokyo.jp
+higashikurume.tokyo.jp
+higashimurayama.tokyo.jp
+higashiyamato.tokyo.jp
+hino.tokyo.jp
+hinode.tokyo.jp
+hinohara.tokyo.jp
+inagi.tokyo.jp
+itabashi.tokyo.jp
+katsushika.tokyo.jp
+kita.tokyo.jp
+kiyose.tokyo.jp
+kodaira.tokyo.jp
+koganei.tokyo.jp
+kokubunji.tokyo.jp
+komae.tokyo.jp
+koto.tokyo.jp
+kouzushima.tokyo.jp
+kunitachi.tokyo.jp
+machida.tokyo.jp
+meguro.tokyo.jp
+minato.tokyo.jp
+mitaka.tokyo.jp
+mizuho.tokyo.jp
+musashimurayama.tokyo.jp
+musashino.tokyo.jp
+nakano.tokyo.jp
+nerima.tokyo.jp
+ogasawara.tokyo.jp
+okutama.tokyo.jp
+ome.tokyo.jp
+oshima.tokyo.jp
+ota.tokyo.jp
+setagaya.tokyo.jp
+shibuya.tokyo.jp
+shinagawa.tokyo.jp
+shinjuku.tokyo.jp
+suginami.tokyo.jp
+sumida.tokyo.jp
+tachikawa.tokyo.jp
+taito.tokyo.jp
+tama.tokyo.jp
+toshima.tokyo.jp
+chizu.tottori.jp
+hino.tottori.jp
+kawahara.tottori.jp
+koge.tottori.jp
+kotoura.tottori.jp
+misasa.tottori.jp
+nanbu.tottori.jp
+nichinan.tottori.jp
+sakaiminato.tottori.jp
+tottori.tottori.jp
+wakasa.tottori.jp
+yazu.tottori.jp
+yonago.tottori.jp
+asahi.toyama.jp
+fuchu.toyama.jp
+fukumitsu.toyama.jp
+funahashi.toyama.jp
+himi.toyama.jp
+imizu.toyama.jp
+inami.toyama.jp
+johana.toyama.jp
+kamiichi.toyama.jp
+kurobe.toyama.jp
+nakaniikawa.toyama.jp
+namerikawa.toyama.jp
+nanto.toyama.jp
+nyuzen.toyama.jp
+oyabe.toyama.jp
+taira.toyama.jp
+takaoka.toyama.jp
+tateyama.toyama.jp
+toga.toyama.jp
+tonami.toyama.jp
+toyama.toyama.jp
+unazuki.toyama.jp
+uozu.toyama.jp
+yamada.toyama.jp
+arida.wakayama.jp
+aridagawa.wakayama.jp
+gobo.wakayama.jp
+hashimoto.wakayama.jp
+hidaka.wakayama.jp
+hirogawa.wakayama.jp
+inami.wakayama.jp
+iwade.wakayama.jp
+kainan.wakayama.jp
+kamitonda.wakayama.jp
+katsuragi.wakayama.jp
+kimino.wakayama.jp
+kinokawa.wakayama.jp
+kitayama.wakayama.jp
+koya.wakayama.jp
+koza.wakayama.jp
+kozagawa.wakayama.jp
+kudoyama.wakayama.jp
+kushimoto.wakayama.jp
+mihama.wakayama.jp
+misato.wakayama.jp
+nachikatsuura.wakayama.jp
+shingu.wakayama.jp
+shirahama.wakayama.jp
+taiji.wakayama.jp
+tanabe.wakayama.jp
+wakayama.wakayama.jp
+yuasa.wakayama.jp
+yura.wakayama.jp
+asahi.yamagata.jp
+funagata.yamagata.jp
+higashine.yamagata.jp
+iide.yamagata.jp
+kahoku.yamagata.jp
+kaminoyama.yamagata.jp
+kaneyama.yamagata.jp
+kawanishi.yamagata.jp
+mamurogawa.yamagata.jp
+mikawa.yamagata.jp
+murayama.yamagata.jp
+nagai.yamagata.jp
+nakayama.yamagata.jp
+nanyo.yamagata.jp
+nishikawa.yamagata.jp
+obanazawa.yamagata.jp
+oe.yamagata.jp
+oguni.yamagata.jp
+ohkura.yamagata.jp
+oishida.yamagata.jp
+sagae.yamagata.jp
+sakata.yamagata.jp
+sakegawa.yamagata.jp
+shinjo.yamagata.jp
+shirataka.yamagata.jp
+shonai.yamagata.jp
+takahata.yamagata.jp
+tendo.yamagata.jp
+tozawa.yamagata.jp
+tsuruoka.yamagata.jp
+yamagata.yamagata.jp
+yamanobe.yamagata.jp
+yonezawa.yamagata.jp
+yuza.yamagata.jp
+abu.yamaguchi.jp
+hagi.yamaguchi.jp
+hikari.yamaguchi.jp
+hofu.yamaguchi.jp
+iwakuni.yamaguchi.jp
+kudamatsu.yamaguchi.jp
+mitou.yamaguchi.jp
+nagato.yamaguchi.jp
+oshima.yamaguchi.jp
+shimonoseki.yamaguchi.jp
+shunan.yamaguchi.jp
+tabuse.yamaguchi.jp
+tokuyama.yamaguchi.jp
+toyota.yamaguchi.jp
+ube.yamaguchi.jp
+yuu.yamaguchi.jp
+chuo.yamanashi.jp
+doshi.yamanashi.jp
+fuefuki.yamanashi.jp
+fujikawa.yamanashi.jp
+fujikawaguchiko.yamanashi.jp
+fujiyoshida.yamanashi.jp
+hayakawa.yamanashi.jp
+hokuto.yamanashi.jp
+ichikawamisato.yamanashi.jp
+kai.yamanashi.jp
+kofu.yamanashi.jp
+koshu.yamanashi.jp
+kosuge.yamanashi.jp
+minami-alps.yamanashi.jp
+minobu.yamanashi.jp
+nakamichi.yamanashi.jp
+nanbu.yamanashi.jp
+narusawa.yamanashi.jp
+nirasaki.yamanashi.jp
+nishikatsura.yamanashi.jp
+oshino.yamanashi.jp
+otsuki.yamanashi.jp
+showa.yamanashi.jp
+tabayama.yamanashi.jp
+tsuru.yamanashi.jp
+uenohara.yamanashi.jp
+yamanakako.yamanashi.jp
+yamanashi.yamanashi.jp
+
+// ke : http://www.kenic.or.ke/index.php?option=com_content&task=view&id=117&Itemid=145
+*.ke
+
+// kg : http://www.domain.kg/dmn_n.html
+kg
+org.kg
+net.kg
+com.kg
+edu.kg
+gov.kg
+mil.kg
+
+// kh : http://www.mptc.gov.kh/dns_registration.htm
+*.kh
+
+// ki : http://www.ki/dns/index.html
+ki
+edu.ki
+biz.ki
+net.ki
+org.ki
+gov.ki
+info.ki
+com.ki
+
+// km : https://en.wikipedia.org/wiki/.km
+// http://www.domaine.km/documents/charte.doc
+km
+org.km
+nom.km
+gov.km
+prd.km
+tm.km
+edu.km
+mil.km
+ass.km
+com.km
+// These are only mentioned as proposed suggestions at domaine.km, but
+// https://en.wikipedia.org/wiki/.km says they're available for registration:
+coop.km
+asso.km
+presse.km
+medecin.km
+notaires.km
+pharmaciens.km
+veterinaire.km
+gouv.km
+
+// kn : https://en.wikipedia.org/wiki/.kn
+// http://www.dot.kn/domainRules.html
+kn
+net.kn
+org.kn
+edu.kn
+gov.kn
+
+// kp : http://www.kcce.kp/en_index.php
+kp
+com.kp
+edu.kp
+gov.kp
+org.kp
+rep.kp
+tra.kp
+
+// kr : https://en.wikipedia.org/wiki/.kr
+// see also: http://domain.nida.or.kr/eng/registration.jsp
+kr
+ac.kr
+co.kr
+es.kr
+go.kr
+hs.kr
+kg.kr
+mil.kr
+ms.kr
+ne.kr
+or.kr
+pe.kr
+re.kr
+sc.kr
+// kr geographical names
+busan.kr
+chungbuk.kr
+chungnam.kr
+daegu.kr
+daejeon.kr
+gangwon.kr
+gwangju.kr
+gyeongbuk.kr
+gyeonggi.kr
+gyeongnam.kr
+incheon.kr
+jeju.kr
+jeonbuk.kr
+jeonnam.kr
+seoul.kr
+ulsan.kr
+
+// kw : https://en.wikipedia.org/wiki/.kw
+*.kw
+
+// ky : http://www.icta.ky/da_ky_reg_dom.php
+// Confirmed by registry <kysupport@perimeterusa.com> 2008-06-17
+ky
+edu.ky
+gov.ky
+com.ky
+org.ky
+net.ky
+
+// kz : https://en.wikipedia.org/wiki/.kz
+// see also: http://www.nic.kz/rules/index.jsp
+kz
+org.kz
+edu.kz
+net.kz
+gov.kz
+mil.kz
+com.kz
+
+// la : https://en.wikipedia.org/wiki/.la
+// Submitted by registry <gavin.brown@nic.la>
+la
+int.la
+net.la
+info.la
+edu.la
+gov.la
+per.la
+com.la
+org.la
+
+// lb : https://en.wikipedia.org/wiki/.lb
+// Submitted by registry <randy@psg.com>
+lb
+com.lb
+edu.lb
+gov.lb
+net.lb
+org.lb
+
+// lc : https://en.wikipedia.org/wiki/.lc
+// see also: http://www.nic.lc/rules.htm
+lc
+com.lc
+net.lc
+co.lc
+org.lc
+edu.lc
+gov.lc
+
+// li : https://en.wikipedia.org/wiki/.li
+li
+
+// lk : http://www.nic.lk/seclevpr.html
+lk
+gov.lk
+sch.lk
+net.lk
+int.lk
+com.lk
+org.lk
+edu.lk
+ngo.lk
+soc.lk
+web.lk
+ltd.lk
+assn.lk
+grp.lk
+hotel.lk
+ac.lk
+
+// lr : http://psg.com/dns/lr/lr.txt
+// Submitted by registry <randy@psg.com>
+lr
+com.lr
+edu.lr
+gov.lr
+org.lr
+net.lr
+
+// ls : https://en.wikipedia.org/wiki/.ls
+ls
+co.ls
+org.ls
+
+// lt : https://en.wikipedia.org/wiki/.lt
+lt
+// gov.lt : http://www.gov.lt/index_en.php
+gov.lt
+
+// lu : http://www.dns.lu/en/
+lu
+
+// lv : http://www.nic.lv/DNS/En/generic.php
+lv
+com.lv
+edu.lv
+gov.lv
+org.lv
+mil.lv
+id.lv
+net.lv
+asn.lv
+conf.lv
+
+// ly : http://www.nic.ly/regulations.php
+ly
+com.ly
+net.ly
+gov.ly
+plc.ly
+edu.ly
+sch.ly
+med.ly
+org.ly
+id.ly
+
+// ma : https://en.wikipedia.org/wiki/.ma
+// http://www.anrt.ma/fr/admin/download/upload/file_fr782.pdf
+ma
+co.ma
+net.ma
+gov.ma
+org.ma
+ac.ma
+press.ma
+
+// mc : http://www.nic.mc/
+mc
+tm.mc
+asso.mc
+
+// md : https://en.wikipedia.org/wiki/.md
+md
+
+// me : https://en.wikipedia.org/wiki/.me
+me
+co.me
+net.me
+org.me
+edu.me
+ac.me
+gov.me
+its.me
+priv.me
+
+// mg : http://nic.mg/nicmg/?page_id=39
+mg
+org.mg
+nom.mg
+gov.mg
+prd.mg
+tm.mg
+edu.mg
+mil.mg
+com.mg
+co.mg
+
+// mh : https://en.wikipedia.org/wiki/.mh
+mh
+
+// mil : https://en.wikipedia.org/wiki/.mil
+mil
+
+// mk : https://en.wikipedia.org/wiki/.mk
+// see also: http://dns.marnet.net.mk/postapka.php
+mk
+com.mk
+org.mk
+net.mk
+edu.mk
+gov.mk
+inf.mk
+name.mk
+
+// ml : http://www.gobin.info/domainname/ml-template.doc
+// see also: https://en.wikipedia.org/wiki/.ml
+ml
+com.ml
+edu.ml
+gouv.ml
+gov.ml
+net.ml
+org.ml
+presse.ml
+
+// mm : https://en.wikipedia.org/wiki/.mm
+*.mm
+
+// mn : https://en.wikipedia.org/wiki/.mn
+mn
+gov.mn
+edu.mn
+org.mn
+
+// mo : http://www.monic.net.mo/
+mo
+com.mo
+net.mo
+org.mo
+edu.mo
+gov.mo
+
+// mobi : https://en.wikipedia.org/wiki/.mobi
+mobi
+
+// mp : http://www.dot.mp/
+// Confirmed by registry <dcamacho@saipan.com> 2008-06-17
+mp
+
+// mq : https://en.wikipedia.org/wiki/.mq
+mq
+
+// mr : https://en.wikipedia.org/wiki/.mr
+mr
+gov.mr
+
+// ms : http://www.nic.ms/pdf/MS_Domain_Name_Rules.pdf
+ms
+com.ms
+edu.ms
+gov.ms
+net.ms
+org.ms
+
+// mt : https://www.nic.org.mt/go/policy
+// Submitted by registry <help@nic.org.mt>
+mt
+com.mt
+edu.mt
+net.mt
+org.mt
+
+// mu : https://en.wikipedia.org/wiki/.mu
+mu
+com.mu
+net.mu
+org.mu
+gov.mu
+ac.mu
+co.mu
+or.mu
+
+// museum : http://about.museum/naming/
+// http://index.museum/
+museum
+academy.museum
+agriculture.museum
+air.museum
+airguard.museum
+alabama.museum
+alaska.museum
+amber.museum
+ambulance.museum
+american.museum
+americana.museum
+americanantiques.museum
+americanart.museum
+amsterdam.museum
+and.museum
+annefrank.museum
+anthro.museum
+anthropology.museum
+antiques.museum
+aquarium.museum
+arboretum.museum
+archaeological.museum
+archaeology.museum
+architecture.museum
+art.museum
+artanddesign.museum
+artcenter.museum
+artdeco.museum
+arteducation.museum
+artgallery.museum
+arts.museum
+artsandcrafts.museum
+asmatart.museum
+assassination.museum
+assisi.museum
+association.museum
+astronomy.museum
+atlanta.museum
+austin.museum
+australia.museum
+automotive.museum
+aviation.museum
+axis.museum
+badajoz.museum
+baghdad.museum
+bahn.museum
+bale.museum
+baltimore.museum
+barcelona.museum
+baseball.museum
+basel.museum
+baths.museum
+bauern.museum
+beauxarts.museum
+beeldengeluid.museum
+bellevue.museum
+bergbau.museum
+berkeley.museum
+berlin.museum
+bern.museum
+bible.museum
+bilbao.museum
+bill.museum
+birdart.museum
+birthplace.museum
+bonn.museum
+boston.museum
+botanical.museum
+botanicalgarden.museum
+botanicgarden.museum
+botany.museum
+brandywinevalley.museum
+brasil.museum
+bristol.museum
+british.museum
+britishcolumbia.museum
+broadcast.museum
+brunel.museum
+brussel.museum
+brussels.museum
+bruxelles.museum
+building.museum
+burghof.museum
+bus.museum
+bushey.museum
+cadaques.museum
+california.museum
+cambridge.museum
+can.museum
+canada.museum
+capebreton.museum
+carrier.museum
+cartoonart.museum
+casadelamoneda.museum
+castle.museum
+castres.museum
+celtic.museum
+center.museum
+chattanooga.museum
+cheltenham.museum
+chesapeakebay.museum
+chicago.museum
+children.museum
+childrens.museum
+childrensgarden.museum
+chiropractic.museum
+chocolate.museum
+christiansburg.museum
+cincinnati.museum
+cinema.museum
+circus.museum
+civilisation.museum
+civilization.museum
+civilwar.museum
+clinton.museum
+clock.museum
+coal.museum
+coastaldefence.museum
+cody.museum
+coldwar.museum
+collection.museum
+colonialwilliamsburg.museum
+coloradoplateau.museum
+columbia.museum
+columbus.museum
+communication.museum
+communications.museum
+community.museum
+computer.museum
+computerhistory.museum
+comunicações.museum
+contemporary.museum
+contemporaryart.museum
+convent.museum
+copenhagen.museum
+corporation.museum
+correios-e-telecomunicações.museum
+corvette.museum
+costume.museum
+countryestate.museum
+county.museum
+crafts.museum
+cranbrook.museum
+creation.museum
+cultural.museum
+culturalcenter.museum
+culture.museum
+cyber.museum
+cymru.museum
+dali.museum
+dallas.museum
+database.museum
+ddr.museum
+decorativearts.museum
+delaware.museum
+delmenhorst.museum
+denmark.museum
+depot.museum
+design.museum
+detroit.museum
+dinosaur.museum
+discovery.museum
+dolls.museum
+donostia.museum
+durham.museum
+eastafrica.museum
+eastcoast.museum
+education.museum
+educational.museum
+egyptian.museum
+eisenbahn.museum
+elburg.museum
+elvendrell.museum
+embroidery.museum
+encyclopedic.museum
+england.museum
+entomology.museum
+environment.museum
+environmentalconservation.museum
+epilepsy.museum
+essex.museum
+estate.museum
+ethnology.museum
+exeter.museum
+exhibition.museum
+family.museum
+farm.museum
+farmequipment.museum
+farmers.museum
+farmstead.museum
+field.museum
+figueres.museum
+filatelia.museum
+film.museum
+fineart.museum
+finearts.museum
+finland.museum
+flanders.museum
+florida.museum
+force.museum
+fortmissoula.museum
+fortworth.museum
+foundation.museum
+francaise.museum
+frankfurt.museum
+franziskaner.museum
+freemasonry.museum
+freiburg.museum
+fribourg.museum
+frog.museum
+fundacio.museum
+furniture.museum
+gallery.museum
+garden.museum
+gateway.museum
+geelvinck.museum
+gemological.museum
+geology.museum
+georgia.museum
+giessen.museum
+glas.museum
+glass.museum
+gorge.museum
+grandrapids.museum
+graz.museum
+guernsey.museum
+halloffame.museum
+hamburg.museum
+handson.museum
+harvestcelebration.museum
+hawaii.museum
+health.museum
+heimatunduhren.museum
+hellas.museum
+helsinki.museum
+hembygdsforbund.museum
+heritage.museum
+histoire.museum
+historical.museum
+historicalsociety.museum
+historichouses.museum
+historisch.museum
+historisches.museum
+history.museum
+historyofscience.museum
+horology.museum
+house.museum
+humanities.museum
+illustration.museum
+imageandsound.museum
+indian.museum
+indiana.museum
+indianapolis.museum
+indianmarket.museum
+intelligence.museum
+interactive.museum
+iraq.museum
+iron.museum
+isleofman.museum
+jamison.museum
+jefferson.museum
+jerusalem.museum
+jewelry.museum
+jewish.museum
+jewishart.museum
+jfk.museum
+journalism.museum
+judaica.museum
+judygarland.museum
+juedisches.museum
+juif.museum
+karate.museum
+karikatur.museum
+kids.museum
+koebenhavn.museum
+koeln.museum
+kunst.museum
+kunstsammlung.museum
+kunstunddesign.museum
+labor.museum
+labour.museum
+lajolla.museum
+lancashire.museum
+landes.museum
+lans.museum
+läns.museum
+larsson.museum
+lewismiller.museum
+lincoln.museum
+linz.museum
+living.museum
+livinghistory.museum
+localhistory.museum
+london.museum
+losangeles.museum
+louvre.museum
+loyalist.museum
+lucerne.museum
+luxembourg.museum
+luzern.museum
+mad.museum
+madrid.museum
+mallorca.museum
+manchester.museum
+mansion.museum
+mansions.museum
+manx.museum
+marburg.museum
+maritime.museum
+maritimo.museum
+maryland.museum
+marylhurst.museum
+media.museum
+medical.museum
+medizinhistorisches.museum
+meeres.museum
+memorial.museum
+mesaverde.museum
+michigan.museum
+midatlantic.museum
+military.museum
+mill.museum
+miners.museum
+mining.museum
+minnesota.museum
+missile.museum
+missoula.museum
+modern.museum
+moma.museum
+money.museum
+monmouth.museum
+monticello.museum
+montreal.museum
+moscow.museum
+motorcycle.museum
+muenchen.museum
+muenster.museum
+mulhouse.museum
+muncie.museum
+museet.museum
+museumcenter.museum
+museumvereniging.museum
+music.museum
+national.museum
+nationalfirearms.museum
+nationalheritage.museum
+nativeamerican.museum
+naturalhistory.museum
+naturalhistorymuseum.museum
+naturalsciences.museum
+nature.museum
+naturhistorisches.museum
+natuurwetenschappen.museum
+naumburg.museum
+naval.museum
+nebraska.museum
+neues.museum
+newhampshire.museum
+newjersey.museum
+newmexico.museum
+newport.museum
+newspaper.museum
+newyork.museum
+niepce.museum
+norfolk.museum
+north.museum
+nrw.museum
+nuernberg.museum
+nuremberg.museum
+nyc.museum
+nyny.museum
+oceanographic.museum
+oceanographique.museum
+omaha.museum
+online.museum
+ontario.museum
+openair.museum
+oregon.museum
+oregontrail.museum
+otago.museum
+oxford.museum
+pacific.museum
+paderborn.museum
+palace.museum
+paleo.museum
+palmsprings.museum
+panama.museum
+paris.museum
+pasadena.museum
+pharmacy.museum
+philadelphia.museum
+philadelphiaarea.museum
+philately.museum
+phoenix.museum
+photography.museum
+pilots.museum
+pittsburgh.museum
+planetarium.museum
+plantation.museum
+plants.museum
+plaza.museum
+portal.museum
+portland.museum
+portlligat.museum
+posts-and-telecommunications.museum
+preservation.museum
+presidio.museum
+press.museum
+project.museum
+public.museum
+pubol.museum
+quebec.museum
+railroad.museum
+railway.museum
+research.museum
+resistance.museum
+riodejaneiro.museum
+rochester.museum
+rockart.museum
+roma.museum
+russia.museum
+saintlouis.museum
+salem.museum
+salvadordali.museum
+salzburg.museum
+sandiego.museum
+sanfrancisco.museum
+santabarbara.museum
+santacruz.museum
+santafe.museum
+saskatchewan.museum
+satx.museum
+savannahga.museum
+schlesisches.museum
+schoenbrunn.museum
+schokoladen.museum
+school.museum
+schweiz.museum
+science.museum
+scienceandhistory.museum
+scienceandindustry.museum
+sciencecenter.museum
+sciencecenters.museum
+science-fiction.museum
+sciencehistory.museum
+sciences.museum
+sciencesnaturelles.museum
+scotland.museum
+seaport.museum
+settlement.museum
+settlers.museum
+shell.museum
+sherbrooke.museum
+sibenik.museum
+silk.museum
+ski.museum
+skole.museum
+society.museum
+sologne.museum
+soundandvision.museum
+southcarolina.museum
+southwest.museum
+space.museum
+spy.museum
+square.museum
+stadt.museum
+stalbans.museum
+starnberg.museum
+state.museum
+stateofdelaware.museum
+station.museum
+steam.museum
+steiermark.museum
+stjohn.museum
+stockholm.museum
+stpetersburg.museum
+stuttgart.museum
+suisse.museum
+surgeonshall.museum
+surrey.museum
+svizzera.museum
+sweden.museum
+sydney.museum
+tank.museum
+tcm.museum
+technology.museum
+telekommunikation.museum
+television.museum
+texas.museum
+textile.museum
+theater.museum
+time.museum
+timekeeping.museum
+topology.museum
+torino.museum
+touch.museum
+town.museum
+transport.museum
+tree.museum
+trolley.museum
+trust.museum
+trustee.museum
+uhren.museum
+ulm.museum
+undersea.museum
+university.museum
+usa.museum
+usantiques.museum
+usarts.museum
+uscountryestate.museum
+usculture.museum
+usdecorativearts.museum
+usgarden.museum
+ushistory.museum
+ushuaia.museum
+uslivinghistory.museum
+utah.museum
+uvic.museum
+valley.museum
+vantaa.museum
+versailles.museum
+viking.museum
+village.museum
+virginia.museum
+virtual.museum
+virtuel.museum
+vlaanderen.museum
+volkenkunde.museum
+wales.museum
+wallonie.museum
+war.museum
+washingtondc.museum
+watchandclock.museum
+watch-and-clock.museum
+western.museum
+westfalen.museum
+whaling.museum
+wildlife.museum
+williamsburg.museum
+windmill.museum
+workshop.museum
+york.museum
+yorkshire.museum
+yosemite.museum
+youth.museum
+zoological.museum
+zoology.museum
+ירושלים.museum
+иком.museum
+
+// mv : https://en.wikipedia.org/wiki/.mv
+// "mv" included because, contra Wikipedia, google.mv exists.
+mv
+aero.mv
+biz.mv
+com.mv
+coop.mv
+edu.mv
+gov.mv
+info.mv
+int.mv
+mil.mv
+museum.mv
+name.mv
+net.mv
+org.mv
+pro.mv
+
+// mw : http://www.registrar.mw/
+mw
+ac.mw
+biz.mw
+co.mw
+com.mw
+coop.mw
+edu.mw
+gov.mw
+int.mw
+museum.mw
+net.mw
+org.mw
+
+// mx : http://www.nic.mx/
+// Submitted by registry <farias@nic.mx>
+mx
+com.mx
+org.mx
+gob.mx
+edu.mx
+net.mx
+
+// my : http://www.mynic.net.my/
+my
+com.my
+net.my
+org.my
+gov.my
+edu.my
+mil.my
+name.my
+
+// mz : http://www.uem.mz/
+// Submitted by registry <antonio@uem.mz>
+mz
+ac.mz
+adv.mz
+co.mz
+edu.mz
+gov.mz
+mil.mz
+net.mz
+org.mz
+
+// na : http://www.na-nic.com.na/
+// http://www.info.na/domain/
+na
+info.na
+pro.na
+name.na
+school.na
+or.na
+dr.na
+us.na
+mx.na
+ca.na
+in.na
+cc.na
+tv.na
+ws.na
+mobi.na
+co.na
+com.na
+org.na
+
+// name : has 2nd-level tlds, but there's no list of them
+name
+
+// nc : http://www.cctld.nc/
+nc
+asso.nc
+nom.nc
+
+// ne : https://en.wikipedia.org/wiki/.ne
+ne
+
+// net : https://en.wikipedia.org/wiki/.net
+net
+
+// nf : https://en.wikipedia.org/wiki/.nf
+nf
+com.nf
+net.nf
+per.nf
+rec.nf
+web.nf
+arts.nf
+firm.nf
+info.nf
+other.nf
+store.nf
+
+// ng : http://www.nira.org.ng/index.php/join-us/register-ng-domain/189-nira-slds
+ng
+com.ng
+edu.ng
+gov.ng
+i.ng
+mil.ng
+mobi.ng
+name.ng
+net.ng
+org.ng
+sch.ng
+
+// ni : http://www.nic.ni/
+ni
+ac.ni
+biz.ni
+co.ni
+com.ni
+edu.ni
+gob.ni
+in.ni
+info.ni
+int.ni
+mil.ni
+net.ni
+nom.ni
+org.ni
+web.ni
+
+// nl : https://en.wikipedia.org/wiki/.nl
+// https://www.sidn.nl/
+// ccTLD for the Netherlands
+nl
+
+// BV.nl will be a registry for dutch BV's (besloten vennootschap)
+bv.nl
+
+// no : http://www.norid.no/regelverk/index.en.html
+// The Norwegian registry has declined to notify us of updates. The web pages
+// referenced below are the official source of the data. There is also an
+// announce mailing list:
+// https://postlister.uninett.no/sympa/info/norid-diskusjon
+no
+// Norid generic domains : http://www.norid.no/regelverk/vedlegg-c.en.html
+fhs.no
+vgs.no
+fylkesbibl.no
+folkebibl.no
+museum.no
+idrett.no
+priv.no
+// Non-Norid generic domains : http://www.norid.no/regelverk/vedlegg-d.en.html
+mil.no
+stat.no
+dep.no
+kommune.no
+herad.no
+// no geographical names : http://www.norid.no/regelverk/vedlegg-b.en.html
+// counties
+aa.no
+ah.no
+bu.no
+fm.no
+hl.no
+hm.no
+jan-mayen.no
+mr.no
+nl.no
+nt.no
+of.no
+ol.no
+oslo.no
+rl.no
+sf.no
+st.no
+svalbard.no
+tm.no
+tr.no
+va.no
+vf.no
+// primary and lower secondary schools per county
+gs.aa.no
+gs.ah.no
+gs.bu.no
+gs.fm.no
+gs.hl.no
+gs.hm.no
+gs.jan-mayen.no
+gs.mr.no
+gs.nl.no
+gs.nt.no
+gs.of.no
+gs.ol.no
+gs.oslo.no
+gs.rl.no
+gs.sf.no
+gs.st.no
+gs.svalbard.no
+gs.tm.no
+gs.tr.no
+gs.va.no
+gs.vf.no
+// cities
+akrehamn.no
+åkrehamn.no
+algard.no
+ålgård.no
+arna.no
+brumunddal.no
+bryne.no
+bronnoysund.no
+brønnøysund.no
+drobak.no
+drøbak.no
+egersund.no
+fetsund.no
+floro.no
+florø.no
+fredrikstad.no
+hokksund.no
+honefoss.no
+hønefoss.no
+jessheim.no
+jorpeland.no
+jørpeland.no
+kirkenes.no
+kopervik.no
+krokstadelva.no
+langevag.no
+langevåg.no
+leirvik.no
+mjondalen.no
+mjøndalen.no
+mo-i-rana.no
+mosjoen.no
+mosjøen.no
+nesoddtangen.no
+orkanger.no
+osoyro.no
+osøyro.no
+raholt.no
+råholt.no
+sandnessjoen.no
+sandnessjøen.no
+skedsmokorset.no
+slattum.no
+spjelkavik.no
+stathelle.no
+stavern.no
+stjordalshalsen.no
+stjørdalshalsen.no
+tananger.no
+tranby.no
+vossevangen.no
+// communities
+afjord.no
+åfjord.no
+agdenes.no
+al.no
+ål.no
+alesund.no
+ålesund.no
+alstahaug.no
+alta.no
+áltá.no
+alaheadju.no
+álaheadju.no
+alvdal.no
+amli.no
+åmli.no
+amot.no
+åmot.no
+andebu.no
+andoy.no
+andøy.no
+andasuolo.no
+ardal.no
+årdal.no
+aremark.no
+arendal.no
+ås.no
+aseral.no
+åseral.no
+asker.no
+askim.no
+askvoll.no
+askoy.no
+askøy.no
+asnes.no
+åsnes.no
+audnedaln.no
+aukra.no
+aure.no
+aurland.no
+aurskog-holand.no
+aurskog-høland.no
+austevoll.no
+austrheim.no
+averoy.no
+averøy.no
+balestrand.no
+ballangen.no
+balat.no
+bálát.no
+balsfjord.no
+bahccavuotna.no
+báhccavuotna.no
+bamble.no
+bardu.no
+beardu.no
+beiarn.no
+bajddar.no
+bájddar.no
+baidar.no
+báidár.no
+berg.no
+bergen.no
+berlevag.no
+berlevåg.no
+bearalvahki.no
+bearalváhki.no
+bindal.no
+birkenes.no
+bjarkoy.no
+bjarkøy.no
+bjerkreim.no
+bjugn.no
+bodo.no
+bodø.no
+badaddja.no
+bådåddjå.no
+budejju.no
+bokn.no
+bremanger.no
+bronnoy.no
+brønnøy.no
+bygland.no
+bykle.no
+barum.no
+bærum.no
+bo.telemark.no
+bø.telemark.no
+bo.nordland.no
+bø.nordland.no
+bievat.no
+bievát.no
+bomlo.no
+bømlo.no
+batsfjord.no
+båtsfjord.no
+bahcavuotna.no
+báhcavuotna.no
+dovre.no
+drammen.no
+drangedal.no
+dyroy.no
+dyrøy.no
+donna.no
+dønna.no
+eid.no
+eidfjord.no
+eidsberg.no
+eidskog.no
+eidsvoll.no
+eigersund.no
+elverum.no
+enebakk.no
+engerdal.no
+etne.no
+etnedal.no
+evenes.no
+evenassi.no
+evenášši.no
+evje-og-hornnes.no
+farsund.no
+fauske.no
+fuossko.no
+fuoisku.no
+fedje.no
+fet.no
+finnoy.no
+finnøy.no
+fitjar.no
+fjaler.no
+fjell.no
+flakstad.no
+flatanger.no
+flekkefjord.no
+flesberg.no
+flora.no
+fla.no
+flå.no
+folldal.no
+forsand.no
+fosnes.no
+frei.no
+frogn.no
+froland.no
+frosta.no
+frana.no
+fræna.no
+froya.no
+frøya.no
+fusa.no
+fyresdal.no
+forde.no
+førde.no
+gamvik.no
+gangaviika.no
+gáŋgaviika.no
+gaular.no
+gausdal.no
+gildeskal.no
+gildeskål.no
+giske.no
+gjemnes.no
+gjerdrum.no
+gjerstad.no
+gjesdal.no
+gjovik.no
+gjøvik.no
+gloppen.no
+gol.no
+gran.no
+grane.no
+granvin.no
+gratangen.no
+grimstad.no
+grong.no
+kraanghke.no
+kråanghke.no
+grue.no
+gulen.no
+hadsel.no
+halden.no
+halsa.no
+hamar.no
+hamaroy.no
+habmer.no
+hábmer.no
+hapmir.no
+hápmir.no
+hammerfest.no
+hammarfeasta.no
+hámmárfeasta.no
+haram.no
+hareid.no
+harstad.no
+hasvik.no
+aknoluokta.no
+ákŋoluokta.no
+hattfjelldal.no
+aarborte.no
+haugesund.no
+hemne.no
+hemnes.no
+hemsedal.no
+heroy.more-og-romsdal.no
+herøy.møre-og-romsdal.no
+heroy.nordland.no
+herøy.nordland.no
+hitra.no
+hjartdal.no
+hjelmeland.no
+hobol.no
+hobøl.no
+hof.no
+hol.no
+hole.no
+holmestrand.no
+holtalen.no
+holtålen.no
+hornindal.no
+horten.no
+hurdal.no
+hurum.no
+hvaler.no
+hyllestad.no
+hagebostad.no
+hægebostad.no
+hoyanger.no
+høyanger.no
+hoylandet.no
+høylandet.no
+ha.no
+hå.no
+ibestad.no
+inderoy.no
+inderøy.no
+iveland.no
+jevnaker.no
+jondal.no
+jolster.no
+jølster.no
+karasjok.no
+karasjohka.no
+kárášjohka.no
+karlsoy.no
+galsa.no
+gálsá.no
+karmoy.no
+karmøy.no
+kautokeino.no
+guovdageaidnu.no
+klepp.no
+klabu.no
+klæbu.no
+kongsberg.no
+kongsvinger.no
+kragero.no
+kragerø.no
+kristiansand.no
+kristiansund.no
+krodsherad.no
+krødsherad.no
+kvalsund.no
+rahkkeravju.no
+ráhkkerávju.no
+kvam.no
+kvinesdal.no
+kvinnherad.no
+kviteseid.no
+kvitsoy.no
+kvitsøy.no
+kvafjord.no
+kvæfjord.no
+giehtavuoatna.no
+kvanangen.no
+kvænangen.no
+navuotna.no
+návuotna.no
+kafjord.no
+kåfjord.no
+gaivuotna.no
+gáivuotna.no
+larvik.no
+lavangen.no
+lavagis.no
+loabat.no
+loabát.no
+lebesby.no
+davvesiida.no
+leikanger.no
+leirfjord.no
+leka.no
+leksvik.no
+lenvik.no
+leangaviika.no
+leaŋgaviika.no
+lesja.no
+levanger.no
+lier.no
+lierne.no
+lillehammer.no
+lillesand.no
+lindesnes.no
+lindas.no
+lindås.no
+lom.no
+loppa.no
+lahppi.no
+láhppi.no
+lund.no
+lunner.no
+luroy.no
+lurøy.no
+luster.no
+lyngdal.no
+lyngen.no
+ivgu.no
+lardal.no
+lerdal.no
+lærdal.no
+lodingen.no
+lødingen.no
+lorenskog.no
+lørenskog.no
+loten.no
+løten.no
+malvik.no
+masoy.no
+måsøy.no
+muosat.no
+muosát.no
+mandal.no
+marker.no
+marnardal.no
+masfjorden.no
+meland.no
+meldal.no
+melhus.no
+meloy.no
+meløy.no
+meraker.no
+meråker.no
+moareke.no
+moåreke.no
+midsund.no
+midtre-gauldal.no
+modalen.no
+modum.no
+molde.no
+moskenes.no
+moss.no
+mosvik.no
+malselv.no
+målselv.no
+malatvuopmi.no
+málatvuopmi.no
+namdalseid.no
+aejrie.no
+namsos.no
+namsskogan.no
+naamesjevuemie.no
+nååmesjevuemie.no
+laakesvuemie.no
+nannestad.no
+narvik.no
+narviika.no
+naustdal.no
+nedre-eiker.no
+nes.akershus.no
+nes.buskerud.no
+nesna.no
+nesodden.no
+nesseby.no
+unjarga.no
+unjárga.no
+nesset.no
+nissedal.no
+nittedal.no
+nord-aurdal.no
+nord-fron.no
+nord-odal.no
+norddal.no
+nordkapp.no
+davvenjarga.no
+davvenjárga.no
+nordre-land.no
+nordreisa.no
+raisa.no
+ráisa.no
+nore-og-uvdal.no
+notodden.no
+naroy.no
+nærøy.no
+notteroy.no
+nøtterøy.no
+odda.no
+oksnes.no
+øksnes.no
+oppdal.no
+oppegard.no
+oppegård.no
+orkdal.no
+orland.no
+ørland.no
+orskog.no
+ørskog.no
+orsta.no
+ørsta.no
+os.hedmark.no
+os.hordaland.no
+osen.no
+osteroy.no
+osterøy.no
+ostre-toten.no
+østre-toten.no
+overhalla.no
+ovre-eiker.no
+øvre-eiker.no
+oyer.no
+øyer.no
+oygarden.no
+øygarden.no
+oystre-slidre.no
+øystre-slidre.no
+porsanger.no
+porsangu.no
+porsáŋgu.no
+porsgrunn.no
+radoy.no
+radøy.no
+rakkestad.no
+rana.no
+ruovat.no
+randaberg.no
+rauma.no
+rendalen.no
+rennebu.no
+rennesoy.no
+rennesøy.no
+rindal.no
+ringebu.no
+ringerike.no
+ringsaker.no
+rissa.no
+risor.no
+risør.no
+roan.no
+rollag.no
+rygge.no
+ralingen.no
+rælingen.no
+rodoy.no
+rødøy.no
+romskog.no
+rømskog.no
+roros.no
+røros.no
+rost.no
+røst.no
+royken.no
+røyken.no
+royrvik.no
+røyrvik.no
+rade.no
+råde.no
+salangen.no
+siellak.no
+saltdal.no
+salat.no
+sálát.no
+sálat.no
+samnanger.no
+sande.more-og-romsdal.no
+sande.møre-og-romsdal.no
+sande.vestfold.no
+sandefjord.no
+sandnes.no
+sandoy.no
+sandøy.no
+sarpsborg.no
+sauda.no
+sauherad.no
+sel.no
+selbu.no
+selje.no
+seljord.no
+sigdal.no
+siljan.no
+sirdal.no
+skaun.no
+skedsmo.no
+ski.no
+skien.no
+skiptvet.no
+skjervoy.no
+skjervøy.no
+skierva.no
+skiervá.no
+skjak.no
+skjåk.no
+skodje.no
+skanland.no
+skånland.no
+skanit.no
+skánit.no
+smola.no
+smøla.no
+snillfjord.no
+snasa.no
+snåsa.no
+snoasa.no
+snaase.no
+snåase.no
+sogndal.no
+sokndal.no
+sola.no
+solund.no
+songdalen.no
+sortland.no
+spydeberg.no
+stange.no
+stavanger.no
+steigen.no
+steinkjer.no
+stjordal.no
+stjørdal.no
+stokke.no
+stor-elvdal.no
+stord.no
+stordal.no
+storfjord.no
+omasvuotna.no
+strand.no
+stranda.no
+stryn.no
+sula.no
+suldal.no
+sund.no
+sunndal.no
+surnadal.no
+sveio.no
+svelvik.no
+sykkylven.no
+sogne.no
+søgne.no
+somna.no
+sømna.no
+sondre-land.no
+søndre-land.no
+sor-aurdal.no
+sør-aurdal.no
+sor-fron.no
+sør-fron.no
+sor-odal.no
+sør-odal.no
+sor-varanger.no
+sør-varanger.no
+matta-varjjat.no
+mátta-várjjat.no
+sorfold.no
+sørfold.no
+sorreisa.no
+sørreisa.no
+sorum.no
+sørum.no
+tana.no
+deatnu.no
+time.no
+tingvoll.no
+tinn.no
+tjeldsund.no
+dielddanuorri.no
+tjome.no
+tjøme.no
+tokke.no
+tolga.no
+torsken.no
+tranoy.no
+tranøy.no
+tromso.no
+tromsø.no
+tromsa.no
+romsa.no
+trondheim.no
+troandin.no
+trysil.no
+trana.no
+træna.no
+trogstad.no
+trøgstad.no
+tvedestrand.no
+tydal.no
+tynset.no
+tysfjord.no
+divtasvuodna.no
+divttasvuotna.no
+tysnes.no
+tysvar.no
+tysvær.no
+tonsberg.no
+tønsberg.no
+ullensaker.no
+ullensvang.no
+ulvik.no
+utsira.no
+vadso.no
+vadsø.no
+cahcesuolo.no
+čáhcesuolo.no
+vaksdal.no
+valle.no
+vang.no
+vanylven.no
+vardo.no
+vardø.no
+varggat.no
+várggát.no
+vefsn.no
+vaapste.no
+vega.no
+vegarshei.no
+vegårshei.no
+vennesla.no
+verdal.no
+verran.no
+vestby.no
+vestnes.no
+vestre-slidre.no
+vestre-toten.no
+vestvagoy.no
+vestvågøy.no
+vevelstad.no
+vik.no
+vikna.no
+vindafjord.no
+volda.no
+voss.no
+varoy.no
+værøy.no
+vagan.no
+vågan.no
+voagat.no
+vagsoy.no
+vågsøy.no
+vaga.no
+vågå.no
+valer.ostfold.no
+våler.østfold.no
+valer.hedmark.no
+våler.hedmark.no
+
+// np : http://www.mos.com.np/register.html
+*.np
+
+// nr : http://cenpac.net.nr/dns/index.html
+// Submitted by registry <technician@cenpac.net.nr>
+nr
+biz.nr
+info.nr
+gov.nr
+edu.nr
+org.nr
+net.nr
+com.nr
+
+// nu : https://en.wikipedia.org/wiki/.nu
+nu
+
+// nz : https://en.wikipedia.org/wiki/.nz
+// Submitted by registry <jay@nzrs.net.nz>
+nz
+ac.nz
+co.nz
+cri.nz
+geek.nz
+gen.nz
+govt.nz
+health.nz
+iwi.nz
+kiwi.nz
+maori.nz
+mil.nz
+māori.nz
+net.nz
+org.nz
+parliament.nz
+school.nz
+
+// om : https://en.wikipedia.org/wiki/.om
+om
+co.om
+com.om
+edu.om
+gov.om
+med.om
+museum.om
+net.om
+org.om
+pro.om
+
+// onion : https://tools.ietf.org/html/rfc7686
+onion
+
+// org : https://en.wikipedia.org/wiki/.org
+org
+
+// pa : http://www.nic.pa/
+// Some additional second level "domains" resolve directly as hostnames, such as
+// pannet.pa, so we add a rule for "pa".
+pa
+ac.pa
+gob.pa
+com.pa
+org.pa
+sld.pa
+edu.pa
+net.pa
+ing.pa
+abo.pa
+med.pa
+nom.pa
+
+// pe : https://www.nic.pe/InformeFinalComision.pdf
+pe
+edu.pe
+gob.pe
+nom.pe
+mil.pe
+org.pe
+com.pe
+net.pe
+
+// pf : http://www.gobin.info/domainname/formulaire-pf.pdf
+pf
+com.pf
+org.pf
+edu.pf
+
+// pg : https://en.wikipedia.org/wiki/.pg
+*.pg
+
+// ph : http://www.domains.ph/FAQ2.asp
+// Submitted by registry <jed@email.com.ph>
+ph
+com.ph
+net.ph
+org.ph
+gov.ph
+edu.ph
+ngo.ph
+mil.ph
+i.ph
+
+// pk : http://pk5.pknic.net.pk/pk5/msgNamepk.PK
+pk
+com.pk
+net.pk
+edu.pk
+org.pk
+fam.pk
+biz.pk
+web.pk
+gov.pk
+gob.pk
+gok.pk
+gon.pk
+gop.pk
+gos.pk
+info.pk
+
+// pl http://www.dns.pl/english/index.html
+// Submitted by registry
+pl
+com.pl
+net.pl
+org.pl
+// pl functional domains (http://www.dns.pl/english/index.html)
+aid.pl
+agro.pl
+atm.pl
+auto.pl
+biz.pl
+edu.pl
+gmina.pl
+gsm.pl
+info.pl
+mail.pl
+miasta.pl
+media.pl
+mil.pl
+nieruchomosci.pl
+nom.pl
+pc.pl
+powiat.pl
+priv.pl
+realestate.pl
+rel.pl
+sex.pl
+shop.pl
+sklep.pl
+sos.pl
+szkola.pl
+targi.pl
+tm.pl
+tourism.pl
+travel.pl
+turystyka.pl
+// Government domains
+gov.pl
+ap.gov.pl
+ic.gov.pl
+is.gov.pl
+us.gov.pl
+kmpsp.gov.pl
+kppsp.gov.pl
+kwpsp.gov.pl
+psp.gov.pl
+wskr.gov.pl
+kwp.gov.pl
+mw.gov.pl
+ug.gov.pl
+um.gov.pl
+umig.gov.pl
+ugim.gov.pl
+upow.gov.pl
+uw.gov.pl
+starostwo.gov.pl
+pa.gov.pl
+po.gov.pl
+psse.gov.pl
+pup.gov.pl
+rzgw.gov.pl
+sa.gov.pl
+so.gov.pl
+sr.gov.pl
+wsa.gov.pl
+sko.gov.pl
+uzs.gov.pl
+wiih.gov.pl
+winb.gov.pl
+pinb.gov.pl
+wios.gov.pl
+witd.gov.pl
+wzmiuw.gov.pl
+piw.gov.pl
+wiw.gov.pl
+griw.gov.pl
+wif.gov.pl
+oum.gov.pl
+sdn.gov.pl
+zp.gov.pl
+uppo.gov.pl
+mup.gov.pl
+wuoz.gov.pl
+konsulat.gov.pl
+oirm.gov.pl
+// pl regional domains (http://www.dns.pl/english/index.html)
+augustow.pl
+babia-gora.pl
+bedzin.pl
+beskidy.pl
+bialowieza.pl
+bialystok.pl
+bielawa.pl
+bieszczady.pl
+boleslawiec.pl
+bydgoszcz.pl
+bytom.pl
+cieszyn.pl
+czeladz.pl
+czest.pl
+dlugoleka.pl
+elblag.pl
+elk.pl
+glogow.pl
+gniezno.pl
+gorlice.pl
+grajewo.pl
+ilawa.pl
+jaworzno.pl
+jelenia-gora.pl
+jgora.pl
+kalisz.pl
+kazimierz-dolny.pl
+karpacz.pl
+kartuzy.pl
+kaszuby.pl
+katowice.pl
+kepno.pl
+ketrzyn.pl
+klodzko.pl
+kobierzyce.pl
+kolobrzeg.pl
+konin.pl
+konskowola.pl
+kutno.pl
+lapy.pl
+lebork.pl
+legnica.pl
+lezajsk.pl
+limanowa.pl
+lomza.pl
+lowicz.pl
+lubin.pl
+lukow.pl
+malbork.pl
+malopolska.pl
+mazowsze.pl
+mazury.pl
+mielec.pl
+mielno.pl
+mragowo.pl
+naklo.pl
+nowaruda.pl
+nysa.pl
+olawa.pl
+olecko.pl
+olkusz.pl
+olsztyn.pl
+opoczno.pl
+opole.pl
+ostroda.pl
+ostroleka.pl
+ostrowiec.pl
+ostrowwlkp.pl
+pila.pl
+pisz.pl
+podhale.pl
+podlasie.pl
+polkowice.pl
+pomorze.pl
+pomorskie.pl
+prochowice.pl
+pruszkow.pl
+przeworsk.pl
+pulawy.pl
+radom.pl
+rawa-maz.pl
+rybnik.pl
+rzeszow.pl
+sanok.pl
+sejny.pl
+slask.pl
+slupsk.pl
+sosnowiec.pl
+stalowa-wola.pl
+skoczow.pl
+starachowice.pl
+stargard.pl
+suwalki.pl
+swidnica.pl
+swiebodzin.pl
+swinoujscie.pl
+szczecin.pl
+szczytno.pl
+tarnobrzeg.pl
+tgory.pl
+turek.pl
+tychy.pl
+ustka.pl
+walbrzych.pl
+warmia.pl
+warszawa.pl
+waw.pl
+wegrow.pl
+wielun.pl
+wlocl.pl
+wloclawek.pl
+wodzislaw.pl
+wolomin.pl
+wroclaw.pl
+zachpomor.pl
+zagan.pl
+zarow.pl
+zgora.pl
+zgorzelec.pl
+
+// pm : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+pm
+
+// pn : http://www.government.pn/PnRegistry/policies.htm
+pn
+gov.pn
+co.pn
+org.pn
+edu.pn
+net.pn
+
+// post : https://en.wikipedia.org/wiki/.post
+post
+
+// pr : http://www.nic.pr/index.asp?f=1
+pr
+com.pr
+net.pr
+org.pr
+gov.pr
+edu.pr
+isla.pr
+pro.pr
+biz.pr
+info.pr
+name.pr
+// these aren't mentioned on nic.pr, but on https://en.wikipedia.org/wiki/.pr
+est.pr
+prof.pr
+ac.pr
+
+// pro : http://registry.pro/get-pro
+pro
+aaa.pro
+aca.pro
+acct.pro
+avocat.pro
+bar.pro
+cpa.pro
+eng.pro
+jur.pro
+law.pro
+med.pro
+recht.pro
+
+// ps : https://en.wikipedia.org/wiki/.ps
+// http://www.nic.ps/registration/policy.html#reg
+ps
+edu.ps
+gov.ps
+sec.ps
+plo.ps
+com.ps
+org.ps
+net.ps
+
+// pt : http://online.dns.pt/dns/start_dns
+pt
+net.pt
+gov.pt
+org.pt
+edu.pt
+int.pt
+publ.pt
+com.pt
+nome.pt
+
+// pw : https://en.wikipedia.org/wiki/.pw
+pw
+co.pw
+ne.pw
+or.pw
+ed.pw
+go.pw
+belau.pw
+
+// py : http://www.nic.py/pautas.html#seccion_9
+// Submitted by registry
+py
+com.py
+coop.py
+edu.py
+gov.py
+mil.py
+net.py
+org.py
+
+// qa : http://domains.qa/en/
+qa
+com.qa
+edu.qa
+gov.qa
+mil.qa
+name.qa
+net.qa
+org.qa
+sch.qa
+
+// re : http://www.afnic.re/obtenir/chartes/nommage-re/annexe-descriptifs
+re
+asso.re
+com.re
+nom.re
+
+// ro : http://www.rotld.ro/
+ro
+arts.ro
+com.ro
+firm.ro
+info.ro
+nom.ro
+nt.ro
+org.ro
+rec.ro
+store.ro
+tm.ro
+www.ro
+
+// rs : https://www.rnids.rs/en/domains/national-domains
+rs
+ac.rs
+co.rs
+edu.rs
+gov.rs
+in.rs
+org.rs
+
+// ru : https://cctld.ru/en/domains/domens_ru/reserved/
+ru
+ac.ru
+edu.ru
+gov.ru
+int.ru
+mil.ru
+test.ru
+
+// rw : http://www.nic.rw/cgi-bin/policy.pl
+rw
+gov.rw
+net.rw
+edu.rw
+ac.rw
+com.rw
+co.rw
+int.rw
+mil.rw
+gouv.rw
+
+// sa : http://www.nic.net.sa/
+sa
+com.sa
+net.sa
+org.sa
+gov.sa
+med.sa
+pub.sa
+edu.sa
+sch.sa
+
+// sb : http://www.sbnic.net.sb/
+// Submitted by registry <lee.humphries@telekom.com.sb>
+sb
+com.sb
+edu.sb
+gov.sb
+net.sb
+org.sb
+
+// sc : http://www.nic.sc/
+sc
+com.sc
+gov.sc
+net.sc
+org.sc
+edu.sc
+
+// sd : http://www.isoc.sd/sudanic.isoc.sd/billing_pricing.htm
+// Submitted by registry <admin@isoc.sd>
+sd
+com.sd
+net.sd
+org.sd
+edu.sd
+med.sd
+tv.sd
+gov.sd
+info.sd
+
+// se : https://en.wikipedia.org/wiki/.se
+// Submitted by registry <patrik.wallstrom@iis.se>
+se
+a.se
+ac.se
+b.se
+bd.se
+brand.se
+c.se
+d.se
+e.se
+f.se
+fh.se
+fhsk.se
+fhv.se
+g.se
+h.se
+i.se
+k.se
+komforb.se
+kommunalforbund.se
+komvux.se
+l.se
+lanbib.se
+m.se
+n.se
+naturbruksgymn.se
+o.se
+org.se
+p.se
+parti.se
+pp.se
+press.se
+r.se
+s.se
+t.se
+tm.se
+u.se
+w.se
+x.se
+y.se
+z.se
+
+// sg : http://www.nic.net.sg/page/registration-policies-procedures-and-guidelines
+sg
+com.sg
+net.sg
+org.sg
+gov.sg
+edu.sg
+per.sg
+
+// sh : http://www.nic.sh/registrar.html
+sh
+com.sh
+net.sh
+gov.sh
+org.sh
+mil.sh
+
+// si : https://en.wikipedia.org/wiki/.si
+si
+
+// sj : No registrations at this time.
+// Submitted by registry <jarle@uninett.no>
+sj
+
+// sk : https://en.wikipedia.org/wiki/.sk
+// list of 2nd level domains ?
+sk
+
+// sl : http://www.nic.sl
+// Submitted by registry <adam@neoip.com>
+sl
+com.sl
+net.sl
+edu.sl
+gov.sl
+org.sl
+
+// sm : https://en.wikipedia.org/wiki/.sm
+sm
+
+// sn : https://en.wikipedia.org/wiki/.sn
+sn
+art.sn
+com.sn
+edu.sn
+gouv.sn
+org.sn
+perso.sn
+univ.sn
+
+// so : http://www.soregistry.com/
+so
+com.so
+net.so
+org.so
+
+// sr : https://en.wikipedia.org/wiki/.sr
+sr
+
+// st : http://www.nic.st/html/policyrules/
+st
+co.st
+com.st
+consulado.st
+edu.st
+embaixada.st
+gov.st
+mil.st
+net.st
+org.st
+principe.st
+saotome.st
+store.st
+
+// su : https://en.wikipedia.org/wiki/.su
+su
+
+// sv : http://www.svnet.org.sv/niveldos.pdf
+sv
+com.sv
+edu.sv
+gob.sv
+org.sv
+red.sv
+
+// sx : https://en.wikipedia.org/wiki/.sx
+// Submitted by registry <jcvignes@openregistry.com>
+sx
+gov.sx
+
+// sy : https://en.wikipedia.org/wiki/.sy
+// see also: http://www.gobin.info/domainname/sy.doc
+sy
+edu.sy
+gov.sy
+net.sy
+mil.sy
+com.sy
+org.sy
+
+// sz : https://en.wikipedia.org/wiki/.sz
+// http://www.sispa.org.sz/
+sz
+co.sz
+ac.sz
+org.sz
+
+// tc : https://en.wikipedia.org/wiki/.tc
+tc
+
+// td : https://en.wikipedia.org/wiki/.td
+td
+
+// tel: https://en.wikipedia.org/wiki/.tel
+// http://www.telnic.org/
+tel
+
+// tf : https://en.wikipedia.org/wiki/.tf
+tf
+
+// tg : https://en.wikipedia.org/wiki/.tg
+// http://www.nic.tg/
+tg
+
+// th : https://en.wikipedia.org/wiki/.th
+// Submitted by registry <krit@thains.co.th>
+th
+ac.th
+co.th
+go.th
+in.th
+mi.th
+net.th
+or.th
+
+// tj : http://www.nic.tj/policy.html
+tj
+ac.tj
+biz.tj
+co.tj
+com.tj
+edu.tj
+go.tj
+gov.tj
+int.tj
+mil.tj
+name.tj
+net.tj
+nic.tj
+org.tj
+test.tj
+web.tj
+
+// tk : https://en.wikipedia.org/wiki/.tk
+tk
+
+// tl : https://en.wikipedia.org/wiki/.tl
+tl
+gov.tl
+
+// tm : http://www.nic.tm/local.html
+tm
+com.tm
+co.tm
+org.tm
+net.tm
+nom.tm
+gov.tm
+mil.tm
+edu.tm
+
+// tn : https://en.wikipedia.org/wiki/.tn
+// http://whois.ati.tn/
+tn
+com.tn
+ens.tn
+fin.tn
+gov.tn
+ind.tn
+intl.tn
+nat.tn
+net.tn
+org.tn
+info.tn
+perso.tn
+tourism.tn
+edunet.tn
+rnrt.tn
+rns.tn
+rnu.tn
+mincom.tn
+agrinet.tn
+defense.tn
+turen.tn
+
+// to : https://en.wikipedia.org/wiki/.to
+// Submitted by registry <egullich@colo.to>
+to
+com.to
+gov.to
+net.to
+org.to
+edu.to
+mil.to
+
+// subTLDs: https://www.nic.tr/forms/eng/policies.pdf
+// and: https://www.nic.tr/forms/politikalar.pdf
+// Submitted by <mehmetgurevin@gmail.com>
+tr
+com.tr
+info.tr
+biz.tr
+net.tr
+org.tr
+web.tr
+gen.tr
+tv.tr
+av.tr
+dr.tr
+bbs.tr
+name.tr
+tel.tr
+gov.tr
+bel.tr
+pol.tr
+mil.tr
+k12.tr
+edu.tr
+kep.tr
+
+// Used by Northern Cyprus
+nc.tr
+
+// Used by government agencies of Northern Cyprus
+gov.nc.tr
+
+// travel : https://en.wikipedia.org/wiki/.travel
+travel
+
+// tt : http://www.nic.tt/
+tt
+co.tt
+com.tt
+org.tt
+net.tt
+biz.tt
+info.tt
+pro.tt
+int.tt
+coop.tt
+jobs.tt
+mobi.tt
+travel.tt
+museum.tt
+aero.tt
+name.tt
+gov.tt
+edu.tt
+
+// tv : https://en.wikipedia.org/wiki/.tv
+// Not listing any 2LDs as reserved since none seem to exist in practice,
+// Wikipedia notwithstanding.
+tv
+
+// tw : https://en.wikipedia.org/wiki/.tw
+tw
+edu.tw
+gov.tw
+mil.tw
+com.tw
+net.tw
+org.tw
+idv.tw
+game.tw
+ebiz.tw
+club.tw
+網路.tw
+組織.tw
+商業.tw
+
+// tz : http://www.tznic.or.tz/index.php/domains
+// Submitted by registry <manager@tznic.or.tz>
+tz
+ac.tz
+co.tz
+go.tz
+hotel.tz
+info.tz
+me.tz
+mil.tz
+mobi.tz
+ne.tz
+or.tz
+sc.tz
+tv.tz
+
+// ua : https://hostmaster.ua/policy/?ua
+// Submitted by registry <dk@cctld.ua>
+ua
+// ua 2LD
+com.ua
+edu.ua
+gov.ua
+in.ua
+net.ua
+org.ua
+// ua geographic names
+// https://hostmaster.ua/2ld/
+cherkassy.ua
+cherkasy.ua
+chernigov.ua
+chernihiv.ua
+chernivtsi.ua
+chernovtsy.ua
+ck.ua
+cn.ua
+cr.ua
+crimea.ua
+cv.ua
+dn.ua
+dnepropetrovsk.ua
+dnipropetrovsk.ua
+dominic.ua
+donetsk.ua
+dp.ua
+if.ua
+ivano-frankivsk.ua
+kh.ua
+kharkiv.ua
+kharkov.ua
+kherson.ua
+khmelnitskiy.ua
+khmelnytskyi.ua
+kiev.ua
+kirovograd.ua
+km.ua
+kr.ua
+krym.ua
+ks.ua
+kv.ua
+kyiv.ua
+lg.ua
+lt.ua
+lugansk.ua
+lutsk.ua
+lv.ua
+lviv.ua
+mk.ua
+mykolaiv.ua
+nikolaev.ua
+od.ua
+odesa.ua
+odessa.ua
+pl.ua
+poltava.ua
+rivne.ua
+rovno.ua
+rv.ua
+sb.ua
+sebastopol.ua
+sevastopol.ua
+sm.ua
+sumy.ua
+te.ua
+ternopil.ua
+uz.ua
+uzhgorod.ua
+vinnica.ua
+vinnytsia.ua
+vn.ua
+volyn.ua
+yalta.ua
+zaporizhzhe.ua
+zaporizhzhia.ua
+zhitomir.ua
+zhytomyr.ua
+zp.ua
+zt.ua
+
+// ug : https://www.registry.co.ug/
+ug
+co.ug
+or.ug
+ac.ug
+sc.ug
+go.ug
+ne.ug
+com.ug
+org.ug
+
+// uk : https://en.wikipedia.org/wiki/.uk
+// Submitted by registry <Michael.Daly@nominet.org.uk>
+uk
+ac.uk
+co.uk
+gov.uk
+ltd.uk
+me.uk
+net.uk
+nhs.uk
+org.uk
+plc.uk
+police.uk
+*.sch.uk
+
+// us : https://en.wikipedia.org/wiki/.us
+us
+dni.us
+fed.us
+isa.us
+kids.us
+nsn.us
+// us geographic names
+ak.us
+al.us
+ar.us
+as.us
+az.us
+ca.us
+co.us
+ct.us
+dc.us
+de.us
+fl.us
+ga.us
+gu.us
+hi.us
+ia.us
+id.us
+il.us
+in.us
+ks.us
+ky.us
+la.us
+ma.us
+md.us
+me.us
+mi.us
+mn.us
+mo.us
+ms.us
+mt.us
+nc.us
+nd.us
+ne.us
+nh.us
+nj.us
+nm.us
+nv.us
+ny.us
+oh.us
+ok.us
+or.us
+pa.us
+pr.us
+ri.us
+sc.us
+sd.us
+tn.us
+tx.us
+ut.us
+vi.us
+vt.us
+va.us
+wa.us
+wi.us
+wv.us
+wy.us
+// The registrar notes several more specific domains available in each state,
+// such as state.*.us, dst.*.us, etc., but resolution of these is somewhat
+// haphazard; in some states these domains resolve as addresses, while in others
+// only subdomains are available, or even nothing at all. We include the
+// most common ones where it's clear that different sites are different
+// entities.
+k12.ak.us
+k12.al.us
+k12.ar.us
+k12.as.us
+k12.az.us
+k12.ca.us
+k12.co.us
+k12.ct.us
+k12.dc.us
+k12.de.us
+k12.fl.us
+k12.ga.us
+k12.gu.us
+// k12.hi.us Bug 614565 - Hawaii has a state-wide DOE login
+k12.ia.us
+k12.id.us
+k12.il.us
+k12.in.us
+k12.ks.us
+k12.ky.us
+k12.la.us
+k12.ma.us
+k12.md.us
+k12.me.us
+k12.mi.us
+k12.mn.us
+k12.mo.us
+k12.ms.us
+k12.mt.us
+k12.nc.us
+// k12.nd.us Bug 1028347 - Removed at request of Travis Rosso <trossow@nd.gov>
+k12.ne.us
+k12.nh.us
+k12.nj.us
+k12.nm.us
+k12.nv.us
+k12.ny.us
+k12.oh.us
+k12.ok.us
+k12.or.us
+k12.pa.us
+k12.pr.us
+k12.ri.us
+k12.sc.us
+// k12.sd.us Bug 934131 - Removed at request of James Booze <James.Booze@k12.sd.us>
+k12.tn.us
+k12.tx.us
+k12.ut.us
+k12.vi.us
+k12.vt.us
+k12.va.us
+k12.wa.us
+k12.wi.us
+// k12.wv.us Bug 947705 - Removed at request of Verne Britton <verne@wvnet.edu>
+k12.wy.us
+cc.ak.us
+cc.al.us
+cc.ar.us
+cc.as.us
+cc.az.us
+cc.ca.us
+cc.co.us
+cc.ct.us
+cc.dc.us
+cc.de.us
+cc.fl.us
+cc.ga.us
+cc.gu.us
+cc.hi.us
+cc.ia.us
+cc.id.us
+cc.il.us
+cc.in.us
+cc.ks.us
+cc.ky.us
+cc.la.us
+cc.ma.us
+cc.md.us
+cc.me.us
+cc.mi.us
+cc.mn.us
+cc.mo.us
+cc.ms.us
+cc.mt.us
+cc.nc.us
+cc.nd.us
+cc.ne.us
+cc.nh.us
+cc.nj.us
+cc.nm.us
+cc.nv.us
+cc.ny.us
+cc.oh.us
+cc.ok.us
+cc.or.us
+cc.pa.us
+cc.pr.us
+cc.ri.us
+cc.sc.us
+cc.sd.us
+cc.tn.us
+cc.tx.us
+cc.ut.us
+cc.vi.us
+cc.vt.us
+cc.va.us
+cc.wa.us
+cc.wi.us
+cc.wv.us
+cc.wy.us
+lib.ak.us
+lib.al.us
+lib.ar.us
+lib.as.us
+lib.az.us
+lib.ca.us
+lib.co.us
+lib.ct.us
+lib.dc.us
+// lib.de.us Issue #243 - Moved to Private section at request of Ed Moore <Ed.Moore@lib.de.us>
+lib.fl.us
+lib.ga.us
+lib.gu.us
+lib.hi.us
+lib.ia.us
+lib.id.us
+lib.il.us
+lib.in.us
+lib.ks.us
+lib.ky.us
+lib.la.us
+lib.ma.us
+lib.md.us
+lib.me.us
+lib.mi.us
+lib.mn.us
+lib.mo.us
+lib.ms.us
+lib.mt.us
+lib.nc.us
+lib.nd.us
+lib.ne.us
+lib.nh.us
+lib.nj.us
+lib.nm.us
+lib.nv.us
+lib.ny.us
+lib.oh.us
+lib.ok.us
+lib.or.us
+lib.pa.us
+lib.pr.us
+lib.ri.us
+lib.sc.us
+lib.sd.us
+lib.tn.us
+lib.tx.us
+lib.ut.us
+lib.vi.us
+lib.vt.us
+lib.va.us
+lib.wa.us
+lib.wi.us
+// lib.wv.us Bug 941670 - Removed at request of Larry W Arnold <arnold@wvlc.lib.wv.us>
+lib.wy.us
+// k12.ma.us contains school districts in Massachusetts. The 4LDs are
+// managed independently except for private (PVT), charter (CHTR) and
+// parochial (PAROCH) schools. Those are delegated directly to the
+// 5LD operators. <k12-ma-hostmaster _ at _ rsuc.gweep.net>
+pvt.k12.ma.us
+chtr.k12.ma.us
+paroch.k12.ma.us
+
+// uy : http://www.nic.org.uy/
+uy
+com.uy
+edu.uy
+gub.uy
+mil.uy
+net.uy
+org.uy
+
+// uz : http://www.reg.uz/
+uz
+co.uz
+com.uz
+net.uz
+org.uz
+
+// va : https://en.wikipedia.org/wiki/.va
+va
+
+// vc : https://en.wikipedia.org/wiki/.vc
+// Submitted by registry <kshah@ca.afilias.info>
+vc
+com.vc
+net.vc
+org.vc
+gov.vc
+mil.vc
+edu.vc
+
+// ve : https://registro.nic.ve/
+// Submitted by registry
+ve
+arts.ve
+co.ve
+com.ve
+e12.ve
+edu.ve
+firm.ve
+gob.ve
+gov.ve
+info.ve
+int.ve
+mil.ve
+net.ve
+org.ve
+rec.ve
+store.ve
+tec.ve
+web.ve
+
+// vg : https://en.wikipedia.org/wiki/.vg
+vg
+
+// vi : http://www.nic.vi/newdomainform.htm
+// http://www.nic.vi/Domain_Rules/body_domain_rules.html indicates some other
+// TLDs are "reserved", such as edu.vi and gov.vi, but doesn't actually say they
+// are available for registration (which they do not seem to be).
+vi
+co.vi
+com.vi
+k12.vi
+net.vi
+org.vi
+
+// vn : https://www.dot.vn/vnnic/vnnic/domainregistration.jsp
+vn
+com.vn
+net.vn
+org.vn
+edu.vn
+gov.vn
+int.vn
+ac.vn
+biz.vn
+info.vn
+name.vn
+pro.vn
+health.vn
+
+// vu : https://en.wikipedia.org/wiki/.vu
+// http://www.vunic.vu/
+vu
+com.vu
+edu.vu
+net.vu
+org.vu
+
+// wf : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+wf
+
+// ws : https://en.wikipedia.org/wiki/.ws
+// http://samoanic.ws/index.dhtml
+ws
+com.ws
+net.ws
+org.ws
+gov.ws
+edu.ws
+
+// yt : http://www.afnic.fr/medias/documents/AFNIC-naming-policy2012.pdf
+yt
+
+// IDN ccTLDs
+// When submitting patches, please maintain a sort by ISO 3166 ccTLD, then
+// U-label, and follow this format:
+// // A-Label ("<Latin renderings>", <language name>[, variant info]) : <ISO 3166 ccTLD>
+// // [sponsoring org]
+// U-Label
+
+// xn--mgbaam7a8h ("Emerat", Arabic) : AE
+// http://nic.ae/english/arabicdomain/rules.jsp
+امارات
+
+// xn--y9a3aq ("hye", Armenian) : AM
+// ISOC AM (operated by .am Registry)
+հայ
+
+// xn--54b7fta0cc ("Bangla", Bangla) : BD
+বাংলা
+
+// xn--90ais ("bel", Belarusian/Russian Cyrillic) : BY
+// Operated by .by registry
+бел
+
+// xn--fiqs8s ("Zhongguo/China", Chinese, Simplified) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中国
+
+// xn--fiqz9s ("Zhongguo/China", Chinese, Traditional) : CN
+// CNNIC
+// http://cnnic.cn/html/Dir/2005/10/11/3218.htm
+中國
+
+// xn--lgbbat1ad8j ("Algeria/Al Jazair", Arabic) : DZ
+الجزائر
+
+// xn--wgbh1c ("Egypt/Masr", Arabic) : EG
+// http://www.dotmasr.eg/
+مصر
+
+// xn--e1a4c ("eu", Cyrillic) : EU
+ею
+
+// xn--node ("ge", Georgian Mkhedruli) : GE
+გე
+
+// xn--qxam ("el", Greek) : GR
+// Hellenic Ministry of Infrastructure, Transport, and Networks
+ελ
+
+// xn--j6w193g ("Hong Kong", Chinese) : HK
+// https://www2.hkirc.hk/register/rules.jsp
+香港
+
+// xn--h2brj9c ("Bharat", Devanagari) : IN
+// India
+भारत
+
+// xn--mgbbh1a71e ("Bharat", Arabic) : IN
+// India
+بھارت
+
+// xn--fpcrj9c3d ("Bharat", Telugu) : IN
+// India
+భారత్
+
+// xn--gecrj9c ("Bharat", Gujarati) : IN
+// India
+ભારત
+
+// xn--s9brj9c ("Bharat", Gurmukhi) : IN
+// India
+ਭਾਰਤ
+
+// xn--45brj9c ("Bharat", Bengali) : IN
+// India
+ভারত
+
+// xn--xkc2dl3a5ee0h ("India", Tamil) : IN
+// India
+இந்தியா
+
+// xn--mgba3a4f16a ("Iran", Persian) : IR
+ایران
+
+// xn--mgba3a4fra ("Iran", Arabic) : IR
+ايران
+
+// xn--mgbtx2b ("Iraq", Arabic) : IQ
+// Communications and Media Commission
+عراق
+
+// xn--mgbayh7gpa ("al-Ordon", Arabic) : JO
+// National Information Technology Center (NITC)
+// Royal Scientific Society, Al-Jubeiha
+الاردن
+
+// xn--3e0b707e ("Republic of Korea", Hangul) : KR
+한국
+
+// xn--80ao21a ("Kaz", Kazakh) : KZ
+қаз
+
+// xn--fzc2c9e2c ("Lanka", Sinhalese-Sinhala) : LK
+// http://nic.lk
+ලංකා
+
+// xn--xkc2al3hye2a ("Ilangai", Tamil) : LK
+// http://nic.lk
+இலங்கை
+
+// xn--mgbc0a9azcg ("Morocco/al-Maghrib", Arabic) : MA
+المغرب
+
+// xn--d1alf ("mkd", Macedonian) : MK
+// MARnet
+мкд
+
+// xn--l1acc ("mon", Mongolian) : MN
+мон
+
+// xn--mix891f ("Macao", Chinese, Traditional) : MO
+// MONIC / HNET Asia (Registry Operator for .mo)
+澳門
+
+// xn--mix082f ("Macao", Chinese, Simplified) : MO
+澳门
+
+// xn--mgbx4cd0ab ("Malaysia", Malay) : MY
+مليسيا
+
+// xn--mgb9awbf ("Oman", Arabic) : OM
+عمان
+
+// xn--mgbai9azgqp6j ("Pakistan", Urdu/Arabic) : PK
+پاکستان
+
+// xn--mgbai9a5eva00b ("Pakistan", Urdu/Arabic, variant) : PK
+پاكستان
+
+// xn--ygbi2ammx ("Falasteen", Arabic) : PS
+// The Palestinian National Internet Naming Authority (PNINA)
+// http://www.pnina.ps
+فلسطين
+
+// xn--90a3ac ("srb", Cyrillic) : RS
+// https://www.rnids.rs/en/domains/national-domains
+срб
+пр.срб
+орг.срб
+обр.срб
+од.срб
+упр.срб
+ак.срб
+
+// xn--p1ai ("rf", Russian-Cyrillic) : RU
+// http://www.cctld.ru/en/docs/rulesrf.php
+рф
+
+// xn--wgbl6a ("Qatar", Arabic) : QA
+// http://www.ict.gov.qa/
+قطر
+
+// xn--mgberp4a5d4ar ("AlSaudiah", Arabic) : SA
+// http://www.nic.net.sa/
+السعودية
+
+// xn--mgberp4a5d4a87g ("AlSaudiah", Arabic, variant) : SA
+السعودیة
+
+// xn--mgbqly7c0a67fbc ("AlSaudiah", Arabic, variant) : SA
+السعودیۃ
+
+// xn--mgbqly7cvafr ("AlSaudiah", Arabic, variant) : SA
+السعوديه
+
+// xn--mgbpl2fh ("sudan", Arabic) : SD
+// Operated by .sd registry
+سودان
+
+// xn--yfro4i67o Singapore ("Singapore", Chinese) : SG
+新加坡
+
+// xn--clchc0ea0b2g2a9gcd ("Singapore", Tamil) : SG
+சிங்கப்பூர்
+
+// xn--ogbpf8fl ("Syria", Arabic) : SY
+سورية
+
+// xn--mgbtf8fl ("Syria", Arabic, variant) : SY
+سوريا
+
+// xn--o3cw4h ("Thai", Thai) : TH
+// http://www.thnic.co.th
+ไทย
+ศึกษา.ไทย
+ธุรกิจ.ไทย
+รัฐบาล.ไทย
+ทหาร.ไทย
+เน็ต.ไทย
+องค์กร.ไทย
+
+// xn--pgbs0dh ("Tunisia", Arabic) : TN
+// http://nic.tn
+تونس
+
+// xn--kpry57d ("Taiwan", Chinese, Traditional) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台灣
+
+// xn--kprw13d ("Taiwan", Chinese, Simplified) : TW
+// http://www.twnic.net/english/dn/dn_07a.htm
+台湾
+
+// xn--nnx388a ("Taiwan", Chinese, variant) : TW
+臺灣
+
+// xn--j1amh ("ukr", Cyrillic) : UA
+укр
+
+// xn--mgb2ddes ("AlYemen", Arabic) : YE
+اليمن
+
+// xxx : http://icmregistry.com
+xxx
+
+// ye : http://www.y.net.ye/services/domain_name.htm
+*.ye
+
+// za : http://www.zadna.org.za/content/page/domain-information
+ac.za
+agric.za
+alt.za
+co.za
+edu.za
+gov.za
+grondar.za
+law.za
+mil.za
+net.za
+ngo.za
+nis.za
+nom.za
+org.za
+school.za
+tm.za
+web.za
+
+// zm : https://zicta.zm/
+// Submitted by registry <info@zicta.zm>
+zm
+ac.zm
+biz.zm
+co.zm
+com.zm
+edu.zm
+gov.zm
+info.zm
+mil.zm
+net.zm
+org.zm
+sch.zm
+
+// zw : https://www.potraz.gov.zw/
+// Confirmed by registry <bmtengwa@potraz.gov.zw> 2017-01-25
+zw
+ac.zw
+co.zw
+gov.zw
+mil.zw
+org.zw
+
+// List of new gTLDs imported from https://newgtlds.icann.org/newgtlds.csv on 2017-02-23T00:46:09Z
+
+// aaa : 2015-02-26 American Automobile Association, Inc.
+aaa
+
+// aarp : 2015-05-21 AARP
+aarp
+
+// abarth : 2015-07-30 Fiat Chrysler Automobiles N.V.
+abarth
+
+// abb : 2014-10-24 ABB Ltd
+abb
+
+// abbott : 2014-07-24 Abbott Laboratories, Inc.
+abbott
+
+// abbvie : 2015-07-30 AbbVie Inc.
+abbvie
+
+// abc : 2015-07-30 Disney Enterprises, Inc.
+abc
+
+// able : 2015-06-25 Able Inc.
+able
+
+// abogado : 2014-04-24 Top Level Domain Holdings Limited
+abogado
+
+// abudhabi : 2015-07-30 Abu Dhabi Systems and Information Centre
+abudhabi
+
+// academy : 2013-11-07 Half Oaks, LLC
+academy
+
+// accenture : 2014-08-15 Accenture plc
+accenture
+
+// accountant : 2014-11-20 dot Accountant Limited
+accountant
+
+// accountants : 2014-03-20 Knob Town, LLC
+accountants
+
+// aco : 2015-01-08 ACO Severin Ahlmann GmbH & Co. KG
+aco
+
+// active : 2014-05-01 The Active Network, Inc
+active
+
+// actor : 2013-12-12 United TLD Holdco Ltd.
+actor
+
+// adac : 2015-07-16 Allgemeiner Deutscher Automobil-Club e.V. (ADAC)
+adac
+
+// ads : 2014-12-04 Charleston Road Registry Inc.
+ads
+
+// adult : 2014-10-16 ICM Registry AD LLC
+adult
+
+// aeg : 2015-03-19 Aktiebolaget Electrolux
+aeg
+
+// aetna : 2015-05-21 Aetna Life Insurance Company
+aetna
+
+// afamilycompany : 2015-07-23 Johnson Shareholdings, Inc.
+afamilycompany
+
+// afl : 2014-10-02 Australian Football League
+afl
+
+// africa : 2014-03-24 ZA Central Registry NPC trading as Registry.Africa
+africa
+
+// agakhan : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+agakhan
+
+// agency : 2013-11-14 Steel Falls, LLC
+agency
+
+// aig : 2014-12-18 American International Group, Inc.
+aig
+
+// aigo : 2015-08-06 aigo Digital Technology Co,Ltd.
+aigo
+
+// airbus : 2015-07-30 Airbus S.A.S.
+airbus
+
+// airforce : 2014-03-06 United TLD Holdco Ltd.
+airforce
+
+// airtel : 2014-10-24 Bharti Airtel Limited
+airtel
+
+// akdn : 2015-04-23 Fondation Aga Khan (Aga Khan Foundation)
+akdn
+
+// alfaromeo : 2015-07-31 Fiat Chrysler Automobiles N.V.
+alfaromeo
+
+// alibaba : 2015-01-15 Alibaba Group Holding Limited
+alibaba
+
+// alipay : 2015-01-15 Alibaba Group Holding Limited
+alipay
+
+// allfinanz : 2014-07-03 Allfinanz Deutsche Vermögensberatung Aktiengesellschaft
+allfinanz
+
+// allstate : 2015-07-31 Allstate Fire and Casualty Insurance Company
+allstate
+
+// ally : 2015-06-18 Ally Financial Inc.
+ally
+
+// alsace : 2014-07-02 REGION D ALSACE
+alsace
+
+// alstom : 2015-07-30 ALSTOM
+alstom
+
+// americanexpress : 2015-07-31 American Express Travel Related Services Company, Inc.
+americanexpress
+
+// americanfamily : 2015-07-23 AmFam, Inc.
+americanfamily
+
+// amex : 2015-07-31 American Express Travel Related Services Company, Inc.
+amex
+
+// amfam : 2015-07-23 AmFam, Inc.
+amfam
+
+// amica : 2015-05-28 Amica Mutual Insurance Company
+amica
+
+// amsterdam : 2014-07-24 Gemeente Amsterdam
+amsterdam
+
+// analytics : 2014-12-18 Campus IP LLC
+analytics
+
+// android : 2014-08-07 Charleston Road Registry Inc.
+android
+
+// anquan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+anquan
+
+// anz : 2015-07-31 Australia and New Zealand Banking Group Limited
+anz
+
+// aol : 2015-09-17 AOL Inc.
+aol
+
+// apartments : 2014-12-11 June Maple, LLC
+apartments
+
+// app : 2015-05-14 Charleston Road Registry Inc.
+app
+
+// apple : 2015-05-14 Apple Inc.
+apple
+
+// aquarelle : 2014-07-24 Aquarelle.com
+aquarelle
+
+// arab : 2015-11-12 League of Arab States
+arab
+
+// aramco : 2014-11-20 Aramco Services Company
+aramco
+
+// archi : 2014-02-06 STARTING DOT LIMITED
+archi
+
+// army : 2014-03-06 United TLD Holdco Ltd.
+army
+
+// art : 2016-03-24 UK Creative Ideas Limited
+art
+
+// arte : 2014-12-11 Association Relative à la Télévision Européenne G.E.I.E.
+arte
+
+// asda : 2015-07-31 Wal-Mart Stores, Inc.
+asda
+
+// associates : 2014-03-06 Baxter Hill, LLC
+associates
+
+// athleta : 2015-07-30 The Gap, Inc.
+athleta
+
+// attorney : 2014-03-20
+attorney
+
+// auction : 2014-03-20
+auction
+
+// audi : 2015-05-21 AUDI Aktiengesellschaft
+audi
+
+// audible : 2015-06-25 Amazon EU S.à r.l.
+audible
+
+// audio : 2014-03-20 Uniregistry, Corp.
+audio
+
+// auspost : 2015-08-13 Australian Postal Corporation
+auspost
+
+// author : 2014-12-18 Amazon EU S.à r.l.
+author
+
+// auto : 2014-11-13
+auto
+
+// autos : 2014-01-09 DERAutos, LLC
+autos
+
+// avianca : 2015-01-08 Aerovias del Continente Americano S.A. Avianca
+avianca
+
+// aws : 2015-06-25 Amazon EU S.à r.l.
+aws
+
+// axa : 2013-12-19 AXA SA
+axa
+
+// azure : 2014-12-18 Microsoft Corporation
+azure
+
+// baby : 2015-04-09 Johnson & Johnson Services, Inc.
+baby
+
+// baidu : 2015-01-08 Baidu, Inc.
+baidu
+
+// banamex : 2015-07-30 Citigroup Inc.
+banamex
+
+// bananarepublic : 2015-07-31 The Gap, Inc.
+bananarepublic
+
+// band : 2014-06-12
+band
+
+// bank : 2014-09-25 fTLD Registry Services LLC
+bank
+
+// bar : 2013-12-12 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+bar
+
+// barcelona : 2014-07-24 Municipi de Barcelona
+barcelona
+
+// barclaycard : 2014-11-20 Barclays Bank PLC
+barclaycard
+
+// barclays : 2014-11-20 Barclays Bank PLC
+barclays
+
+// barefoot : 2015-06-11 Gallo Vineyards, Inc.
+barefoot
+
+// bargains : 2013-11-14 Half Hallow, LLC
+bargains
+
+// baseball : 2015-10-29 MLB Advanced Media DH, LLC
+baseball
+
+// basketball : 2015-08-20 Fédération Internationale de Basketball (FIBA)
+basketball
+
+// bauhaus : 2014-04-17 Werkhaus GmbH
+bauhaus
+
+// bayern : 2014-01-23 Bayern Connect GmbH
+bayern
+
+// bbc : 2014-12-18 British Broadcasting Corporation
+bbc
+
+// bbt : 2015-07-23 BB&T Corporation
+bbt
+
+// bbva : 2014-10-02 BANCO BILBAO VIZCAYA ARGENTARIA, S.A.
+bbva
+
+// bcg : 2015-04-02 The Boston Consulting Group, Inc.
+bcg
+
+// bcn : 2014-07-24 Municipi de Barcelona
+bcn
+
+// beats : 2015-05-14 Beats Electronics, LLC
+beats
+
+// beauty : 2015-12-03 L'Oréal
+beauty
+
+// beer : 2014-01-09 Top Level Domain Holdings Limited
+beer
+
+// bentley : 2014-12-18 Bentley Motors Limited
+bentley
+
+// berlin : 2013-10-31 dotBERLIN GmbH & Co. KG
+berlin
+
+// best : 2013-12-19 BestTLD Pty Ltd
+best
+
+// bestbuy : 2015-07-31 BBY Solutions, Inc.
+bestbuy
+
+// bet : 2015-05-07 Afilias plc
+bet
+
+// bharti : 2014-01-09 Bharti Enterprises (Holding) Private Limited
+bharti
+
+// bible : 2014-06-19 American Bible Society
+bible
+
+// bid : 2013-12-19 dot Bid Limited
+bid
+
+// bike : 2013-08-27 Grand Hollow, LLC
+bike
+
+// bing : 2014-12-18 Microsoft Corporation
+bing
+
+// bingo : 2014-12-04 Sand Cedar, LLC
+bingo
+
+// bio : 2014-03-06 STARTING DOT LIMITED
+bio
+
+// black : 2014-01-16 Afilias Limited
+black
+
+// blackfriday : 2014-01-16 Uniregistry, Corp.
+blackfriday
+
+// blanco : 2015-07-16 BLANCO GmbH + Co KG
+blanco
+
+// blockbuster : 2015-07-30 Dish DBS Corporation
+blockbuster
+
+// blog : 2015-05-14
+blog
+
+// bloomberg : 2014-07-17 Bloomberg IP Holdings LLC
+bloomberg
+
+// blue : 2013-11-07 Afilias Limited
+blue
+
+// bms : 2014-10-30 Bristol-Myers Squibb Company
+bms
+
+// bmw : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+bmw
+
+// bnl : 2014-07-24 Banca Nazionale del Lavoro
+bnl
+
+// bnpparibas : 2014-05-29 BNP Paribas
+bnpparibas
+
+// boats : 2014-12-04 DERBoats, LLC
+boats
+
+// boehringer : 2015-07-09 Boehringer Ingelheim International GmbH
+boehringer
+
+// bofa : 2015-07-31 NMS Services, Inc.
+bofa
+
+// bom : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+bom
+
+// bond : 2014-06-05 Bond University Limited
+bond
+
+// boo : 2014-01-30 Charleston Road Registry Inc.
+boo
+
+// book : 2015-08-27 Amazon EU S.à r.l.
+book
+
+// booking : 2015-07-16 Booking.com B.V.
+booking
+
+// boots : 2015-01-08 THE BOOTS COMPANY PLC
+boots
+
+// bosch : 2015-06-18 Robert Bosch GMBH
+bosch
+
+// bostik : 2015-05-28 Bostik SA
+bostik
+
+// boston : 2015-12-10
+boston
+
+// bot : 2014-12-18 Amazon EU S.à r.l.
+bot
+
+// boutique : 2013-11-14 Over Galley, LLC
+boutique
+
+// box : 2015-11-12 NS1 Limited
+box
+
+// bradesco : 2014-12-18 Banco Bradesco S.A.
+bradesco
+
+// bridgestone : 2014-12-18 Bridgestone Corporation
+bridgestone
+
+// broadway : 2014-12-22 Celebrate Broadway, Inc.
+broadway
+
+// broker : 2014-12-11 IG Group Holdings PLC
+broker
+
+// brother : 2015-01-29 Brother Industries, Ltd.
+brother
+
+// brussels : 2014-02-06 DNS.be vzw
+brussels
+
+// budapest : 2013-11-21 Top Level Domain Holdings Limited
+budapest
+
+// bugatti : 2015-07-23 Bugatti International SA
+bugatti
+
+// build : 2013-11-07 Plan Bee LLC
+build
+
+// builders : 2013-11-07 Atomic Madison, LLC
+builders
+
+// business : 2013-11-07 Spring Cross, LLC
+business
+
+// buy : 2014-12-18 Amazon EU S.à r.l.
+buy
+
+// buzz : 2013-10-02 DOTSTRATEGY CO.
+buzz
+
+// bzh : 2014-02-27 Association www.bzh
+bzh
+
+// cab : 2013-10-24 Half Sunset, LLC
+cab
+
+// cafe : 2015-02-11 Pioneer Canyon, LLC
+cafe
+
+// cal : 2014-07-24 Charleston Road Registry Inc.
+cal
+
+// call : 2014-12-18 Amazon EU S.à r.l.
+call
+
+// calvinklein : 2015-07-30 PVH gTLD Holdings LLC
+calvinklein
+
+// cam : 2016-04-21 AC Webconnecting Holding B.V.
+cam
+
+// camera : 2013-08-27 Atomic Maple, LLC
+camera
+
+// camp : 2013-11-07 Delta Dynamite, LLC
+camp
+
+// cancerresearch : 2014-05-15 Australian Cancer Research Foundation
+cancerresearch
+
+// canon : 2014-09-12 Canon Inc.
+canon
+
+// capetown : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+capetown
+
+// capital : 2014-03-06 Delta Mill, LLC
+capital
+
+// capitalone : 2015-08-06 Capital One Financial Corporation
+capitalone
+
+// car : 2015-01-22
+car
+
+// caravan : 2013-12-12 Caravan International, Inc.
+caravan
+
+// cards : 2013-12-05 Foggy Hollow, LLC
+cards
+
+// care : 2014-03-06 Goose Cross
+care
+
+// career : 2013-10-09 dotCareer LLC
+career
+
+// careers : 2013-10-02 Wild Corner, LLC
+careers
+
+// cars : 2014-11-13
+cars
+
+// cartier : 2014-06-23 Richemont DNS Inc.
+cartier
+
+// casa : 2013-11-21 Top Level Domain Holdings Limited
+casa
+
+// case : 2015-09-03 CNH Industrial N.V.
+case
+
+// caseih : 2015-09-03 CNH Industrial N.V.
+caseih
+
+// cash : 2014-03-06 Delta Lake, LLC
+cash
+
+// casino : 2014-12-18 Binky Sky, LLC
+casino
+
+// catering : 2013-12-05 New Falls. LLC
+catering
+
+// catholic : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+catholic
+
+// cba : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+cba
+
+// cbn : 2014-08-22 The Christian Broadcasting Network, Inc.
+cbn
+
+// cbre : 2015-07-02 CBRE, Inc.
+cbre
+
+// cbs : 2015-08-06 CBS Domains Inc.
+cbs
+
+// ceb : 2015-04-09 The Corporate Executive Board Company
+ceb
+
+// center : 2013-11-07 Tin Mill, LLC
+center
+
+// ceo : 2013-11-07 CEOTLD Pty Ltd
+ceo
+
+// cern : 2014-06-05 European Organization for Nuclear Research ("CERN")
+cern
+
+// cfa : 2014-08-28 CFA Institute
+cfa
+
+// cfd : 2014-12-11 IG Group Holdings PLC
+cfd
+
+// chanel : 2015-04-09 Chanel International B.V.
+chanel
+
+// channel : 2014-05-08 Charleston Road Registry Inc.
+channel
+
+// chase : 2015-04-30 JPMorgan Chase & Co.
+chase
+
+// chat : 2014-12-04 Sand Fields, LLC
+chat
+
+// cheap : 2013-11-14 Sand Cover, LLC
+cheap
+
+// chintai : 2015-06-11 CHINTAI Corporation
+chintai
+
+// chloe : 2014-10-16 Richemont DNS Inc.
+chloe
+
+// christmas : 2013-11-21 Uniregistry, Corp.
+christmas
+
+// chrome : 2014-07-24 Charleston Road Registry Inc.
+chrome
+
+// chrysler : 2015-07-30 FCA US LLC.
+chrysler
+
+// church : 2014-02-06 Holly Fields, LLC
+church
+
+// cipriani : 2015-02-19 Hotel Cipriani Srl
+cipriani
+
+// circle : 2014-12-18 Amazon EU S.à r.l.
+circle
+
+// cisco : 2014-12-22 Cisco Technology, Inc.
+cisco
+
+// citadel : 2015-07-23 Citadel Domain LLC
+citadel
+
+// citi : 2015-07-30 Citigroup Inc.
+citi
+
+// citic : 2014-01-09 CITIC Group Corporation
+citic
+
+// city : 2014-05-29 Snow Sky, LLC
+city
+
+// cityeats : 2014-12-11 Lifestyle Domain Holdings, Inc.
+cityeats
+
+// claims : 2014-03-20 Black Corner, LLC
+claims
+
+// cleaning : 2013-12-05 Fox Shadow, LLC
+cleaning
+
+// click : 2014-06-05 Uniregistry, Corp.
+click
+
+// clinic : 2014-03-20 Goose Park, LLC
+clinic
+
+// clinique : 2015-10-01 The Estée Lauder Companies Inc.
+clinique
+
+// clothing : 2013-08-27 Steel Lake, LLC
+clothing
+
+// cloud : 2015-04-16 ARUBA S.p.A.
+cloud
+
+// club : 2013-11-08 .CLUB DOMAINS, LLC
+club
+
+// clubmed : 2015-06-25 Club Méditerranée S.A.
+clubmed
+
+// coach : 2014-10-09 Koko Island, LLC
+coach
+
+// codes : 2013-10-31 Puff Willow, LLC
+codes
+
+// coffee : 2013-10-17 Trixy Cover, LLC
+coffee
+
+// college : 2014-01-16 XYZ.COM LLC
+college
+
+// cologne : 2014-02-05 NetCologne Gesellschaft für Telekommunikation mbH
+cologne
+
+// comcast : 2015-07-23 Comcast IP Holdings I, LLC
+comcast
+
+// commbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+commbank
+
+// community : 2013-12-05 Fox Orchard, LLC
+community
+
+// company : 2013-11-07 Silver Avenue, LLC
+company
+
+// compare : 2015-10-08 iSelect Ltd
+compare
+
+// computer : 2013-10-24 Pine Mill, LLC
+computer
+
+// comsec : 2015-01-08 VeriSign, Inc.
+comsec
+
+// condos : 2013-12-05 Pine House, LLC
+condos
+
+// construction : 2013-09-16 Fox Dynamite, LLC
+construction
+
+// consulting : 2013-12-05
+consulting
+
+// contact : 2015-01-08 Top Level Spectrum, Inc.
+contact
+
+// contractors : 2013-09-10 Magic Woods, LLC
+contractors
+
+// cooking : 2013-11-21 Top Level Domain Holdings Limited
+cooking
+
+// cookingchannel : 2015-07-02 Lifestyle Domain Holdings, Inc.
+cookingchannel
+
+// cool : 2013-11-14 Koko Lake, LLC
+cool
+
+// corsica : 2014-09-25 Collectivité Territoriale de Corse
+corsica
+
+// country : 2013-12-19 Top Level Domain Holdings Limited
+country
+
+// coupon : 2015-02-26 Amazon EU S.à r.l.
+coupon
+
+// coupons : 2015-03-26 Black Island, LLC
+coupons
+
+// courses : 2014-12-04 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+courses
+
+// credit : 2014-03-20 Snow Shadow, LLC
+credit
+
+// creditcard : 2014-03-20 Binky Frostbite, LLC
+creditcard
+
+// creditunion : 2015-01-22 CUNA Performance Resources, LLC
+creditunion
+
+// cricket : 2014-10-09 dot Cricket Limited
+cricket
+
+// crown : 2014-10-24 Crown Equipment Corporation
+crown
+
+// crs : 2014-04-03 Federated Co-operatives Limited
+crs
+
+// cruise : 2015-12-10 Viking River Cruises (Bermuda) Ltd.
+cruise
+
+// cruises : 2013-12-05 Spring Way, LLC
+cruises
+
+// csc : 2014-09-25 Alliance-One Services, Inc.
+csc
+
+// cuisinella : 2014-04-03 SALM S.A.S.
+cuisinella
+
+// cymru : 2014-05-08 Nominet UK
+cymru
+
+// cyou : 2015-01-22 Beijing Gamease Age Digital Technology Co., Ltd.
+cyou
+
+// dabur : 2014-02-06 Dabur India Limited
+dabur
+
+// dad : 2014-01-23 Charleston Road Registry Inc.
+dad
+
+// dance : 2013-10-24 United TLD Holdco Ltd.
+dance
+
+// data : 2016-06-02 Dish DBS Corporation
+data
+
+// date : 2014-11-20 dot Date Limited
+date
+
+// dating : 2013-12-05 Pine Fest, LLC
+dating
+
+// datsun : 2014-03-27 NISSAN MOTOR CO., LTD.
+datsun
+
+// day : 2014-01-30 Charleston Road Registry Inc.
+day
+
+// dclk : 2014-11-20 Charleston Road Registry Inc.
+dclk
+
+// dds : 2015-05-07 Top Level Domain Holdings Limited
+dds
+
+// deal : 2015-06-25 Amazon EU S.à r.l.
+deal
+
+// dealer : 2014-12-22 Dealer Dot Com, Inc.
+dealer
+
+// deals : 2014-05-22 Sand Sunset, LLC
+deals
+
+// degree : 2014-03-06
+degree
+
+// delivery : 2014-09-11 Steel Station, LLC
+delivery
+
+// dell : 2014-10-24 Dell Inc.
+dell
+
+// deloitte : 2015-07-31 Deloitte Touche Tohmatsu
+deloitte
+
+// delta : 2015-02-19 Delta Air Lines, Inc.
+delta
+
+// democrat : 2013-10-24 United TLD Holdco Ltd.
+democrat
+
+// dental : 2014-03-20 Tin Birch, LLC
+dental
+
+// dentist : 2014-03-20
+dentist
+
+// desi : 2013-11-14 Desi Networks LLC
+desi
+
+// design : 2014-11-07 Top Level Design, LLC
+design
+
+// dev : 2014-10-16 Charleston Road Registry Inc.
+dev
+
+// dhl : 2015-07-23 Deutsche Post AG
+dhl
+
+// diamonds : 2013-09-22 John Edge, LLC
+diamonds
+
+// diet : 2014-06-26 Uniregistry, Corp.
+diet
+
+// digital : 2014-03-06 Dash Park, LLC
+digital
+
+// direct : 2014-04-10 Half Trail, LLC
+direct
+
+// directory : 2013-09-20 Extra Madison, LLC
+directory
+
+// discount : 2014-03-06 Holly Hill, LLC
+discount
+
+// discover : 2015-07-23 Discover Financial Services
+discover
+
+// dish : 2015-07-30 Dish DBS Corporation
+dish
+
+// diy : 2015-11-05 Lifestyle Domain Holdings, Inc.
+diy
+
+// dnp : 2013-12-13 Dai Nippon Printing Co., Ltd.
+dnp
+
+// docs : 2014-10-16 Charleston Road Registry Inc.
+docs
+
+// doctor : 2016-06-02 Brice Trail, LLC
+doctor
+
+// dodge : 2015-07-30 FCA US LLC.
+dodge
+
+// dog : 2014-12-04 Koko Mill, LLC
+dog
+
+// doha : 2014-09-18 Communications Regulatory Authority (CRA)
+doha
+
+// domains : 2013-10-17 Sugar Cross, LLC
+domains
+
+// dot : 2015-05-21 Dish DBS Corporation
+dot
+
+// download : 2014-11-20 dot Support Limited
+download
+
+// drive : 2015-03-05 Charleston Road Registry Inc.
+drive
+
+// dtv : 2015-06-04 Dish DBS Corporation
+dtv
+
+// dubai : 2015-01-01 Dubai Smart Government Department
+dubai
+
+// duck : 2015-07-23 Johnson Shareholdings, Inc.
+duck
+
+// dunlop : 2015-07-02 The Goodyear Tire & Rubber Company
+dunlop
+
+// duns : 2015-08-06 The Dun & Bradstreet Corporation
+duns
+
+// dupont : 2015-06-25 E. I. du Pont de Nemours and Company
+dupont
+
+// durban : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+durban
+
+// dvag : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+dvag
+
+// dvr : 2016-05-26 Hughes Satellite Systems Corporation
+dvr
+
+// earth : 2014-12-04 Interlink Co., Ltd.
+earth
+
+// eat : 2014-01-23 Charleston Road Registry Inc.
+eat
+
+// eco : 2016-07-08 Big Room Inc.
+eco
+
+// edeka : 2014-12-18 EDEKA Verband kaufmännischer Genossenschaften e.V.
+edeka
+
+// education : 2013-11-07 Brice Way, LLC
+education
+
+// email : 2013-10-31 Spring Madison, LLC
+email
+
+// emerck : 2014-04-03 Merck KGaA
+emerck
+
+// energy : 2014-09-11 Binky Birch, LLC
+energy
+
+// engineer : 2014-03-06 United TLD Holdco Ltd.
+engineer
+
+// engineering : 2014-03-06 Romeo Canyon
+engineering
+
+// enterprises : 2013-09-20 Snow Oaks, LLC
+enterprises
+
+// epost : 2015-07-23 Deutsche Post AG
+epost
+
+// epson : 2014-12-04 Seiko Epson Corporation
+epson
+
+// equipment : 2013-08-27 Corn Station, LLC
+equipment
+
+// ericsson : 2015-07-09 Telefonaktiebolaget L M Ericsson
+ericsson
+
+// erni : 2014-04-03 ERNI Group Holding AG
+erni
+
+// esq : 2014-05-08 Charleston Road Registry Inc.
+esq
+
+// estate : 2013-08-27 Trixy Park, LLC
+estate
+
+// esurance : 2015-07-23 Esurance Insurance Company
+esurance
+
+// etisalat : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
+etisalat
+
+// eurovision : 2014-04-24 European Broadcasting Union (EBU)
+eurovision
+
+// eus : 2013-12-12 Puntueus Fundazioa
+eus
+
+// events : 2013-12-05 Pioneer Maple, LLC
+events
+
+// everbank : 2014-05-15 EverBank
+everbank
+
+// exchange : 2014-03-06 Spring Falls, LLC
+exchange
+
+// expert : 2013-11-21 Magic Pass, LLC
+expert
+
+// exposed : 2013-12-05 Victor Beach, LLC
+exposed
+
+// express : 2015-02-11 Sea Sunset, LLC
+express
+
+// extraspace : 2015-05-14 Extra Space Storage LLC
+extraspace
+
+// fage : 2014-12-18 Fage International S.A.
+fage
+
+// fail : 2014-03-06 Atomic Pipe, LLC
+fail
+
+// fairwinds : 2014-11-13 FairWinds Partners, LLC
+fairwinds
+
+// faith : 2014-11-20 dot Faith Limited
+faith
+
+// family : 2015-04-02
+family
+
+// fan : 2014-03-06
+fan
+
+// fans : 2014-11-07 Asiamix Digital Limited
+fans
+
+// farm : 2013-11-07 Just Maple, LLC
+farm
+
+// farmers : 2015-07-09 Farmers Insurance Exchange
+farmers
+
+// fashion : 2014-07-03 Top Level Domain Holdings Limited
+fashion
+
+// fast : 2014-12-18 Amazon EU S.à r.l.
+fast
+
+// fedex : 2015-08-06 Federal Express Corporation
+fedex
+
+// feedback : 2013-12-19 Top Level Spectrum, Inc.
+feedback
+
+// ferrari : 2015-07-31 Fiat Chrysler Automobiles N.V.
+ferrari
+
+// ferrero : 2014-12-18 Ferrero Trading Lux S.A.
+ferrero
+
+// fiat : 2015-07-31 Fiat Chrysler Automobiles N.V.
+fiat
+
+// fidelity : 2015-07-30 Fidelity Brokerage Services LLC
+fidelity
+
+// fido : 2015-08-06 Rogers Communications Partnership
+fido
+
+// film : 2015-01-08 Motion Picture Domain Registry Pty Ltd
+film
+
+// final : 2014-10-16 Núcleo de Informação e Coordenação do Ponto BR - NIC.br
+final
+
+// finance : 2014-03-20 Cotton Cypress, LLC
+finance
+
+// financial : 2014-03-06 Just Cover, LLC
+financial
+
+// fire : 2015-06-25 Amazon EU S.à r.l.
+fire
+
+// firestone : 2014-12-18 Bridgestone Corporation
+firestone
+
+// firmdale : 2014-03-27 Firmdale Holdings Limited
+firmdale
+
+// fish : 2013-12-12 Fox Woods, LLC
+fish
+
+// fishing : 2013-11-21 Top Level Domain Holdings Limited
+fishing
+
+// fit : 2014-11-07 Top Level Domain Holdings Limited
+fit
+
+// fitness : 2014-03-06 Brice Orchard, LLC
+fitness
+
+// flickr : 2015-04-02 Yahoo! Domain Services Inc.
+flickr
+
+// flights : 2013-12-05 Fox Station, LLC
+flights
+
+// flir : 2015-07-23 FLIR Systems, Inc.
+flir
+
+// florist : 2013-11-07 Half Cypress, LLC
+florist
+
+// flowers : 2014-10-09 Uniregistry, Corp.
+flowers
+
+// fly : 2014-05-08 Charleston Road Registry Inc.
+fly
+
+// foo : 2014-01-23 Charleston Road Registry Inc.
+foo
+
+// food : 2016-04-21 Lifestyle Domain Holdings, Inc.
+food
+
+// foodnetwork : 2015-07-02 Lifestyle Domain Holdings, Inc.
+foodnetwork
+
+// football : 2014-12-18 Foggy Farms, LLC
+football
+
+// ford : 2014-11-13 Ford Motor Company
+ford
+
+// forex : 2014-12-11 IG Group Holdings PLC
+forex
+
+// forsale : 2014-05-22
+forsale
+
+// forum : 2015-04-02 Fegistry, LLC
+forum
+
+// foundation : 2013-12-05 John Dale, LLC
+foundation
+
+// fox : 2015-09-11 FOX Registry, LLC
+fox
+
+// free : 2015-12-10 Amazon EU S.à r.l.
+free
+
+// fresenius : 2015-07-30 Fresenius Immobilien-Verwaltungs-GmbH
+fresenius
+
+// frl : 2014-05-15 FRLregistry B.V.
+frl
+
+// frogans : 2013-12-19 OP3FT
+frogans
+
+// frontdoor : 2015-07-02 Lifestyle Domain Holdings, Inc.
+frontdoor
+
+// frontier : 2015-02-05 Frontier Communications Corporation
+frontier
+
+// ftr : 2015-07-16 Frontier Communications Corporation
+ftr
+
+// fujitsu : 2015-07-30 Fujitsu Limited
+fujitsu
+
+// fujixerox : 2015-07-23 Xerox DNHC LLC
+fujixerox
+
+// fun : 2016-01-14
+fun
+
+// fund : 2014-03-20 John Castle, LLC
+fund
+
+// furniture : 2014-03-20 Lone Fields, LLC
+furniture
+
+// futbol : 2013-09-20
+futbol
+
+// fyi : 2015-04-02 Silver Tigers, LLC
+fyi
+
+// gal : 2013-11-07 Asociación puntoGAL
+gal
+
+// gallery : 2013-09-13 Sugar House, LLC
+gallery
+
+// gallo : 2015-06-11 Gallo Vineyards, Inc.
+gallo
+
+// gallup : 2015-02-19 Gallup, Inc.
+gallup
+
+// game : 2015-05-28 Uniregistry, Corp.
+game
+
+// games : 2015-05-28
+games
+
+// gap : 2015-07-31 The Gap, Inc.
+gap
+
+// garden : 2014-06-26 Top Level Domain Holdings Limited
+garden
+
+// gbiz : 2014-07-17 Charleston Road Registry Inc.
+gbiz
+
+// gdn : 2014-07-31 Joint Stock Company "Navigation-information systems"
+gdn
+
+// gea : 2014-12-04 GEA Group Aktiengesellschaft
+gea
+
+// gent : 2014-01-23 COMBELL GROUP NV/SA
+gent
+
+// genting : 2015-03-12 Resorts World Inc Pte. Ltd.
+genting
+
+// george : 2015-07-31 Wal-Mart Stores, Inc.
+george
+
+// ggee : 2014-01-09 GMO Internet, Inc.
+ggee
+
+// gift : 2013-10-17 Uniregistry, Corp.
+gift
+
+// gifts : 2014-07-03 Goose Sky, LLC
+gifts
+
+// gives : 2014-03-06 United TLD Holdco Ltd.
+gives
+
+// giving : 2014-11-13 Giving Limited
+giving
+
+// glade : 2015-07-23 Johnson Shareholdings, Inc.
+glade
+
+// glass : 2013-11-07 Black Cover, LLC
+glass
+
+// gle : 2014-07-24 Charleston Road Registry Inc.
+gle
+
+// global : 2014-04-17 Dot GLOBAL AS
+global
+
+// globo : 2013-12-19 Globo Comunicação e Participações S.A
+globo
+
+// gmail : 2014-05-01 Charleston Road Registry Inc.
+gmail
+
+// gmbh : 2016-01-29 Extra Dynamite, LLC
+gmbh
+
+// gmo : 2014-01-09 GMO Internet, Inc.
+gmo
+
+// gmx : 2014-04-24 1&1 Mail & Media GmbH
+gmx
+
+// godaddy : 2015-07-23 Go Daddy East, LLC
+godaddy
+
+// gold : 2015-01-22 June Edge, LLC
+gold
+
+// goldpoint : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+goldpoint
+
+// golf : 2014-12-18 Lone falls, LLC
+golf
+
+// goo : 2014-12-18 NTT Resonant Inc.
+goo
+
+// goodhands : 2015-07-31 Allstate Fire and Casualty Insurance Company
+goodhands
+
+// goodyear : 2015-07-02 The Goodyear Tire & Rubber Company
+goodyear
+
+// goog : 2014-11-20 Charleston Road Registry Inc.
+goog
+
+// google : 2014-07-24 Charleston Road Registry Inc.
+google
+
+// gop : 2014-01-16 Republican State Leadership Committee, Inc.
+gop
+
+// got : 2014-12-18 Amazon EU S.à r.l.
+got
+
+// grainger : 2015-05-07 Grainger Registry Services, LLC
+grainger
+
+// graphics : 2013-09-13 Over Madison, LLC
+graphics
+
+// gratis : 2014-03-20 Pioneer Tigers, LLC
+gratis
+
+// green : 2014-05-08 Afilias Limited
+green
+
+// gripe : 2014-03-06 Corn Sunset, LLC
+gripe
+
+// grocery : 2016-06-16 Wal-Mart Stores, Inc.
+grocery
+
+// group : 2014-08-15 Romeo Town, LLC
+group
+
+// guardian : 2015-07-30 The Guardian Life Insurance Company of America
+guardian
+
+// gucci : 2014-11-13 Guccio Gucci S.p.a.
+gucci
+
+// guge : 2014-08-28 Charleston Road Registry Inc.
+guge
+
+// guide : 2013-09-13 Snow Moon, LLC
+guide
+
+// guitars : 2013-11-14 Uniregistry, Corp.
+guitars
+
+// guru : 2013-08-27 Pioneer Cypress, LLC
+guru
+
+// hair : 2015-12-03 L'Oréal
+hair
+
+// hamburg : 2014-02-20 Hamburg Top-Level-Domain GmbH
+hamburg
+
+// hangout : 2014-11-13 Charleston Road Registry Inc.
+hangout
+
+// haus : 2013-12-05
+haus
+
+// hbo : 2015-07-30 HBO Registry Services, Inc.
+hbo
+
+// hdfc : 2015-07-30 HOUSING DEVELOPMENT FINANCE CORPORATION LIMITED
+hdfc
+
+// hdfcbank : 2015-02-12 HDFC Bank Limited
+hdfcbank
+
+// health : 2015-02-11 DotHealth, LLC
+health
+
+// healthcare : 2014-06-12 Silver Glen, LLC
+healthcare
+
+// help : 2014-06-26 Uniregistry, Corp.
+help
+
+// helsinki : 2015-02-05 City of Helsinki
+helsinki
+
+// here : 2014-02-06 Charleston Road Registry Inc.
+here
+
+// hermes : 2014-07-10 HERMES INTERNATIONAL
+hermes
+
+// hgtv : 2015-07-02 Lifestyle Domain Holdings, Inc.
+hgtv
+
+// hiphop : 2014-03-06 Uniregistry, Corp.
+hiphop
+
+// hisamitsu : 2015-07-16 Hisamitsu Pharmaceutical Co.,Inc.
+hisamitsu
+
+// hitachi : 2014-10-31 Hitachi, Ltd.
+hitachi
+
+// hiv : 2014-03-13
+hiv
+
+// hkt : 2015-05-14 PCCW-HKT DataCom Services Limited
+hkt
+
+// hockey : 2015-03-19 Half Willow, LLC
+hockey
+
+// holdings : 2013-08-27 John Madison, LLC
+holdings
+
+// holiday : 2013-11-07 Goose Woods, LLC
+holiday
+
+// homedepot : 2015-04-02 Homer TLC, Inc.
+homedepot
+
+// homegoods : 2015-07-16 The TJX Companies, Inc.
+homegoods
+
+// homes : 2014-01-09 DERHomes, LLC
+homes
+
+// homesense : 2015-07-16 The TJX Companies, Inc.
+homesense
+
+// honda : 2014-12-18 Honda Motor Co., Ltd.
+honda
+
+// honeywell : 2015-07-23 Honeywell GTLD LLC
+honeywell
+
+// horse : 2013-11-21 Top Level Domain Holdings Limited
+horse
+
+// hospital : 2016-10-20 Ruby Pike, LLC
+hospital
+
+// host : 2014-04-17 DotHost Inc.
+host
+
+// hosting : 2014-05-29 Uniregistry, Corp.
+hosting
+
+// hot : 2015-08-27 Amazon EU S.à r.l.
+hot
+
+// hoteles : 2015-03-05 Travel Reservations SRL
+hoteles
+
+// hotels : 2016-04-07 Booking.com B.V.
+hotels
+
+// hotmail : 2014-12-18 Microsoft Corporation
+hotmail
+
+// house : 2013-11-07 Sugar Park, LLC
+house
+
+// how : 2014-01-23 Charleston Road Registry Inc.
+how
+
+// hsbc : 2014-10-24 HSBC Holdings PLC
+hsbc
+
+// htc : 2015-04-02 HTC corporation
+htc
+
+// hughes : 2015-07-30 Hughes Satellite Systems Corporation
+hughes
+
+// hyatt : 2015-07-30 Hyatt GTLD, L.L.C.
+hyatt
+
+// hyundai : 2015-07-09 Hyundai Motor Company
+hyundai
+
+// ibm : 2014-07-31 International Business Machines Corporation
+ibm
+
+// icbc : 2015-02-19 Industrial and Commercial Bank of China Limited
+icbc
+
+// ice : 2014-10-30 IntercontinentalExchange, Inc.
+ice
+
+// icu : 2015-01-08 One.com A/S
+icu
+
+// ieee : 2015-07-23 IEEE Global LLC
+ieee
+
+// ifm : 2014-01-30 ifm electronic gmbh
+ifm
+
+// ikano : 2015-07-09 Ikano S.A.
+ikano
+
+// imamat : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+imamat
+
+// imdb : 2015-06-25 Amazon EU S.à r.l.
+imdb
+
+// immo : 2014-07-10 Auburn Bloom, LLC
+immo
+
+// immobilien : 2013-11-07 United TLD Holdco Ltd.
+immobilien
+
+// industries : 2013-12-05 Outer House, LLC
+industries
+
+// infiniti : 2014-03-27 NISSAN MOTOR CO., LTD.
+infiniti
+
+// ing : 2014-01-23 Charleston Road Registry Inc.
+ing
+
+// ink : 2013-12-05 Top Level Design, LLC
+ink
+
+// institute : 2013-11-07 Outer Maple, LLC
+institute
+
+// insurance : 2015-02-19 fTLD Registry Services LLC
+insurance
+
+// insure : 2014-03-20 Pioneer Willow, LLC
+insure
+
+// intel : 2015-08-06 Intel Corporation
+intel
+
+// international : 2013-11-07 Wild Way, LLC
+international
+
+// intuit : 2015-07-30 Intuit Administrative Services, Inc.
+intuit
+
+// investments : 2014-03-20 Holly Glen, LLC
+investments
+
+// ipiranga : 2014-08-28 Ipiranga Produtos de Petroleo S.A.
+ipiranga
+
+// irish : 2014-08-07 Dot-Irish LLC
+irish
+
+// iselect : 2015-02-11 iSelect Ltd
+iselect
+
+// ismaili : 2015-08-06 Fondation Aga Khan (Aga Khan Foundation)
+ismaili
+
+// ist : 2014-08-28 Istanbul Metropolitan Municipality
+ist
+
+// istanbul : 2014-08-28 Istanbul Metropolitan Municipality
+istanbul
+
+// itau : 2014-10-02 Itau Unibanco Holding S.A.
+itau
+
+// itv : 2015-07-09 ITV Services Limited
+itv
+
+// iveco : 2015-09-03 CNH Industrial N.V.
+iveco
+
+// iwc : 2014-06-23 Richemont DNS Inc.
+iwc
+
+// jaguar : 2014-11-13 Jaguar Land Rover Ltd
+jaguar
+
+// java : 2014-06-19 Oracle Corporation
+java
+
+// jcb : 2014-11-20 JCB Co., Ltd.
+jcb
+
+// jcp : 2015-04-23 JCP Media, Inc.
+jcp
+
+// jeep : 2015-07-30 FCA US LLC.
+jeep
+
+// jetzt : 2014-01-09
+jetzt
+
+// jewelry : 2015-03-05 Wild Bloom, LLC
+jewelry
+
+// jio : 2015-04-02 Affinity Names, Inc.
+jio
+
+// jlc : 2014-12-04 Richemont DNS Inc.
+jlc
+
+// jll : 2015-04-02 Jones Lang LaSalle Incorporated
+jll
+
+// jmp : 2015-03-26 Matrix IP LLC
+jmp
+
+// jnj : 2015-06-18 Johnson & Johnson Services, Inc.
+jnj
+
+// joburg : 2014-03-24 ZA Central Registry NPC trading as ZA Central Registry
+joburg
+
+// jot : 2014-12-18 Amazon EU S.à r.l.
+jot
+
+// joy : 2014-12-18 Amazon EU S.à r.l.
+joy
+
+// jpmorgan : 2015-04-30 JPMorgan Chase & Co.
+jpmorgan
+
+// jprs : 2014-09-18 Japan Registry Services Co., Ltd.
+jprs
+
+// juegos : 2014-03-20 Uniregistry, Corp.
+juegos
+
+// juniper : 2015-07-30 JUNIPER NETWORKS, INC.
+juniper
+
+// kaufen : 2013-11-07 United TLD Holdco Ltd.
+kaufen
+
+// kddi : 2014-09-12 KDDI CORPORATION
+kddi
+
+// kerryhotels : 2015-04-30 Kerry Trading Co. Limited
+kerryhotels
+
+// kerrylogistics : 2015-04-09 Kerry Trading Co. Limited
+kerrylogistics
+
+// kerryproperties : 2015-04-09 Kerry Trading Co. Limited
+kerryproperties
+
+// kfh : 2014-12-04 Kuwait Finance House
+kfh
+
+// kia : 2015-07-09 KIA MOTORS CORPORATION
+kia
+
+// kim : 2013-09-23 Afilias Limited
+kim
+
+// kinder : 2014-11-07 Ferrero Trading Lux S.A.
+kinder
+
+// kindle : 2015-06-25 Amazon EU S.à r.l.
+kindle
+
+// kitchen : 2013-09-20 Just Goodbye, LLC
+kitchen
+
+// kiwi : 2013-09-20 DOT KIWI LIMITED
+kiwi
+
+// koeln : 2014-01-09 NetCologne Gesellschaft für Telekommunikation mbH
+koeln
+
+// komatsu : 2015-01-08 Komatsu Ltd.
+komatsu
+
+// kosher : 2015-08-20 Kosher Marketing Assets LLC
+kosher
+
+// kpmg : 2015-04-23 KPMG International Cooperative (KPMG International Genossenschaft)
+kpmg
+
+// kpn : 2015-01-08 Koninklijke KPN N.V.
+kpn
+
+// krd : 2013-12-05 KRG Department of Information Technology
+krd
+
+// kred : 2013-12-19 KredTLD Pty Ltd
+kred
+
+// kuokgroup : 2015-04-09 Kerry Trading Co. Limited
+kuokgroup
+
+// kyoto : 2014-11-07 Academic Institution: Kyoto Jyoho Gakuen
+kyoto
+
+// lacaixa : 2014-01-09 CAIXA D'ESTALVIS I PENSIONS DE BARCELONA
+lacaixa
+
+// ladbrokes : 2015-08-06 LADBROKES INTERNATIONAL PLC
+ladbrokes
+
+// lamborghini : 2015-06-04 Automobili Lamborghini S.p.A.
+lamborghini
+
+// lamer : 2015-10-01 The Estée Lauder Companies Inc.
+lamer
+
+// lancaster : 2015-02-12 LANCASTER
+lancaster
+
+// lancia : 2015-07-31 Fiat Chrysler Automobiles N.V.
+lancia
+
+// lancome : 2015-07-23 L'Oréal
+lancome
+
+// land : 2013-09-10 Pine Moon, LLC
+land
+
+// landrover : 2014-11-13 Jaguar Land Rover Ltd
+landrover
+
+// lanxess : 2015-07-30 LANXESS Corporation
+lanxess
+
+// lasalle : 2015-04-02 Jones Lang LaSalle Incorporated
+lasalle
+
+// lat : 2014-10-16 ECOM-LAC Federaciòn de Latinoamèrica y el Caribe para Internet y el Comercio Electrònico
+lat
+
+// latino : 2015-07-30 Dish DBS Corporation
+latino
+
+// latrobe : 2014-06-16 La Trobe University
+latrobe
+
+// law : 2015-01-22 Minds + Machines Group Limited
+law
+
+// lawyer : 2014-03-20
+lawyer
+
+// lds : 2014-03-20 IRI Domain Management, LLC ("Applicant")
+lds
+
+// lease : 2014-03-06 Victor Trail, LLC
+lease
+
+// leclerc : 2014-08-07 A.C.D. LEC Association des Centres Distributeurs Edouard Leclerc
+leclerc
+
+// lefrak : 2015-07-16 LeFrak Organization, Inc.
+lefrak
+
+// legal : 2014-10-16 Blue Falls, LLC
+legal
+
+// lego : 2015-07-16 LEGO Juris A/S
+lego
+
+// lexus : 2015-04-23 TOYOTA MOTOR CORPORATION
+lexus
+
+// lgbt : 2014-05-08 Afilias Limited
+lgbt
+
+// liaison : 2014-10-02 Liaison Technologies, Incorporated
+liaison
+
+// lidl : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+lidl
+
+// life : 2014-02-06 Trixy Oaks, LLC
+life
+
+// lifeinsurance : 2015-01-15 American Council of Life Insurers
+lifeinsurance
+
+// lifestyle : 2014-12-11 Lifestyle Domain Holdings, Inc.
+lifestyle
+
+// lighting : 2013-08-27 John McCook, LLC
+lighting
+
+// like : 2014-12-18 Amazon EU S.à r.l.
+like
+
+// lilly : 2015-07-31 Eli Lilly and Company
+lilly
+
+// limited : 2014-03-06 Big Fest, LLC
+limited
+
+// limo : 2013-10-17 Hidden Frostbite, LLC
+limo
+
+// lincoln : 2014-11-13 Ford Motor Company
+lincoln
+
+// linde : 2014-12-04 Linde Aktiengesellschaft
+linde
+
+// link : 2013-11-14 Uniregistry, Corp.
+link
+
+// lipsy : 2015-06-25 Lipsy Ltd
+lipsy
+
+// live : 2014-12-04
+live
+
+// living : 2015-07-30 Lifestyle Domain Holdings, Inc.
+living
+
+// lixil : 2015-03-19 LIXIL Group Corporation
+lixil
+
+// loan : 2014-11-20 dot Loan Limited
+loan
+
+// loans : 2014-03-20 June Woods, LLC
+loans
+
+// locker : 2015-06-04 Dish DBS Corporation
+locker
+
+// locus : 2015-06-25 Locus Analytics LLC
+locus
+
+// loft : 2015-07-30 Annco, Inc.
+loft
+
+// lol : 2015-01-30 Uniregistry, Corp.
+lol
+
+// london : 2013-11-14 Dot London Domains Limited
+london
+
+// lotte : 2014-11-07 Lotte Holdings Co., Ltd.
+lotte
+
+// lotto : 2014-04-10 Afilias Limited
+lotto
+
+// love : 2014-12-22 Merchant Law Group LLP
+love
+
+// lpl : 2015-07-30 LPL Holdings, Inc.
+lpl
+
+// lplfinancial : 2015-07-30 LPL Holdings, Inc.
+lplfinancial
+
+// ltd : 2014-09-25 Over Corner, LLC
+ltd
+
+// ltda : 2014-04-17 DOMAIN ROBOT SERVICOS DE HOSPEDAGEM NA INTERNET LTDA
+ltda
+
+// lundbeck : 2015-08-06 H. Lundbeck A/S
+lundbeck
+
+// lupin : 2014-11-07 LUPIN LIMITED
+lupin
+
+// luxe : 2014-01-09 Top Level Domain Holdings Limited
+luxe
+
+// luxury : 2013-10-17 Luxury Partners, LLC
+luxury
+
+// macys : 2015-07-31 Macys, Inc.
+macys
+
+// madrid : 2014-05-01 Comunidad de Madrid
+madrid
+
+// maif : 2014-10-02 Mutuelle Assurance Instituteur France (MAIF)
+maif
+
+// maison : 2013-12-05 Victor Frostbite, LLC
+maison
+
+// makeup : 2015-01-15 L'Oréal
+makeup
+
+// man : 2014-12-04 MAN SE
+man
+
+// management : 2013-11-07 John Goodbye, LLC
+management
+
+// mango : 2013-10-24 PUNTO FA S.L.
+mango
+
+// map : 2016-06-09 Charleston Road Registry Inc.
+map
+
+// market : 2014-03-06
+market
+
+// marketing : 2013-11-07 Fern Pass, LLC
+marketing
+
+// markets : 2014-12-11 IG Group Holdings PLC
+markets
+
+// marriott : 2014-10-09 Marriott Worldwide Corporation
+marriott
+
+// marshalls : 2015-07-16 The TJX Companies, Inc.
+marshalls
+
+// maserati : 2015-07-31 Fiat Chrysler Automobiles N.V.
+maserati
+
+// mattel : 2015-08-06 Mattel Sites, Inc.
+mattel
+
+// mba : 2015-04-02 Lone Hollow, LLC
+mba
+
+// mcd : 2015-07-30 McDonald’s Corporation
+mcd
+
+// mcdonalds : 2015-07-30 McDonald’s Corporation
+mcdonalds
+
+// mckinsey : 2015-07-31 McKinsey Holdings, Inc.
+mckinsey
+
+// med : 2015-08-06 Medistry LLC
+med
+
+// media : 2014-03-06 Grand Glen, LLC
+media
+
+// meet : 2014-01-16
+meet
+
+// melbourne : 2014-05-29 The Crown in right of the State of Victoria, represented by its Department of State Development, Business and Innovation
+melbourne
+
+// meme : 2014-01-30 Charleston Road Registry Inc.
+meme
+
+// memorial : 2014-10-16 Dog Beach, LLC
+memorial
+
+// men : 2015-02-26 Exclusive Registry Limited
+men
+
+// menu : 2013-09-11 Wedding TLD2, LLC
+menu
+
+// meo : 2014-11-07 PT Comunicacoes S.A.
+meo
+
+// merckmsd : 2016-07-14 MSD Registry Holdings, Inc.
+merckmsd
+
+// metlife : 2015-05-07 MetLife Services and Solutions, LLC
+metlife
+
+// miami : 2013-12-19 Top Level Domain Holdings Limited
+miami
+
+// microsoft : 2014-12-18 Microsoft Corporation
+microsoft
+
+// mini : 2014-01-09 Bayerische Motoren Werke Aktiengesellschaft
+mini
+
+// mint : 2015-07-30 Intuit Administrative Services, Inc.
+mint
+
+// mit : 2015-07-02 Massachusetts Institute of Technology
+mit
+
+// mitsubishi : 2015-07-23 Mitsubishi Corporation
+mitsubishi
+
+// mlb : 2015-05-21 MLB Advanced Media DH, LLC
+mlb
+
+// mls : 2015-04-23 The Canadian Real Estate Association
+mls
+
+// mma : 2014-11-07 MMA IARD
+mma
+
+// mobile : 2016-06-02 Dish DBS Corporation
+mobile
+
+// mobily : 2014-12-18 GreenTech Consultancy Company W.L.L.
+mobily
+
+// moda : 2013-11-07 United TLD Holdco Ltd.
+moda
+
+// moe : 2013-11-13 Interlink Co., Ltd.
+moe
+
+// moi : 2014-12-18 Amazon EU S.à r.l.
+moi
+
+// mom : 2015-04-16 Uniregistry, Corp.
+mom
+
+// monash : 2013-09-30 Monash University
+monash
+
+// money : 2014-10-16 Outer McCook, LLC
+money
+
+// monster : 2015-09-11 Monster Worldwide, Inc.
+monster
+
+// montblanc : 2014-06-23 Richemont DNS Inc.
+montblanc
+
+// mopar : 2015-07-30 FCA US LLC.
+mopar
+
+// mormon : 2013-12-05 IRI Domain Management, LLC ("Applicant")
+mormon
+
+// mortgage : 2014-03-20
+mortgage
+
+// moscow : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+moscow
+
+// moto : 2015-06-04
+moto
+
+// motorcycles : 2014-01-09 DERMotorcycles, LLC
+motorcycles
+
+// mov : 2014-01-30 Charleston Road Registry Inc.
+mov
+
+// movie : 2015-02-05 New Frostbite, LLC
+movie
+
+// movistar : 2014-10-16 Telefónica S.A.
+movistar
+
+// msd : 2015-07-23 MSD Registry Holdings, Inc.
+msd
+
+// mtn : 2014-12-04 MTN Dubai Limited
+mtn
+
+// mtpc : 2014-11-20 Mitsubishi Tanabe Pharma Corporation
+mtpc
+
+// mtr : 2015-03-12 MTR Corporation Limited
+mtr
+
+// mutual : 2015-04-02 Northwestern Mutual MU TLD Registry, LLC
+mutual
+
+// nab : 2015-08-20 National Australia Bank Limited
+nab
+
+// nadex : 2014-12-11 IG Group Holdings PLC
+nadex
+
+// nagoya : 2013-10-24 GMO Registry, Inc.
+nagoya
+
+// nationwide : 2015-07-23 Nationwide Mutual Insurance Company
+nationwide
+
+// natura : 2015-03-12 NATURA COSMÉTICOS S.A.
+natura
+
+// navy : 2014-03-06 United TLD Holdco Ltd.
+navy
+
+// nba : 2015-07-31 NBA REGISTRY, LLC
+nba
+
+// nec : 2015-01-08 NEC Corporation
+nec
+
+// netbank : 2014-06-26 COMMONWEALTH BANK OF AUSTRALIA
+netbank
+
+// netflix : 2015-06-18 Netflix, Inc.
+netflix
+
+// network : 2013-11-14 Trixy Manor, LLC
+network
+
+// neustar : 2013-12-05 NeuStar, Inc.
+neustar
+
+// new : 2014-01-30 Charleston Road Registry Inc.
+new
+
+// newholland : 2015-09-03 CNH Industrial N.V.
+newholland
+
+// news : 2014-12-18
+news
+
+// next : 2015-06-18 Next plc
+next
+
+// nextdirect : 2015-06-18 Next plc
+nextdirect
+
+// nexus : 2014-07-24 Charleston Road Registry Inc.
+nexus
+
+// nfl : 2015-07-23 NFL Reg Ops LLC
+nfl
+
+// ngo : 2014-03-06 Public Interest Registry
+ngo
+
+// nhk : 2014-02-13 Japan Broadcasting Corporation (NHK)
+nhk
+
+// nico : 2014-12-04 DWANGO Co., Ltd.
+nico
+
+// nike : 2015-07-23 NIKE, Inc.
+nike
+
+// nikon : 2015-05-21 NIKON CORPORATION
+nikon
+
+// ninja : 2013-11-07 United TLD Holdco Ltd.
+ninja
+
+// nissan : 2014-03-27 NISSAN MOTOR CO., LTD.
+nissan
+
+// nissay : 2015-10-29 Nippon Life Insurance Company
+nissay
+
+// nokia : 2015-01-08 Nokia Corporation
+nokia
+
+// northwesternmutual : 2015-06-18 Northwestern Mutual Registry, LLC
+northwesternmutual
+
+// norton : 2014-12-04 Symantec Corporation
+norton
+
+// now : 2015-06-25 Amazon EU S.à r.l.
+now
+
+// nowruz : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+nowruz
+
+// nowtv : 2015-05-14 Starbucks (HK) Limited
+nowtv
+
+// nra : 2014-05-22 NRA Holdings Company, INC.
+nra
+
+// nrw : 2013-11-21 Minds + Machines GmbH
+nrw
+
+// ntt : 2014-10-31 NIPPON TELEGRAPH AND TELEPHONE CORPORATION
+ntt
+
+// nyc : 2014-01-23 The City of New York by and through the New York City Department of Information Technology & Telecommunications
+nyc
+
+// obi : 2014-09-25 OBI Group Holding SE & Co. KGaA
+obi
+
+// observer : 2015-04-30
+observer
+
+// off : 2015-07-23 Johnson Shareholdings, Inc.
+off
+
+// office : 2015-03-12 Microsoft Corporation
+office
+
+// okinawa : 2013-12-05 BusinessRalliart Inc.
+okinawa
+
+// olayan : 2015-05-14 Crescent Holding GmbH
+olayan
+
+// olayangroup : 2015-05-14 Crescent Holding GmbH
+olayangroup
+
+// oldnavy : 2015-07-31 The Gap, Inc.
+oldnavy
+
+// ollo : 2015-06-04 Dish DBS Corporation
+ollo
+
+// omega : 2015-01-08 The Swatch Group Ltd
+omega
+
+// one : 2014-11-07 One.com A/S
+one
+
+// ong : 2014-03-06 Public Interest Registry
+ong
+
+// onl : 2013-09-16 I-Registry Ltd.
+onl
+
+// online : 2015-01-15 DotOnline Inc.
+online
+
+// onyourside : 2015-07-23 Nationwide Mutual Insurance Company
+onyourside
+
+// ooo : 2014-01-09 INFIBEAM INCORPORATION LIMITED
+ooo
+
+// open : 2015-07-31 American Express Travel Related Services Company, Inc.
+open
+
+// oracle : 2014-06-19 Oracle Corporation
+oracle
+
+// orange : 2015-03-12 Orange Brand Services Limited
+orange
+
+// organic : 2014-03-27 Afilias Limited
+organic
+
+// origins : 2015-10-01 The Estée Lauder Companies Inc.
+origins
+
+// osaka : 2014-09-04 Interlink Co., Ltd.
+osaka
+
+// otsuka : 2013-10-11 Otsuka Holdings Co., Ltd.
+otsuka
+
+// ott : 2015-06-04 Dish DBS Corporation
+ott
+
+// ovh : 2014-01-16 OVH SAS
+ovh
+
+// page : 2014-12-04 Charleston Road Registry Inc.
+page
+
+// pamperedchef : 2015-02-05 The Pampered Chef, Ltd.
+pamperedchef
+
+// panasonic : 2015-07-30 Panasonic Corporation
+panasonic
+
+// panerai : 2014-11-07 Richemont DNS Inc.
+panerai
+
+// paris : 2014-01-30 City of Paris
+paris
+
+// pars : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+pars
+
+// partners : 2013-12-05 Magic Glen, LLC
+partners
+
+// parts : 2013-12-05 Sea Goodbye, LLC
+parts
+
+// party : 2014-09-11 Blue Sky Registry Limited
+party
+
+// passagens : 2015-03-05 Travel Reservations SRL
+passagens
+
+// pay : 2015-08-27 Amazon EU S.à r.l.
+pay
+
+// pccw : 2015-05-14 PCCW Enterprises Limited
+pccw
+
+// pet : 2015-05-07 Afilias plc
+pet
+
+// pfizer : 2015-09-11 Pfizer Inc.
+pfizer
+
+// pharmacy : 2014-06-19 National Association of Boards of Pharmacy
+pharmacy
+
+// phd : 2016-07-28 Charleston Road Registry Inc.
+phd
+
+// philips : 2014-11-07 Koninklijke Philips N.V.
+philips
+
+// phone : 2016-06-02 Dish DBS Corporation
+phone
+
+// photo : 2013-11-14 Uniregistry, Corp.
+photo
+
+// photography : 2013-09-20 Sugar Glen, LLC
+photography
+
+// photos : 2013-10-17 Sea Corner, LLC
+photos
+
+// physio : 2014-05-01 PhysBiz Pty Ltd
+physio
+
+// piaget : 2014-10-16 Richemont DNS Inc.
+piaget
+
+// pics : 2013-11-14 Uniregistry, Corp.
+pics
+
+// pictet : 2014-06-26 Pictet Europe S.A.
+pictet
+
+// pictures : 2014-03-06 Foggy Sky, LLC
+pictures
+
+// pid : 2015-01-08 Top Level Spectrum, Inc.
+pid
+
+// pin : 2014-12-18 Amazon EU S.à r.l.
+pin
+
+// ping : 2015-06-11 Ping Registry Provider, Inc.
+ping
+
+// pink : 2013-10-01 Afilias Limited
+pink
+
+// pioneer : 2015-07-16 Pioneer Corporation
+pioneer
+
+// pizza : 2014-06-26 Foggy Moon, LLC
+pizza
+
+// place : 2014-04-24 Snow Galley, LLC
+place
+
+// play : 2015-03-05 Charleston Road Registry Inc.
+play
+
+// playstation : 2015-07-02 Sony Computer Entertainment Inc.
+playstation
+
+// plumbing : 2013-09-10 Spring Tigers, LLC
+plumbing
+
+// plus : 2015-02-05 Sugar Mill, LLC
+plus
+
+// pnc : 2015-07-02 PNC Domain Co., LLC
+pnc
+
+// pohl : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+pohl
+
+// poker : 2014-07-03 Afilias Domains No. 5 Limited
+poker
+
+// politie : 2015-08-20 Politie Nederland
+politie
+
+// porn : 2014-10-16 ICM Registry PN LLC
+porn
+
+// pramerica : 2015-07-30 Prudential Financial, Inc.
+pramerica
+
+// praxi : 2013-12-05 Praxi S.p.A.
+praxi
+
+// press : 2014-04-03 DotPress Inc.
+press
+
+// prime : 2015-06-25 Amazon EU S.à r.l.
+prime
+
+// prod : 2014-01-23 Charleston Road Registry Inc.
+prod
+
+// productions : 2013-12-05 Magic Birch, LLC
+productions
+
+// prof : 2014-07-24 Charleston Road Registry Inc.
+prof
+
+// progressive : 2015-07-23 Progressive Casualty Insurance Company
+progressive
+
+// promo : 2014-12-18
+promo
+
+// properties : 2013-12-05 Big Pass, LLC
+properties
+
+// property : 2014-05-22 Uniregistry, Corp.
+property
+
+// protection : 2015-04-23
+protection
+
+// pru : 2015-07-30 Prudential Financial, Inc.
+pru
+
+// prudential : 2015-07-30 Prudential Financial, Inc.
+prudential
+
+// pub : 2013-12-12 United TLD Holdco Ltd.
+pub
+
+// pwc : 2015-10-29 PricewaterhouseCoopers LLP
+pwc
+
+// qpon : 2013-11-14 dotCOOL, Inc.
+qpon
+
+// quebec : 2013-12-19 PointQuébec Inc
+quebec
+
+// quest : 2015-03-26 Quest ION Limited
+quest
+
+// qvc : 2015-07-30 QVC, Inc.
+qvc
+
+// racing : 2014-12-04 Premier Registry Limited
+racing
+
+// radio : 2016-07-21 European Broadcasting Union (EBU)
+radio
+
+// raid : 2015-07-23 Johnson Shareholdings, Inc.
+raid
+
+// read : 2014-12-18 Amazon EU S.à r.l.
+read
+
+// realestate : 2015-09-11 dotRealEstate LLC
+realestate
+
+// realtor : 2014-05-29 Real Estate Domains LLC
+realtor
+
+// realty : 2015-03-19 Fegistry, LLC
+realty
+
+// recipes : 2013-10-17 Grand Island, LLC
+recipes
+
+// red : 2013-11-07 Afilias Limited
+red
+
+// redstone : 2014-10-31 Redstone Haute Couture Co., Ltd.
+redstone
+
+// redumbrella : 2015-03-26 Travelers TLD, LLC
+redumbrella
+
+// rehab : 2014-03-06 United TLD Holdco Ltd.
+rehab
+
+// reise : 2014-03-13
+reise
+
+// reisen : 2014-03-06 New Cypress, LLC
+reisen
+
+// reit : 2014-09-04 National Association of Real Estate Investment Trusts, Inc.
+reit
+
+// reliance : 2015-04-02 Reliance Industries Limited
+reliance
+
+// ren : 2013-12-12 Beijing Qianxiang Wangjing Technology Development Co., Ltd.
+ren
+
+// rent : 2014-12-04 DERRent, LLC
+rent
+
+// rentals : 2013-12-05 Big Hollow,LLC
+rentals
+
+// repair : 2013-11-07 Lone Sunset, LLC
+repair
+
+// report : 2013-12-05 Binky Glen, LLC
+report
+
+// republican : 2014-03-20 United TLD Holdco Ltd.
+republican
+
+// rest : 2013-12-19 Punto 2012 Sociedad Anonima Promotora de Inversion de Capital Variable
+rest
+
+// restaurant : 2014-07-03 Snow Avenue, LLC
+restaurant
+
+// review : 2014-11-20 dot Review Limited
+review
+
+// reviews : 2013-09-13
+reviews
+
+// rexroth : 2015-06-18 Robert Bosch GMBH
+rexroth
+
+// rich : 2013-11-21 I-Registry Ltd.
+rich
+
+// richardli : 2015-05-14 Pacific Century Asset Management (HK) Limited
+richardli
+
+// ricoh : 2014-11-20 Ricoh Company, Ltd.
+ricoh
+
+// rightathome : 2015-07-23 Johnson Shareholdings, Inc.
+rightathome
+
+// ril : 2015-04-02 Reliance Industries Limited
+ril
+
+// rio : 2014-02-27 Empresa Municipal de Informática SA - IPLANRIO
+rio
+
+// rip : 2014-07-10 United TLD Holdco Ltd.
+rip
+
+// rmit : 2015-11-19 Royal Melbourne Institute of Technology
+rmit
+
+// rocher : 2014-12-18 Ferrero Trading Lux S.A.
+rocher
+
+// rocks : 2013-11-14
+rocks
+
+// rodeo : 2013-12-19 Top Level Domain Holdings Limited
+rodeo
+
+// rogers : 2015-08-06 Rogers Communications Partnership
+rogers
+
+// room : 2014-12-18 Amazon EU S.à r.l.
+room
+
+// rsvp : 2014-05-08 Charleston Road Registry Inc.
+rsvp
+
+// rugby : 2016-12-15 World Rugby Strategic Developments Limited
+rugby
+
+// ruhr : 2013-10-02 regiodot GmbH & Co. KG
+ruhr
+
+// run : 2015-03-19 Snow Park, LLC
+run
+
+// rwe : 2015-04-02 RWE AG
+rwe
+
+// ryukyu : 2014-01-09 BusinessRalliart Inc.
+ryukyu
+
+// saarland : 2013-12-12 dotSaarland GmbH
+saarland
+
+// safe : 2014-12-18 Amazon EU S.à r.l.
+safe
+
+// safety : 2015-01-08 Safety Registry Services, LLC.
+safety
+
+// sakura : 2014-12-18 SAKURA Internet Inc.
+sakura
+
+// sale : 2014-10-16
+sale
+
+// salon : 2014-12-11 Outer Orchard, LLC
+salon
+
+// samsclub : 2015-07-31 Wal-Mart Stores, Inc.
+samsclub
+
+// samsung : 2014-04-03 SAMSUNG SDS CO., LTD
+samsung
+
+// sandvik : 2014-11-13 Sandvik AB
+sandvik
+
+// sandvikcoromant : 2014-11-07 Sandvik AB
+sandvikcoromant
+
+// sanofi : 2014-10-09 Sanofi
+sanofi
+
+// sap : 2014-03-27 SAP AG
+sap
+
+// sapo : 2014-11-07 PT Comunicacoes S.A.
+sapo
+
+// sarl : 2014-07-03 Delta Orchard, LLC
+sarl
+
+// sas : 2015-04-02 Research IP LLC
+sas
+
+// save : 2015-06-25 Amazon EU S.à r.l.
+save
+
+// saxo : 2014-10-31 Saxo Bank A/S
+saxo
+
+// sbi : 2015-03-12 STATE BANK OF INDIA
+sbi
+
+// sbs : 2014-11-07 SPECIAL BROADCASTING SERVICE CORPORATION
+sbs
+
+// sca : 2014-03-13 SVENSKA CELLULOSA AKTIEBOLAGET SCA (publ)
+sca
+
+// scb : 2014-02-20 The Siam Commercial Bank Public Company Limited ("SCB")
+scb
+
+// schaeffler : 2015-08-06 Schaeffler Technologies AG & Co. KG
+schaeffler
+
+// schmidt : 2014-04-03 SALM S.A.S.
+schmidt
+
+// scholarships : 2014-04-24 Scholarships.com, LLC
+scholarships
+
+// school : 2014-12-18 Little Galley, LLC
+school
+
+// schule : 2014-03-06 Outer Moon, LLC
+schule
+
+// schwarz : 2014-09-18 Schwarz Domains und Services GmbH & Co. KG
+schwarz
+
+// science : 2014-09-11 dot Science Limited
+science
+
+// scjohnson : 2015-07-23 Johnson Shareholdings, Inc.
+scjohnson
+
+// scor : 2014-10-31 SCOR SE
+scor
+
+// scot : 2014-01-23 Dot Scot Registry Limited
+scot
+
+// search : 2016-06-09 Charleston Road Registry Inc.
+search
+
+// seat : 2014-05-22 SEAT, S.A. (Sociedad Unipersonal)
+seat
+
+// secure : 2015-08-27 Amazon EU S.à r.l.
+secure
+
+// security : 2015-05-14
+security
+
+// seek : 2014-12-04 Seek Limited
+seek
+
+// select : 2015-10-08 iSelect Ltd
+select
+
+// sener : 2014-10-24 Sener Ingeniería y Sistemas, S.A.
+sener
+
+// services : 2014-02-27 Fox Castle, LLC
+services
+
+// ses : 2015-07-23 SES
+ses
+
+// seven : 2015-08-06 Seven West Media Ltd
+seven
+
+// sew : 2014-07-17 SEW-EURODRIVE GmbH & Co KG
+sew
+
+// sex : 2014-11-13 ICM Registry SX LLC
+sex
+
+// sexy : 2013-09-11 Uniregistry, Corp.
+sexy
+
+// sfr : 2015-08-13 Societe Francaise du Radiotelephone - SFR
+sfr
+
+// shangrila : 2015-09-03 Shangri‐La International Hotel Management Limited
+shangrila
+
+// sharp : 2014-05-01 Sharp Corporation
+sharp
+
+// shaw : 2015-04-23 Shaw Cablesystems G.P.
+shaw
+
+// shell : 2015-07-30 Shell Information Technology International Inc
+shell
+
+// shia : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+shia
+
+// shiksha : 2013-11-14 Afilias Limited
+shiksha
+
+// shoes : 2013-10-02 Binky Galley, LLC
+shoes
+
+// shop : 2016-04-08 GMO Registry, Inc.
+shop
+
+// shopping : 2016-03-31
+shopping
+
+// shouji : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+shouji
+
+// show : 2015-03-05 Snow Beach, LLC
+show
+
+// showtime : 2015-08-06 CBS Domains Inc.
+showtime
+
+// shriram : 2014-01-23 Shriram Capital Ltd.
+shriram
+
+// silk : 2015-06-25 Amazon EU S.à r.l.
+silk
+
+// sina : 2015-03-12 Sina Corporation
+sina
+
+// singles : 2013-08-27 Fern Madison, LLC
+singles
+
+// site : 2015-01-15 DotSite Inc.
+site
+
+// ski : 2015-04-09 STARTING DOT LIMITED
+ski
+
+// skin : 2015-01-15 L'Oréal
+skin
+
+// sky : 2014-06-19 Sky IP International Ltd, a company incorporated in England and Wales, operating via its registered Swiss branch
+sky
+
+// skype : 2014-12-18 Microsoft Corporation
+skype
+
+// sling : 2015-07-30 Hughes Satellite Systems Corporation
+sling
+
+// smart : 2015-07-09 Smart Communications, Inc. (SMART)
+smart
+
+// smile : 2014-12-18 Amazon EU S.à r.l.
+smile
+
+// sncf : 2015-02-19 Société Nationale des Chemins de fer Francais S N C F
+sncf
+
+// soccer : 2015-03-26 Foggy Shadow, LLC
+soccer
+
+// social : 2013-11-07 United TLD Holdco Ltd.
+social
+
+// softbank : 2015-07-02 SoftBank Corp.
+softbank
+
+// software : 2014-03-20
+software
+
+// sohu : 2013-12-19 Sohu.com Limited
+sohu
+
+// solar : 2013-11-07 Ruby Town, LLC
+solar
+
+// solutions : 2013-11-07 Silver Cover, LLC
+solutions
+
+// song : 2015-02-26 Amazon EU S.à r.l.
+song
+
+// sony : 2015-01-08 Sony Corporation
+sony
+
+// soy : 2014-01-23 Charleston Road Registry Inc.
+soy
+
+// space : 2014-04-03 DotSpace Inc.
+space
+
+// spiegel : 2014-02-05 SPIEGEL-Verlag Rudolf Augstein GmbH & Co. KG
+spiegel
+
+// spot : 2015-02-26 Amazon EU S.à r.l.
+spot
+
+// spreadbetting : 2014-12-11 IG Group Holdings PLC
+spreadbetting
+
+// srl : 2015-05-07 mySRL GmbH
+srl
+
+// srt : 2015-07-30 FCA US LLC.
+srt
+
+// stada : 2014-11-13 STADA Arzneimittel AG
+stada
+
+// staples : 2015-07-30 Staples, Inc.
+staples
+
+// star : 2015-01-08 Star India Private Limited
+star
+
+// starhub : 2015-02-05 StarHub Ltd
+starhub
+
+// statebank : 2015-03-12 STATE BANK OF INDIA
+statebank
+
+// statefarm : 2015-07-30 State Farm Mutual Automobile Insurance Company
+statefarm
+
+// statoil : 2014-12-04 Statoil ASA
+statoil
+
+// stc : 2014-10-09 Saudi Telecom Company
+stc
+
+// stcgroup : 2014-10-09 Saudi Telecom Company
+stcgroup
+
+// stockholm : 2014-12-18 Stockholms kommun
+stockholm
+
+// storage : 2014-12-22 Self Storage Company LLC
+storage
+
+// store : 2015-04-09 DotStore Inc.
+store
+
+// stream : 2016-01-08 dot Stream Limited
+stream
+
+// studio : 2015-02-11
+studio
+
+// study : 2014-12-11 OPEN UNIVERSITIES AUSTRALIA PTY LTD
+study
+
+// style : 2014-12-04 Binky Moon, LLC
+style
+
+// sucks : 2014-12-22 Vox Populi Registry Inc.
+sucks
+
+// supplies : 2013-12-19 Atomic Fields, LLC
+supplies
+
+// supply : 2013-12-19 Half Falls, LLC
+supply
+
+// support : 2013-10-24 Grand Orchard, LLC
+support
+
+// surf : 2014-01-09 Top Level Domain Holdings Limited
+surf
+
+// surgery : 2014-03-20 Tin Avenue, LLC
+surgery
+
+// suzuki : 2014-02-20 SUZUKI MOTOR CORPORATION
+suzuki
+
+// swatch : 2015-01-08 The Swatch Group Ltd
+swatch
+
+// swiftcover : 2015-07-23 Swiftcover Insurance Services Limited
+swiftcover
+
+// swiss : 2014-10-16 Swiss Confederation
+swiss
+
+// sydney : 2014-09-18 State of New South Wales, Department of Premier and Cabinet
+sydney
+
+// symantec : 2014-12-04 Symantec Corporation
+symantec
+
+// systems : 2013-11-07 Dash Cypress, LLC
+systems
+
+// tab : 2014-12-04 Tabcorp Holdings Limited
+tab
+
+// taipei : 2014-07-10 Taipei City Government
+taipei
+
+// talk : 2015-04-09 Amazon EU S.à r.l.
+talk
+
+// taobao : 2015-01-15 Alibaba Group Holding Limited
+taobao
+
+// target : 2015-07-31 Target Domain Holdings, LLC
+target
+
+// tatamotors : 2015-03-12 Tata Motors Ltd
+tatamotors
+
+// tatar : 2014-04-24 Limited Liability Company "Coordination Center of Regional Domain of Tatarstan Republic"
+tatar
+
+// tattoo : 2013-08-30 Uniregistry, Corp.
+tattoo
+
+// tax : 2014-03-20 Storm Orchard, LLC
+tax
+
+// taxi : 2015-03-19 Pine Falls, LLC
+taxi
+
+// tci : 2014-09-12 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+tci
+
+// tdk : 2015-06-11 TDK Corporation
+tdk
+
+// team : 2015-03-05 Atomic Lake, LLC
+team
+
+// tech : 2015-01-30 Dot Tech LLC
+tech
+
+// technology : 2013-09-13 Auburn Falls
+technology
+
+// telecity : 2015-02-19 TelecityGroup International Limited
+telecity
+
+// telefonica : 2014-10-16 Telefónica S.A.
+telefonica
+
+// temasek : 2014-08-07 Temasek Holdings (Private) Limited
+temasek
+
+// tennis : 2014-12-04 Cotton Bloom, LLC
+tennis
+
+// teva : 2015-07-02 Teva Pharmaceutical Industries Limited
+teva
+
+// thd : 2015-04-02 Homer TLC, Inc.
+thd
+
+// theater : 2015-03-19 Blue Tigers, LLC
+theater
+
+// theatre : 2015-05-07
+theatre
+
+// tiaa : 2015-07-23 Teachers Insurance and Annuity Association of America
+tiaa
+
+// tickets : 2015-02-05 Accent Media Limited
+tickets
+
+// tienda : 2013-11-14 Victor Manor, LLC
+tienda
+
+// tiffany : 2015-01-30 Tiffany and Company
+tiffany
+
+// tips : 2013-09-20 Corn Willow, LLC
+tips
+
+// tires : 2014-11-07 Dog Edge, LLC
+tires
+
+// tirol : 2014-04-24 punkt Tirol GmbH
+tirol
+
+// tjmaxx : 2015-07-16 The TJX Companies, Inc.
+tjmaxx
+
+// tjx : 2015-07-16 The TJX Companies, Inc.
+tjx
+
+// tkmaxx : 2015-07-16 The TJX Companies, Inc.
+tkmaxx
+
+// tmall : 2015-01-15 Alibaba Group Holding Limited
+tmall
+
+// today : 2013-09-20 Pearl Woods, LLC
+today
+
+// tokyo : 2013-11-13 GMO Registry, Inc.
+tokyo
+
+// tools : 2013-11-21 Pioneer North, LLC
+tools
+
+// top : 2014-03-20 Jiangsu Bangning Science & Technology Co.,Ltd.
+top
+
+// toray : 2014-12-18 Toray Industries, Inc.
+toray
+
+// toshiba : 2014-04-10 TOSHIBA Corporation
+toshiba
+
+// total : 2015-08-06 Total SA
+total
+
+// tours : 2015-01-22 Sugar Station, LLC
+tours
+
+// town : 2014-03-06 Koko Moon, LLC
+town
+
+// toyota : 2015-04-23 TOYOTA MOTOR CORPORATION
+toyota
+
+// toys : 2014-03-06 Pioneer Orchard, LLC
+toys
+
+// trade : 2014-01-23 Elite Registry Limited
+trade
+
+// trading : 2014-12-11 IG Group Holdings PLC
+trading
+
+// training : 2013-11-07 Wild Willow, LLC
+training
+
+// travelchannel : 2015-07-02 Lifestyle Domain Holdings, Inc.
+travelchannel
+
+// travelers : 2015-03-26 Travelers TLD, LLC
+travelers
+
+// travelersinsurance : 2015-03-26 Travelers TLD, LLC
+travelersinsurance
+
+// trust : 2014-10-16
+trust
+
+// trv : 2015-03-26 Travelers TLD, LLC
+trv
+
+// tube : 2015-06-11 Latin American Telecom LLC
+tube
+
+// tui : 2014-07-03 TUI AG
+tui
+
+// tunes : 2015-02-26 Amazon EU S.à r.l.
+tunes
+
+// tushu : 2014-12-18 Amazon EU S.à r.l.
+tushu
+
+// tvs : 2015-02-19 T V SUNDRAM IYENGAR & SONS LIMITED
+tvs
+
+// ubank : 2015-08-20 National Australia Bank Limited
+ubank
+
+// ubs : 2014-12-11 UBS AG
+ubs
+
+// uconnect : 2015-07-30 FCA US LLC.
+uconnect
+
+// unicom : 2015-10-15 China United Network Communications Corporation Limited
+unicom
+
+// university : 2014-03-06 Little Station, LLC
+university
+
+// uno : 2013-09-11 Dot Latin LLC
+uno
+
+// uol : 2014-05-01 UBN INTERNET LTDA.
+uol
+
+// ups : 2015-06-25 UPS Market Driver, Inc.
+ups
+
+// vacations : 2013-12-05 Atomic Tigers, LLC
+vacations
+
+// vana : 2014-12-11 Lifestyle Domain Holdings, Inc.
+vana
+
+// vanguard : 2015-09-03 The Vanguard Group, Inc.
+vanguard
+
+// vegas : 2014-01-16 Dot Vegas, Inc.
+vegas
+
+// ventures : 2013-08-27 Binky Lake, LLC
+ventures
+
+// verisign : 2015-08-13 VeriSign, Inc.
+verisign
+
+// versicherung : 2014-03-20
+versicherung
+
+// vet : 2014-03-06
+vet
+
+// viajes : 2013-10-17 Black Madison, LLC
+viajes
+
+// video : 2014-10-16
+video
+
+// vig : 2015-05-14 VIENNA INSURANCE GROUP AG Wiener Versicherung Gruppe
+vig
+
+// viking : 2015-04-02 Viking River Cruises (Bermuda) Ltd.
+viking
+
+// villas : 2013-12-05 New Sky, LLC
+villas
+
+// vin : 2015-06-18 Holly Shadow, LLC
+vin
+
+// vip : 2015-01-22 Minds + Machines Group Limited
+vip
+
+// virgin : 2014-09-25 Virgin Enterprises Limited
+virgin
+
+// visa : 2015-07-30 Visa Worldwide Pte. Limited
+visa
+
+// vision : 2013-12-05 Koko Station, LLC
+vision
+
+// vista : 2014-09-18 Vistaprint Limited
+vista
+
+// vistaprint : 2014-09-18 Vistaprint Limited
+vistaprint
+
+// viva : 2014-11-07 Saudi Telecom Company
+viva
+
+// vivo : 2015-07-31 Telefonica Brasil S.A.
+vivo
+
+// vlaanderen : 2014-02-06 DNS.be vzw
+vlaanderen
+
+// vodka : 2013-12-19 Top Level Domain Holdings Limited
+vodka
+
+// volkswagen : 2015-05-14 Volkswagen Group of America Inc.
+volkswagen
+
+// volvo : 2015-11-12 Volvo Holding Sverige Aktiebolag
+volvo
+
+// vote : 2013-11-21 Monolith Registry LLC
+vote
+
+// voting : 2013-11-13 Valuetainment Corp.
+voting
+
+// voto : 2013-11-21 Monolith Registry LLC
+voto
+
+// voyage : 2013-08-27 Ruby House, LLC
+voyage
+
+// vuelos : 2015-03-05 Travel Reservations SRL
+vuelos
+
+// wales : 2014-05-08 Nominet UK
+wales
+
+// walmart : 2015-07-31 Wal-Mart Stores, Inc.
+walmart
+
+// walter : 2014-11-13 Sandvik AB
+walter
+
+// wang : 2013-10-24 Zodiac Leo Limited
+wang
+
+// wanggou : 2014-12-18 Amazon EU S.à r.l.
+wanggou
+
+// warman : 2015-06-18 Weir Group IP Limited
+warman
+
+// watch : 2013-11-14 Sand Shadow, LLC
+watch
+
+// watches : 2014-12-22 Richemont DNS Inc.
+watches
+
+// weather : 2015-01-08 The Weather Channel, LLC
+weather
+
+// weatherchannel : 2015-03-12 The Weather Channel, LLC
+weatherchannel
+
+// webcam : 2014-01-23 dot Webcam Limited
+webcam
+
+// weber : 2015-06-04 Saint-Gobain Weber SA
+weber
+
+// website : 2014-04-03 DotWebsite Inc.
+website
+
+// wed : 2013-10-01 Atgron, Inc.
+wed
+
+// wedding : 2014-04-24 Top Level Domain Holdings Limited
+wedding
+
+// weibo : 2015-03-05 Sina Corporation
+weibo
+
+// weir : 2015-01-29 Weir Group IP Limited
+weir
+
+// whoswho : 2014-02-20 Who's Who Registry
+whoswho
+
+// wien : 2013-10-28 punkt.wien GmbH
+wien
+
+// wiki : 2013-11-07 Top Level Design, LLC
+wiki
+
+// williamhill : 2014-03-13 William Hill Organization Limited
+williamhill
+
+// win : 2014-11-20 First Registry Limited
+win
+
+// windows : 2014-12-18 Microsoft Corporation
+windows
+
+// wine : 2015-06-18 June Station, LLC
+wine
+
+// winners : 2015-07-16 The TJX Companies, Inc.
+winners
+
+// wme : 2014-02-13 William Morris Endeavor Entertainment, LLC
+wme
+
+// wolterskluwer : 2015-08-06 Wolters Kluwer N.V.
+wolterskluwer
+
+// woodside : 2015-07-09 Woodside Petroleum Limited
+woodside
+
+// work : 2013-12-19 Top Level Domain Holdings Limited
+work
+
+// works : 2013-11-14 Little Dynamite, LLC
+works
+
+// world : 2014-06-12 Bitter Fields, LLC
+world
+
+// wow : 2015-10-08 Amazon EU S.à r.l.
+wow
+
+// wtc : 2013-12-19 World Trade Centers Association, Inc.
+wtc
+
+// wtf : 2014-03-06 Hidden Way, LLC
+wtf
+
+// xbox : 2014-12-18 Microsoft Corporation
+xbox
+
+// xerox : 2014-10-24 Xerox DNHC LLC
+xerox
+
+// xfinity : 2015-07-09 Comcast IP Holdings I, LLC
+xfinity
+
+// xihuan : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+xihuan
+
+// xin : 2014-12-11 Elegant Leader Limited
+xin
+
+// xn--11b4c3d : 2015-01-15 VeriSign Sarl
+कॉम
+
+// xn--1ck2e1b : 2015-02-26 Amazon EU S.à r.l.
+セール
+
+// xn--1qqw23a : 2014-01-09 Guangzhou YU Wei Information Technology Co., Ltd.
+佛山
+
+// xn--30rr7y : 2014-06-12 Excellent First Limited
+慈善
+
+// xn--3bst00m : 2013-09-13 Eagle Horizon Limited
+集团
+
+// xn--3ds443g : 2013-09-08 TLD REGISTRY LIMITED
+在线
+
+// xn--3oq18vl8pn36a : 2015-07-02 Volkswagen (China) Investment Co., Ltd.
+大众汽车
+
+// xn--3pxu8k : 2015-01-15 VeriSign Sarl
+点看
+
+// xn--42c2d9a : 2015-01-15 VeriSign Sarl
+คอม
+
+// xn--45q11c : 2013-11-21 Zodiac Scorpio Limited
+八卦
+
+// xn--4gbrim : 2013-10-04 Suhub Electronic Establishment
+موقع
+
+// xn--55qw42g : 2013-11-08 China Organizational Name Administration Center
+公益
+
+// xn--55qx5d : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+公司
+
+// xn--5su34j936bgsg : 2015-09-03 Shangri‐La International Hotel Management Limited
+香格里拉
+
+// xn--5tzm5g : 2014-12-22 Global Website TLD Asia Limited
+网站
+
+// xn--6frz82g : 2013-09-23 Afilias Limited
+移动
+
+// xn--6qq986b3xl : 2013-09-13 Tycoon Treasure Limited
+我爱你
+
+// xn--80adxhks : 2013-12-19 Foundation for Assistance for Internet Technologies and Infrastructure Development (FAITID)
+москва
+
+// xn--80aqecdr1a : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+католик
+
+// xn--80asehdb : 2013-07-14 CORE Association
+онлайн
+
+// xn--80aswg : 2013-07-14 CORE Association
+сайт
+
+// xn--8y0a063a : 2015-03-26 China United Network Communications Corporation Limited
+联通
+
+// xn--9dbq2a : 2015-01-15 VeriSign Sarl
+קום
+
+// xn--9et52u : 2014-06-12 RISE VICTORY LIMITED
+时尚
+
+// xn--9krt00a : 2015-03-12 Sina Corporation
+微博
+
+// xn--b4w605ferd : 2014-08-07 Temasek Holdings (Private) Limited
+淡马锡
+
+// xn--bck1b9a5dre4c : 2015-02-26 Amazon EU S.à r.l.
+ファッション
+
+// xn--c1avg : 2013-11-14 Public Interest Registry
+орг
+
+// xn--c2br7g : 2015-01-15 VeriSign Sarl
+नेट
+
+// xn--cck2b3b : 2015-02-26 Amazon EU S.à r.l.
+ストア
+
+// xn--cg4bki : 2013-09-27 SAMSUNG SDS CO., LTD
+삼성
+
+// xn--czr694b : 2014-01-16 Dot Trademark TLD Holding Company Limited
+商标
+
+// xn--czrs0t : 2013-12-19 Wild Island, LLC
+商店
+
+// xn--czru2d : 2013-11-21 Zodiac Capricorn Limited
+商城
+
+// xn--d1acj3b : 2013-11-20 The Foundation for Network Initiatives “The Smart Internet”
+дети
+
+// xn--eckvdtc9d : 2014-12-18 Amazon EU S.à r.l.
+ポイント
+
+// xn--efvy88h : 2014-08-22 Xinhua News Agency Guangdong Branch 新华通讯社广东分社
+新闻
+
+// xn--estv75g : 2015-02-19 Industrial and Commercial Bank of China Limited
+工行
+
+// xn--fct429k : 2015-04-09 Amazon EU S.à r.l.
+家電
+
+// xn--fhbei : 2015-01-15 VeriSign Sarl
+كوم
+
+// xn--fiq228c5hs : 2013-09-08 TLD REGISTRY LIMITED
+中文网
+
+// xn--fiq64b : 2013-10-14 CITIC Group Corporation
+中信
+
+// xn--fjq720a : 2014-05-22 Will Bloom, LLC
+娱乐
+
+// xn--flw351e : 2014-07-31 Charleston Road Registry Inc.
+谷歌
+
+// xn--fzys8d69uvgm : 2015-05-14 PCCW Enterprises Limited
+電訊盈科
+
+// xn--g2xx48c : 2015-01-30 Minds + Machines Group Limited
+购物
+
+// xn--gckr3f0f : 2015-02-26 Amazon EU S.à r.l.
+クラウド
+
+// xn--gk3at1e : 2015-10-08 Amazon EU S.à r.l.
+通販
+
+// xn--hxt814e : 2014-05-15 Zodiac Libra Limited
+网店
+
+// xn--i1b6b1a6a2e : 2013-11-14 Public Interest Registry
+संगठन
+
+// xn--imr513n : 2014-12-11 Dot Trademark TLD Holding Company Limited
+餐厅
+
+// xn--io0a7i : 2013-11-14 Computer Network Information Center of Chinese Academy of Sciences (China Internet Network Information Center)
+网络
+
+// xn--j1aef : 2015-01-15 VeriSign Sarl
+ком
+
+// xn--jlq61u9w7b : 2015-01-08 Nokia Corporation
+诺基亚
+
+// xn--jvr189m : 2015-02-26 Amazon EU S.à r.l.
+食品
+
+// xn--kcrx77d1x4a : 2014-11-07 Koninklijke Philips N.V.
+飞利浦
+
+// xn--kpu716f : 2014-12-22 Richemont DNS Inc.
+手表
+
+// xn--kput3i : 2014-02-13 Beijing RITT-Net Technology Development Co., Ltd
+手机
+
+// xn--mgba3a3ejt : 2014-11-20 Aramco Services Company
+ارامكو
+
+// xn--mgba7c0bbn0a : 2015-05-14 Crescent Holding GmbH
+العليان
+
+// xn--mgbaakc7dvf : 2015-09-03 Emirates Telecommunications Corporation (trading as Etisalat)
+اتصالات
+
+// xn--mgbab2bd : 2013-10-31 CORE Association
+بازار
+
+// xn--mgbb9fbpob : 2014-12-18 GreenTech Consultancy Company W.L.L.
+موبايلي
+
+// xn--mgbca7dzdo : 2015-07-30 Abu Dhabi Systems and Information Centre
+ابوظبي
+
+// xn--mgbi4ecexp : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+كاثوليك
+
+// xn--mgbt3dhd : 2014-09-04 Asia Green IT System Bilgisayar San. ve Tic. Ltd. Sti.
+همراه
+
+// xn--mk1bu44c : 2015-01-15 VeriSign Sarl
+닷컴
+
+// xn--mxtq1m : 2014-03-06 Net-Chinese Co., Ltd.
+政府
+
+// xn--ngbc5azd : 2013-07-13 International Domain Registry Pty. Ltd.
+شبكة
+
+// xn--ngbe9e0a : 2014-12-04 Kuwait Finance House
+بيتك
+
+// xn--ngbrx : 2015-11-12 League of Arab States
+عرب
+
+// xn--nqv7f : 2013-11-14 Public Interest Registry
+机构
+
+// xn--nqv7fs00ema : 2013-11-14 Public Interest Registry
+组织机构
+
+// xn--nyqy26a : 2014-11-07 Stable Tone Limited
+健康
+
+// xn--p1acf : 2013-12-12 Rusnames Limited
+рус
+
+// xn--pbt977c : 2014-12-22 Richemont DNS Inc.
+珠宝
+
+// xn--pssy2u : 2015-01-15 VeriSign Sarl
+大拿
+
+// xn--q9jyb4c : 2013-09-17 Charleston Road Registry Inc.
+みんな
+
+// xn--qcka1pmc : 2014-07-31 Charleston Road Registry Inc.
+グーグル
+
+// xn--rhqv96g : 2013-09-11 Stable Tone Limited
+世界
+
+// xn--rovu88b : 2015-02-26 Amazon EU S.à r.l.
+書籍
+
+// xn--ses554g : 2014-01-16
+网址
+
+// xn--t60b56a : 2015-01-15 VeriSign Sarl
+닷넷
+
+// xn--tckwe : 2015-01-15 VeriSign Sarl
+コム
+
+// xn--tiq49xqyj : 2015-10-21 Pontificium Consilium de Comunicationibus Socialibus (PCCS) (Pontifical Council for Social Communication)
+天主教
+
+// xn--unup4y : 2013-07-14 Spring Fields, LLC
+游戏
+
+// xn--vermgensberater-ctb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberater
+
+// xn--vermgensberatung-pwb : 2014-06-23 Deutsche Vermögensberatung Aktiengesellschaft DVAG
+vermögensberatung
+
+// xn--vhquv : 2013-08-27 Dash McCook, LLC
+企业
+
+// xn--vuq861b : 2014-10-16 Beijing Tele-info Network Technology Co., Ltd.
+信息
+
+// xn--w4r85el8fhu5dnra : 2015-04-30 Kerry Trading Co. Limited
+嘉里大酒店
+
+// xn--w4rs40l : 2015-07-30 Kerry Trading Co. Limited
+嘉里
+
+// xn--xhq521b : 2013-11-14 Guangzhou YU Wei Information Technology Co., Ltd.
+广东
+
+// xn--zfr164b : 2013-11-08 China Organizational Name Administration Center
+政务
+
+// xperia : 2015-05-14 Sony Mobile Communications AB
+xperia
+
+// xyz : 2013-12-05 XYZ.COM LLC
+xyz
+
+// yachts : 2014-01-09 DERYachts, LLC
+yachts
+
+// yahoo : 2015-04-02 Yahoo! Domain Services Inc.
+yahoo
+
+// yamaxun : 2014-12-18 Amazon EU S.à r.l.
+yamaxun
+
+// yandex : 2014-04-10 YANDEX, LLC
+yandex
+
+// yodobashi : 2014-11-20 YODOBASHI CAMERA CO.,LTD.
+yodobashi
+
+// yoga : 2014-05-29 Top Level Domain Holdings Limited
+yoga
+
+// yokohama : 2013-12-12 GMO Registry, Inc.
+yokohama
+
+// you : 2015-04-09 Amazon EU S.à r.l.
+you
+
+// youtube : 2014-05-01 Charleston Road Registry Inc.
+youtube
+
+// yun : 2015-01-08 QIHOO 360 TECHNOLOGY CO. LTD.
+yun
+
+// zappos : 2015-06-25 Amazon EU S.à r.l.
+zappos
+
+// zara : 2014-11-07 Industria de Diseño Textil, S.A. (INDITEX, S.A.)
+zara
+
+// zero : 2014-12-18 Amazon EU S.à r.l.
+zero
+
+// zip : 2014-05-08 Charleston Road Registry Inc.
+zip
+
+// zippo : 2015-07-02 Zadco Company
+zippo
+
+// zone : 2013-11-14 Outer Falls, LLC
+zone
+
+// zuerich : 2014-11-07 Kanton Zürich (Canton of Zurich)
+zuerich
+
+
+// ===END ICANN DOMAINS===
+// ===BEGIN PRIVATE DOMAINS===
+// (Note: these are in alphabetical order by company name)
+
+// 1GB LLC : https://www.1gb.ua/
+// Submitted by 1GB LLC <noc@1gb.com.ua>
+cc.ua
+inf.ua
+ltd.ua
+
+// Agnat sp. z o.o. : https://domena.pl
+// Submitted by Przemyslaw Plewa <it-admin@domena.pl>
+beep.pl
+
+// Alces Software Ltd : http://alces-software.com
+// Submitted by Mark J. Titorenko <mark.titorenko@alces-software.com>
+*.compute.estate
+*.alces.network
+
+// alwaysdata : https://www.alwaysdata.com
+// Submitted by Cyril <admin@alwaysdata.com>
+*.alwaysdata.net
+
+// Amazon CloudFront : https://aws.amazon.com/cloudfront/
+// Submitted by Donavan Miller <donavanm@amazon.com>
+cloudfront.net
+
+// Amazon Elastic Compute Cloud : https://aws.amazon.com/ec2/
+// Submitted by Luke Wells <psl-maintainers@amazon.com>
+*.compute.amazonaws.com
+*.compute-1.amazonaws.com
+*.compute.amazonaws.com.cn
+us-east-1.amazonaws.com
+
+// Amazon Elastic Beanstalk : https://aws.amazon.com/elasticbeanstalk/
+// Submitted by Luke Wells <psl-maintainers@amazon.com>
+elasticbeanstalk.cn-north-1.amazonaws.com.cn
+*.elasticbeanstalk.com
+
+// Amazon Elastic Load Balancing : https://aws.amazon.com/elasticloadbalancing/
+// Submitted by Luke Wells <psl-maintainers@amazon.com>
+*.elb.amazonaws.com
+*.elb.amazonaws.com.cn
+
+// Amazon S3 : https://aws.amazon.com/s3/
+// Submitted by Luke Wells <psl-maintainers@amazon.com>
+s3.amazonaws.com
+s3-ap-northeast-1.amazonaws.com
+s3-ap-northeast-2.amazonaws.com
+s3-ap-south-1.amazonaws.com
+s3-ap-southeast-1.amazonaws.com
+s3-ap-southeast-2.amazonaws.com
+s3-ca-central-1.amazonaws.com
+s3-eu-central-1.amazonaws.com
+s3-eu-west-1.amazonaws.com
+s3-eu-west-2.amazonaws.com
+s3-external-1.amazonaws.com
+s3-fips-us-gov-west-1.amazonaws.com
+s3-sa-east-1.amazonaws.com
+s3-us-gov-west-1.amazonaws.com
+s3-us-east-2.amazonaws.com
+s3-us-west-1.amazonaws.com
+s3-us-west-2.amazonaws.com
+s3.ap-northeast-2.amazonaws.com
+s3.ap-south-1.amazonaws.com
+s3.cn-north-1.amazonaws.com.cn
+s3.ca-central-1.amazonaws.com
+s3.eu-central-1.amazonaws.com
+s3.eu-west-2.amazonaws.com
+s3.us-east-2.amazonaws.com
+s3.dualstack.ap-northeast-1.amazonaws.com
+s3.dualstack.ap-northeast-2.amazonaws.com
+s3.dualstack.ap-south-1.amazonaws.com
+s3.dualstack.ap-southeast-1.amazonaws.com
+s3.dualstack.ap-southeast-2.amazonaws.com
+s3.dualstack.ca-central-1.amazonaws.com
+s3.dualstack.eu-central-1.amazonaws.com
+s3.dualstack.eu-west-1.amazonaws.com
+s3.dualstack.eu-west-2.amazonaws.com
+s3.dualstack.sa-east-1.amazonaws.com
+s3.dualstack.us-east-1.amazonaws.com
+s3.dualstack.us-east-2.amazonaws.com
+s3-website-us-east-1.amazonaws.com
+s3-website-us-west-1.amazonaws.com
+s3-website-us-west-2.amazonaws.com
+s3-website-ap-northeast-1.amazonaws.com
+s3-website-ap-southeast-1.amazonaws.com
+s3-website-ap-southeast-2.amazonaws.com
+s3-website-eu-west-1.amazonaws.com
+s3-website-sa-east-1.amazonaws.com
+s3-website.ap-northeast-2.amazonaws.com
+s3-website.ap-south-1.amazonaws.com
+s3-website.ca-central-1.amazonaws.com
+s3-website.eu-central-1.amazonaws.com
+s3-website.eu-west-2.amazonaws.com
+s3-website.us-east-2.amazonaws.com
+
+// Amune : https://amune.org/
+// Submitted by Team Amune <cert@amune.org>
+t3l3p0rt.net
+tele.amune.org
+
+// Aptible : https://www.aptible.com/
+// Submitted by Thomas Orozco <thomas@aptible.com>
+on-aptible.com
+
+// Asociación Amigos de la Informática "Euskalamiga" : http://encounter.eus/
+// Submitted by Hector Martin <marcan@euskalencounter.org>
+user.party.eus
+
+// Association potager.org : https://potager.org/
+// Submitted by Lunar <jardiniers@potager.org>
+pimienta.org
+poivron.org
+potager.org
+sweetpepper.org
+
+// ASUSTOR Inc. : http://www.asustor.com
+// Submitted by Vincent Tseng <vincenttseng@asustor.com>
+myasustor.com
+
+// AVM : https://avm.de
+// Submitted by Andreas Weise <a.weise@avm.de>
+myfritz.net
+
+// AW AdvisorWebsites.com Software Inc : https://advisorwebsites.com
+// Submitted by James Kennedy <domains@advisorwebsites.com>
+*.awdev.ca
+*.advisor.ws
+
+// backplane : https://www.backplane.io
+// Submitted by Anthony Voutas <anthony@backplane.io>
+backplaneapp.io
+
+// BetaInABox
+// Submitted by Adrian <adrian@betainabox.com>
+betainabox.com
+
+// BinaryLane : http://www.binarylane.com
+// Submitted by Nathan O'Sullivan <nathan@mammoth.com.au>
+bnr.la
+
+// Boxfuse : https://boxfuse.com
+// Submitted by Axel Fontaine <axel@boxfuse.com>
+boxfuse.io
+
+// bplaced : https://www.bplaced.net/
+// Submitted by Miroslav Bozic <security@bplaced.net>
+square7.ch
+bplaced.com
+bplaced.de
+square7.de
+bplaced.net
+square7.net
+
+// BrowserSafetyMark
+// Submitted by Dave Tharp <browsersafetymark.io@quicinc.com>
+browsersafetymark.io
+
+// callidomus : https://www.callidomus.com/
+// Submitted by Marcus Popp <admin@callidomus.com>
+mycd.eu
+
+// CentralNic : http://www.centralnic.com/names/domains
+// Submitted by registry <gavin.brown@centralnic.com>
+ae.org
+ar.com
+br.com
+cn.com
+com.de
+com.se
+de.com
+eu.com
+gb.com
+gb.net
+hu.com
+hu.net
+jp.net
+jpn.com
+kr.com
+mex.com
+no.com
+qc.com
+ru.com
+sa.com
+se.com
+se.net
+uk.com
+uk.net
+us.com
+uy.com
+za.bz
+za.com
+
+// Africa.com Web Solutions Ltd : https://registry.africa.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+africa.com
+
+// iDOT Services Limited : http://www.domain.gr.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+gr.com
+
+// Radix FZC : http://domains.in.net
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+in.net
+
+// US REGISTRY LLC : http://us.org
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+us.org
+
+// co.com Registry, LLC : https://registry.co.com
+// Submitted by Gavin Brown <gavin.brown@centralnic.com>
+co.com
+
+// c.la : http://www.c.la/
+c.la
+
+// certmgr.org : https://certmgr.org
+// Submitted by B. Blechschmidt <hostmaster@certmgr.org>
+certmgr.org
+
+// Citrix : https://citrix.com
+// Submitted by Alex Stoddard <alex.stoddard@citrix.com>
+xenapponazure.com
+
+// ClearVox : http://www.clearvox.nl/
+// Submitted by Leon Rowland <leon@clearvox.nl>
+virtueeldomein.nl
+
+// Cloud66 : https://www.cloud66.com/
+// Submitted by Khash Sajadi <khash@cloud66.com>
+c66.me
+
+// CloudAccess.net : https://www.cloudaccess.net/
+// Submitted by Pawel Panek <noc@cloudaccess.net>
+jdevcloud.com
+wpdevcloud.com
+cloudaccess.host
+freesite.host
+cloudaccess.net
+
+// cloudControl : https://www.cloudcontrol.com/
+// Submitted by Tobias Wilken <tw@cloudcontrol.com>
+cloudcontrolled.com
+cloudcontrolapp.com
+
+// co.ca : http://registry.co.ca/
+co.ca
+
+// i-registry s.r.o. : http://www.i-registry.cz/
+// Submitted by Martin Semrad <semrad@i-registry.cz>
+co.cz
+
+// CDN77.com : http://www.cdn77.com
+// Submitted by Jan Krpes <jan.krpes@cdn77.com>
+c.cdn77.org
+cdn77-ssl.net
+r.cdn77.net
+rsc.cdn77.org
+ssl.origin.cdn77-secure.org
+
+// Cloud DNS Ltd : http://www.cloudns.net
+// Submitted by Aleksander Hristov <noc@cloudns.net>
+cloudns.asia
+cloudns.biz
+cloudns.club
+cloudns.cc
+cloudns.eu
+cloudns.in
+cloudns.info
+cloudns.org
+cloudns.pro
+cloudns.pw
+cloudns.us
+
+// CoDNS B.V.
+co.nl
+co.no
+
+// COSIMO GmbH : http://www.cosimo.de
+// Submitted by Rene Marticke <rmarticke@cosimo.de>
+dyn.cosidns.de
+dynamisches-dns.de
+dnsupdater.de
+internet-dns.de
+l-o-g-i-n.de
+dynamic-dns.info
+feste-ip.net
+knx-server.net
+static-access.net
+
+// Craynic, s.r.o. : http://www.craynic.com/
+// Submitted by Ales Krajnik <ales.krajnik@craynic.com>
+realm.cz
+
+// Cryptonomic : https://cryptonomic.net/
+// Submitted by Andrew Cady <public-suffix-list@cryptonomic.net>
+*.cryptonomic.net
+
+// Cupcake : https://cupcake.io/
+// Submitted by Jonathan Rudenberg <jonathan@cupcake.io>
+cupcake.is
+
+// cyon GmbH : https://www.cyon.ch/
+// Submitted by Dominic Luechinger <dol@cyon.ch>
+cyon.link
+cyon.site
+
+// Daplie, Inc : https://daplie.com
+// Submitted by AJ ONeal <aj@daplie.com>
+daplie.me
+localhost.daplie.me
+
+// Dansk.net : http://www.dansk.net/
+// Submitted by Anani Voule <digital@digital.co.dk>
+biz.dk
+co.dk
+firm.dk
+reg.dk
+store.dk
+
+// deSEC : https://desec.io/
+// Submitted by Peter Thomassen <peter@desec.io>
+dedyn.io
+
+// DNShome : https://www.dnshome.de/
+// Submitted by Norbert Auler <mail@dnshome.de>
+dnshome.de
+
+// DrayTek Corp. : https://www.draytek.com/
+// Submitted by Paul Fang <mis@draytek.com>
+drayddns.com
+
+// DreamHost : http://www.dreamhost.com/
+// Submitted by Andrew Farmer <andrew.farmer@dreamhost.com>
+dreamhosters.com
+
+// Drobo : http://www.drobo.com/
+// Submitted by Ricardo Padilha <rpadilha@drobo.com>
+mydrobo.com
+
+// Drud Holdings, LLC. : https://www.drud.com/
+// Submitted by Kevin Bridges <kevin@drud.com>
+drud.io
+drud.us
+
+// DuckDNS : http://www.duckdns.org/
+// Submitted by Richard Harper <richard@duckdns.org>
+duckdns.org
+
+// dy.fi : http://dy.fi/
+// Submitted by Heikki Hannikainen <hessu@hes.iki.fi>
+dy.fi
+tunk.org
+
+// DynDNS.com : http://www.dyndns.com/services/dns/dyndns/
+dyndns-at-home.com
+dyndns-at-work.com
+dyndns-blog.com
+dyndns-free.com
+dyndns-home.com
+dyndns-ip.com
+dyndns-mail.com
+dyndns-office.com
+dyndns-pics.com
+dyndns-remote.com
+dyndns-server.com
+dyndns-web.com
+dyndns-wiki.com
+dyndns-work.com
+dyndns.biz
+dyndns.info
+dyndns.org
+dyndns.tv
+at-band-camp.net
+ath.cx
+barrel-of-knowledge.info
+barrell-of-knowledge.info
+better-than.tv
+blogdns.com
+blogdns.net
+blogdns.org
+blogsite.org
+boldlygoingnowhere.org
+broke-it.net
+buyshouses.net
+cechire.com
+dnsalias.com
+dnsalias.net
+dnsalias.org
+dnsdojo.com
+dnsdojo.net
+dnsdojo.org
+does-it.net
+doesntexist.com
+doesntexist.org
+dontexist.com
+dontexist.net
+dontexist.org
+doomdns.com
+doomdns.org
+dvrdns.org
+dyn-o-saur.com
+dynalias.com
+dynalias.net
+dynalias.org
+dynathome.net
+dyndns.ws
+endofinternet.net
+endofinternet.org
+endoftheinternet.org
+est-a-la-maison.com
+est-a-la-masion.com
+est-le-patron.com
+est-mon-blogueur.com
+for-better.biz
+for-more.biz
+for-our.info
+for-some.biz
+for-the.biz
+forgot.her.name
+forgot.his.name
+from-ak.com
+from-al.com
+from-ar.com
+from-az.net
+from-ca.com
+from-co.net
+from-ct.com
+from-dc.com
+from-de.com
+from-fl.com
+from-ga.com
+from-hi.com
+from-ia.com
+from-id.com
+from-il.com
+from-in.com
+from-ks.com
+from-ky.com
+from-la.net
+from-ma.com
+from-md.com
+from-me.org
+from-mi.com
+from-mn.com
+from-mo.com
+from-ms.com
+from-mt.com
+from-nc.com
+from-nd.com
+from-ne.com
+from-nh.com
+from-nj.com
+from-nm.com
+from-nv.com
+from-ny.net
+from-oh.com
+from-ok.com
+from-or.com
+from-pa.com
+from-pr.com
+from-ri.com
+from-sc.com
+from-sd.com
+from-tn.com
+from-tx.com
+from-ut.com
+from-va.com
+from-vt.com
+from-wa.com
+from-wi.com
+from-wv.com
+from-wy.com
+ftpaccess.cc
+fuettertdasnetz.de
+game-host.org
+game-server.cc
+getmyip.com
+gets-it.net
+go.dyndns.org
+gotdns.com
+gotdns.org
+groks-the.info
+groks-this.info
+ham-radio-op.net
+here-for-more.info
+hobby-site.com
+hobby-site.org
+home.dyndns.org
+homedns.org
+homeftp.net
+homeftp.org
+homeip.net
+homelinux.com
+homelinux.net
+homelinux.org
+homeunix.com
+homeunix.net
+homeunix.org
+iamallama.com
+in-the-band.net
+is-a-anarchist.com
+is-a-blogger.com
+is-a-bookkeeper.com
+is-a-bruinsfan.org
+is-a-bulls-fan.com
+is-a-candidate.org
+is-a-caterer.com
+is-a-celticsfan.org
+is-a-chef.com
+is-a-chef.net
+is-a-chef.org
+is-a-conservative.com
+is-a-cpa.com
+is-a-cubicle-slave.com
+is-a-democrat.com
+is-a-designer.com
+is-a-doctor.com
+is-a-financialadvisor.com
+is-a-geek.com
+is-a-geek.net
+is-a-geek.org
+is-a-green.com
+is-a-guru.com
+is-a-hard-worker.com
+is-a-hunter.com
+is-a-knight.org
+is-a-landscaper.com
+is-a-lawyer.com
+is-a-liberal.com
+is-a-libertarian.com
+is-a-linux-user.org
+is-a-llama.com
+is-a-musician.com
+is-a-nascarfan.com
+is-a-nurse.com
+is-a-painter.com
+is-a-patsfan.org
+is-a-personaltrainer.com
+is-a-photographer.com
+is-a-player.com
+is-a-republican.com
+is-a-rockstar.com
+is-a-socialist.com
+is-a-soxfan.org
+is-a-student.com
+is-a-teacher.com
+is-a-techie.com
+is-a-therapist.com
+is-an-accountant.com
+is-an-actor.com
+is-an-actress.com
+is-an-anarchist.com
+is-an-artist.com
+is-an-engineer.com
+is-an-entertainer.com
+is-by.us
+is-certified.com
+is-found.org
+is-gone.com
+is-into-anime.com
+is-into-cars.com
+is-into-cartoons.com
+is-into-games.com
+is-leet.com
+is-lost.org
+is-not-certified.com
+is-saved.org
+is-slick.com
+is-uberleet.com
+is-very-bad.org
+is-very-evil.org
+is-very-good.org
+is-very-nice.org
+is-very-sweet.org
+is-with-theband.com
+isa-geek.com
+isa-geek.net
+isa-geek.org
+isa-hockeynut.com
+issmarterthanyou.com
+isteingeek.de
+istmein.de
+kicks-ass.net
+kicks-ass.org
+knowsitall.info
+land-4-sale.us
+lebtimnetz.de
+leitungsen.de
+likes-pie.com
+likescandy.com
+merseine.nu
+mine.nu
+misconfused.org
+mypets.ws
+myphotos.cc
+neat-url.com
+office-on-the.net
+on-the-web.tv
+podzone.net
+podzone.org
+readmyblog.org
+saves-the-whales.com
+scrapper-site.net
+scrapping.cc
+selfip.biz
+selfip.com
+selfip.info
+selfip.net
+selfip.org
+sells-for-less.com
+sells-for-u.com
+sells-it.net
+sellsyourhome.org
+servebbs.com
+servebbs.net
+servebbs.org
+serveftp.net
+serveftp.org
+servegame.org
+shacknet.nu
+simple-url.com
+space-to-rent.com
+stuff-4-sale.org
+stuff-4-sale.us
+teaches-yoga.com
+thruhere.net
+traeumtgerade.de
+webhop.biz
+webhop.info
+webhop.net
+webhop.org
+worse-than.tv
+writesthisblog.com
+
+// ddnss.de : https://www.ddnss.de/
+// Submitted by Robert Niedziela <webmaster@ddnss.de>
+ddnss.de
+dyn.ddnss.de
+dyndns.ddnss.de
+dyndns1.de
+dyn-ip24.de
+home-webserver.de
+dyn.home-webserver.de
+myhome-server.de
+ddnss.org
+
+// Definima : http://www.definima.com/
+// Submitted by Maxence Bitterli <maxence@definima.com>
+definima.net
+definima.io
+
+// dynv6 : https://dynv6.com
+// Submitted by Dominik Menke <dom@digineo.de>
+dynv6.net
+
+// E4YOU spol. s.r.o. : https://e4you.cz/
+// Submitted by Vladimir Dudr <info@e4you.cz>
+e4.cz
+
+// Enalean SAS: https://www.enalean.com
+// Submitted by Thomas Cottier <thomas.cottier@enalean.com>
+mytuleap.com
+
+// Enonic : http://enonic.com/
+// Submitted by Erik Kaareng-Sunde <esu@enonic.com>
+enonic.io
+customer.enonic.io
+
+// EU.org https://eu.org/
+// Submitted by Pierre Beyssac <hostmaster@eu.org>
+eu.org
+al.eu.org
+asso.eu.org
+at.eu.org
+au.eu.org
+be.eu.org
+bg.eu.org
+ca.eu.org
+cd.eu.org
+ch.eu.org
+cn.eu.org
+cy.eu.org
+cz.eu.org
+de.eu.org
+dk.eu.org
+edu.eu.org
+ee.eu.org
+es.eu.org
+fi.eu.org
+fr.eu.org
+gr.eu.org
+hr.eu.org
+hu.eu.org
+ie.eu.org
+il.eu.org
+in.eu.org
+int.eu.org
+is.eu.org
+it.eu.org
+jp.eu.org
+kr.eu.org
+lt.eu.org
+lu.eu.org
+lv.eu.org
+mc.eu.org
+me.eu.org
+mk.eu.org
+mt.eu.org
+my.eu.org
+net.eu.org
+ng.eu.org
+nl.eu.org
+no.eu.org
+nz.eu.org
+paris.eu.org
+pl.eu.org
+pt.eu.org
+q-a.eu.org
+ro.eu.org
+ru.eu.org
+se.eu.org
+si.eu.org
+sk.eu.org
+tr.eu.org
+uk.eu.org
+us.eu.org
+
+// Evennode : http://www.evennode.com/
+// Submitted by Michal Kralik <support@evennode.com>
+eu-1.evennode.com
+eu-2.evennode.com
+eu-3.evennode.com
+us-1.evennode.com
+us-2.evennode.com
+us-3.evennode.com
+
+// eDirect Corp. : https://hosting.url.com.tw/
+// Submitted by C.S. chang <cschang@corp.url.com.tw>
+twmail.cc
+twmail.net
+twmail.org
+mymailer.com.tw
+url.tw
+
+// Facebook, Inc.
+// Submitted by Peter Ruibal <public-suffix@fb.com>
+apps.fbsbx.com
+
+// FAITID : https://faitid.org/
+// Submitted by Maxim Alzoba <tech.contact@faitid.org>
+// https://www.flexireg.net/stat_info
+ru.net
+adygeya.ru
+bashkiria.ru
+bir.ru
+cbg.ru
+com.ru
+dagestan.ru
+grozny.ru
+kalmykia.ru
+kustanai.ru
+marine.ru
+mordovia.ru
+msk.ru
+mytis.ru
+nalchik.ru
+nov.ru
+pyatigorsk.ru
+spb.ru
+vladikavkaz.ru
+vladimir.ru
+abkhazia.su
+adygeya.su
+aktyubinsk.su
+arkhangelsk.su
+armenia.su
+ashgabad.su
+azerbaijan.su
+balashov.su
+bashkiria.su
+bryansk.su
+bukhara.su
+chimkent.su
+dagestan.su
+east-kazakhstan.su
+exnet.su
+georgia.su
+grozny.su
+ivanovo.su
+jambyl.su
+kalmykia.su
+kaluga.su
+karacol.su
+karaganda.su
+karelia.su
+khakassia.su
+krasnodar.su
+kurgan.su
+kustanai.su
+lenug.su
+mangyshlak.su
+mordovia.su
+msk.su
+murmansk.su
+nalchik.su
+navoi.su
+north-kazakhstan.su
+nov.su
+obninsk.su
+penza.su
+pokrovsk.su
+sochi.su
+spb.su
+tashkent.su
+termez.su
+togliatti.su
+troitsk.su
+tselinograd.su
+tula.su
+tuva.su
+vladikavkaz.su
+vladimir.su
+vologda.su
+
+// Fastly Inc. : http://www.fastly.com/
+// Submitted by Fastly Security <security@fastly.com>
+fastlylb.net
+map.fastlylb.net
+freetls.fastly.net
+map.fastly.net
+a.prod.fastly.net
+global.prod.fastly.net
+a.ssl.fastly.net
+b.ssl.fastly.net
+global.ssl.fastly.net
+
+// Featherhead : https://featherhead.xyz/
+// Submitted by Simon Menke <simon@featherhead.xyz>
+fhapp.xyz
+
+// Fedora : https://fedoraproject.org/
+// submitted by Patrick Uiterwijk <puiterwijk@fedoraproject.org>
+fedorainfracloud.org
+fedorapeople.org
+cloud.fedoraproject.org
+
+// Filegear Inc. : https://www.filegear.com
+// Submitted by Jason Zhu <jason@owtware.com>
+filegear.me
+
+// Firebase, Inc.
+// Submitted by Chris Raynor <chris@firebase.com>
+firebaseapp.com
+
+// Flynn : https://flynn.io
+// Submitted by Jonathan Rudenberg <jonathan@flynn.io>
+flynnhub.com
+flynnhosting.net
+
+// Freebox : http://www.freebox.fr
+// Submitted by Romain Fliedel <rfliedel@freebox.fr>
+freebox-os.com
+freeboxos.com
+fbx-os.fr
+fbxos.fr
+freebox-os.fr
+freeboxos.fr
+
+// Fusion Intranet : https://www.fusion-intranet.com
+// Submitted by Matthias Burtscher <matthias.burtscher@fusonic.net>
+myfusion.cloud
+
+// Futureweb OG : http://www.futureweb.at
+// Submitted by Andreas Schnederle-Wagner <schnederle@futureweb.at>
+futurehosting.at
+futuremailing.at
+*.ex.ortsinfo.at
+*.kunden.ortsinfo.at
+*.statics.cloud
+
+// GDS : https://www.gov.uk/service-manual/operations/operating-servicegovuk-subdomains
+// Submitted by David Illsley <david.illsley@digital.cabinet-office.gov.uk>
+service.gov.uk
+
+// GitHub, Inc.
+// Submitted by Patrick Toomey <security@github.com>
+github.io
+githubusercontent.com
+githubcloud.com
+*.api.githubcloud.com
+*.ext.githubcloud.com
+gist.githubcloud.com
+*.githubcloudusercontent.com
+
+// GitLab, Inc.
+// Submitted by Alex Hanselka <alex@gitlab.com>
+gitlab.io
+
+// UKHomeOffice : https://www.gov.uk/government/organisations/home-office
+// Submitted by Jon Shanks <jon.shanks@digital.homeoffice.gov.uk>
+homeoffice.gov.uk
+
+// GlobeHosting, Inc.
+// Submitted by Zoltan Egresi <egresi@globehosting.com>
+ro.im
+shop.ro
+
+// GoIP DNS Services : http://www.goip.de
+// Submitted by Christian Poulter <milchstrasse@goip.de>
+goip.de
+
+// Google, Inc.
+// Submitted by Eduardo Vela <evn@google.com>
+*.0emm.com
+appspot.com
+blogspot.ae
+blogspot.al
+blogspot.am
+blogspot.ba
+blogspot.be
+blogspot.bg
+blogspot.bj
+blogspot.ca
+blogspot.cf
+blogspot.ch
+blogspot.cl
+blogspot.co.at
+blogspot.co.id
+blogspot.co.il
+blogspot.co.ke
+blogspot.co.nz
+blogspot.co.uk
+blogspot.co.za
+blogspot.com
+blogspot.com.ar
+blogspot.com.au
+blogspot.com.br
+blogspot.com.by
+blogspot.com.co
+blogspot.com.cy
+blogspot.com.ee
+blogspot.com.eg
+blogspot.com.es
+blogspot.com.mt
+blogspot.com.ng
+blogspot.com.tr
+blogspot.com.uy
+blogspot.cv
+blogspot.cz
+blogspot.de
+blogspot.dk
+blogspot.fi
+blogspot.fr
+blogspot.gr
+blogspot.hk
+blogspot.hr
+blogspot.hu
+blogspot.ie
+blogspot.in
+blogspot.is
+blogspot.it
+blogspot.jp
+blogspot.kr
+blogspot.li
+blogspot.lt
+blogspot.lu
+blogspot.md
+blogspot.mk
+blogspot.mr
+blogspot.mx
+blogspot.my
+blogspot.nl
+blogspot.no
+blogspot.pe
+blogspot.pt
+blogspot.qa
+blogspot.re
+blogspot.ro
+blogspot.rs
+blogspot.ru
+blogspot.se
+blogspot.sg
+blogspot.si
+blogspot.sk
+blogspot.sn
+blogspot.td
+blogspot.tw
+blogspot.ug
+blogspot.vn
+cloudfunctions.net
+cloud.goog
+codespot.com
+googleapis.com
+googlecode.com
+pagespeedmobilizer.com
+publishproxy.com
+withgoogle.com
+withyoutube.com
+
+// Hashbang : https://hashbang.sh
+hashbang.sh
+
+// Hasura : https://hasura.io
+// Submitted by Shahidh K Muhammed <shahidh@hasura.io>
+hasura-app.io
+
+// Hepforge : https://www.hepforge.org
+// Submitted by David Grellscheid <admin@hepforge.org>
+hepforge.org
+
+// Heroku : https://www.heroku.com/
+// Submitted by Tom Maher <tmaher@heroku.com>
+herokuapp.com
+herokussl.com
+
+// Ici la Lune : http://www.icilalune.com/
+// Submitted by Simon Morvan <simon@icilalune.com>
+moonscale.net
+
+// iki.fi
+// Submitted by Hannu Aronsson <haa@iki.fi>
+iki.fi
+
+// info.at : http://www.info.at/
+biz.at
+info.at
+
+// info.cx : http://info.cx
+// Submitted by Jacob Slater <whois@igloo.to>
+info.cx
+
+// Interlegis : http://www.interlegis.leg.br
+// Submitted by Gabriel Ferreira <registrobr@interlegis.leg.br>
+ac.leg.br
+al.leg.br
+am.leg.br
+ap.leg.br
+ba.leg.br
+ce.leg.br
+df.leg.br
+es.leg.br
+go.leg.br
+ma.leg.br
+mg.leg.br
+ms.leg.br
+mt.leg.br
+pa.leg.br
+pb.leg.br
+pe.leg.br
+pi.leg.br
+pr.leg.br
+rj.leg.br
+rn.leg.br
+ro.leg.br
+rr.leg.br
+rs.leg.br
+sc.leg.br
+se.leg.br
+sp.leg.br
+to.leg.br
+
+// IPiFony Systems, Inc. : https://www.ipifony.com/
+// Submitted by Matthew Hardeman <mhardeman@ipifony.com>
+ipifony.net
+
+// Joyent : https://www.joyent.com/
+// Submitted by Brian Bennett <brian.bennett@joyent.com>
+*.triton.zone
+*.cns.joyent.com
+
+// JS.ORG : http://dns.js.org
+// Submitted by Stefan Keim <admin@js.org>
+js.org
+
+// Keyweb AG : https://www.keyweb.de
+// Submitted by Martin Dannehl <postmaster@keymachine.de>
+keymachine.de
+
+// KnightPoint Systems, LLC : http://www.knightpoint.com/
+// Submitted by Roy Keene <rkeene@knightpoint.com>
+knightpoint.systems
+
+// .KRD : http://nic.krd/data/krd/Registration%20Policy.pdf
+co.krd
+edu.krd
+
+// LCube - Professional hosting e.K. : https://www.lcube-webhosting.de
+// Submitted by Lars Laehn <info@lcube.de>
+git-repos.de
+lcube-server.de
+svn-repos.de
+
+// Lukanet Ltd : https://lukanet.com
+// Submitted by Anton Avramov <register@lukanet.com>
+barsy.bg
+barsyonline.com
+barsy.de
+barsy.eu
+barsy.in
+barsy.net
+barsy.online
+barsy.support
+
+// Magento Commerce
+// Submitted by Damien Tournoud <dtournoud@magento.cloud>
+*.magentosite.cloud
+
+// Mail.Ru Group : https://hb.cldmail.ru
+// Submitted by Ilya Zaretskiy <zaretskiy@corp.mail.ru>
+hb.cldmail.ru
+
+// MetaCentrum, CESNET z.s.p.o. : https://www.metacentrum.cz/en/
+// Submitted by Zdeněk Šustr <zdenek.sustr@cesnet.cz>
+cloud.metacentrum.cz
+custom.metacentrum.cz
+
+// Meteor Development Group : https://www.meteor.com/hosting
+// Submitted by Pierre Carrier <pierre@meteor.com>
+meteorapp.com
+eu.meteorapp.com
+
+// Michau Enterprises Limited : http://www.co.pl/
+co.pl
+
+// Microsoft : http://microsoft.com
+// Submitted by Barry Dorrans <bdorrans@microsoft.com>
+azurewebsites.net
+azure-mobile.net
+cloudapp.net
+
+// Mozilla Foundation : https://mozilla.org/
+// Submitted by glob <glob@mozilla.com>
+bmoattachments.org
+
+// Neustar Inc.
+// Submitted by Trung Tran <Trung.Tran@neustar.biz>
+4u.com
+
+// ngrok : https://ngrok.com/
+// Submitted by Alan Shreve <alan@ngrok.com>
+ngrok.io
+
+// NFSN, Inc. : https://www.NearlyFreeSpeech.NET/
+// Submitted by Jeff Wheelhouse <support@nearlyfreespeech.net>
+nfshost.com
+
+// nsupdate.info : https://www.nsupdate.info/
+// Submitted by Thomas Waldmann <info@nsupdate.info>
+nsupdate.info
+nerdpol.ovh
+
+// No-IP.com : https://noip.com/
+// Submitted by Deven Reza <publicsuffixlist@noip.com>
+blogsyte.com
+brasilia.me
+cable-modem.org
+ciscofreak.com
+collegefan.org
+couchpotatofries.org
+damnserver.com
+ddns.me
+ditchyourip.com
+dnsfor.me
+dnsiskinky.com
+dvrcam.info
+dynns.com
+eating-organic.net
+fantasyleague.cc
+geekgalaxy.com
+golffan.us
+health-carereform.com
+homesecuritymac.com
+homesecuritypc.com
+hopto.me
+ilovecollege.info
+loginto.me
+mlbfan.org
+mmafan.biz
+myactivedirectory.com
+mydissent.net
+myeffect.net
+mymediapc.net
+mypsx.net
+mysecuritycamera.com
+mysecuritycamera.net
+mysecuritycamera.org
+net-freaks.com
+nflfan.org
+nhlfan.net
+no-ip.ca
+no-ip.co.uk
+no-ip.net
+noip.us
+onthewifi.com
+pgafan.net
+point2this.com
+pointto.us
+privatizehealthinsurance.net
+quicksytes.com
+read-books.org
+securitytactics.com
+serveexchange.com
+servehumour.com
+servep2p.com
+servesarcasm.com
+stufftoread.com
+ufcfan.org
+unusualperson.com
+workisboring.com
+3utilities.com
+bounceme.net
+ddns.net
+ddnsking.com
+gotdns.ch
+hopto.org
+myftp.biz
+myftp.org
+myvnc.com
+no-ip.biz
+no-ip.info
+no-ip.org
+noip.me
+redirectme.net
+servebeer.com
+serveblog.net
+servecounterstrike.com
+serveftp.com
+servegame.com
+servehalflife.com
+servehttp.com
+serveirc.com
+serveminecraft.net
+servemp3.com
+servepics.com
+servequake.com
+sytes.net
+webhop.me
+zapto.org
+
+// Nodum B.V. : https://nodum.io/
+// Submitted by Wietse Wind <hello+publicsuffixlist@nodum.io>
+nodum.co
+nodum.io
+
+// NYC.mn : http://www.information.nyc.mn
+// Submitted by Matthew Brown <mattbrown@nyc.mn>
+nyc.mn
+
+// Octopodal Solutions, LLC. : https://ulterius.io/
+// Submitted by Andrew Sampson <andrew@ulterius.io>
+cya.gg
+
+// One Fold Media : http://www.onefoldmedia.com/
+// Submitted by Eddie Jones <eddie@onefoldmedia.com>
+nid.io
+
+// OpenCraft GmbH : http://opencraft.com/
+// Submitted by Sven Marnach <sven@opencraft.com>
+opencraft.hosting
+
+// Opera Software, A.S.A.
+// Submitted by Yngve Pettersen <yngve@opera.com>
+operaunite.com
+
+// OutSystems
+// Submitted by Duarte Santos <domain-admin@outsystemscloud.com>
+outsystemscloud.com
+
+// OwnProvider : http://www.ownprovider.com
+// Submitted by Jan Moennich <jan.moennich@ownprovider.com>
+ownprovider.com
+
+// oy.lc
+// Submitted by Charly Coste <changaco@changaco.oy.lc>
+oy.lc
+
+// Pagefog : https://pagefog.com/
+// Submitted by Derek Myers <derek@pagefog.com>
+pgfog.com
+
+// Pagefront : https://www.pagefronthq.com/
+// Submitted by Jason Kriss <jason@pagefronthq.com>
+pagefrontapp.com
+
+// .pl domains (grandfathered)
+art.pl
+gliwice.pl
+krakow.pl
+poznan.pl
+wroc.pl
+zakopane.pl
+
+// Pantheon Systems, Inc. : https://pantheon.io/
+// Submitted by Gary Dylina <gary@pantheon.io>
+pantheonsite.io
+gotpantheon.com
+
+// Peplink | Pepwave : http://peplink.com/
+// Submitted by Steve Leung <steveleung@peplink.com>
+mypep.link
+
+// Planet-Work : https://www.planet-work.com/
+// Submitted by Frédéric VANNIÈRE <f.vanniere@planet-work.com>
+on-web.fr
+
+// Platform.sh : https://platform.sh
+// Submitted by Nikola Kotur <nikola@platform.sh>
+*.platform.sh
+*.platformsh.site
+
+// prgmr.com : https://prgmr.com/
+// Submitted by Sarah Newman <owner@prgmr.com>
+xen.prgmr.com
+
+// priv.at : http://www.nic.priv.at/
+// Submitted by registry <lendl@nic.at>
+priv.at
+
+// Protonet GmbH : http://protonet.io
+// Submitted by Martin Meier <admin@protonet.io>
+protonet.io
+
+// Publication Presse Communication SARL : https://ppcom.fr
+// Submitted by Yaacov Akiba Slama <admin@chirurgiens-dentistes-en-france.fr>
+chirurgiens-dentistes-en-france.fr
+
+// QA2
+// Submitted by Daniel Dent (https://www.danieldent.com/)
+qa2.com
+
+// QNAP System Inc : https://www.qnap.com
+// Submitted by Nick Chang <nickchang@qnap.com>
+dev-myqnapcloud.com
+alpha-myqnapcloud.com
+myqnapcloud.com
+
+// Quip : https://quip.com
+// Submitted by Patrick Linehan <plinehan@quip.com>
+*.quipelements.com
+
+// Qutheory LLC : http://qutheory.io
+// Submitted by Jonas Schwartz <jonas@qutheory.io>
+vapor.cloud
+vaporcloud.io
+
+// Rackmaze LLC : https://www.rackmaze.com
+// Submitted by Kirill Pertsev <kika@rackmaze.com>
+rackmaze.com
+rackmaze.net
+
+// Red Hat, Inc. OpenShift : https://openshift.redhat.com/
+// Submitted by Tim Kramer <tkramer@rhcloud.com>
+rhcloud.com
+
+// RethinkDB : https://www.rethinkdb.com/
+// Submitted by Chris Kastorff <info@rethinkdb.com>
+hzc.io
+
+// Revitalised Limited : http://www.revitalised.co.uk
+// Submitted by Jack Price <jack@revitalised.co.uk>
+wellbeingzone.eu
+ptplus.fit
+wellbeingzone.co.uk
+
+// Sandstorm Development Group, Inc. : https://sandcats.io/
+// Submitted by Asheesh Laroia <asheesh@sandstorm.io>
+sandcats.io
+
+// SBE network solutions GmbH : https://www.sbe.de/
+// Submitted by Norman Meilick <nm@sbe.de>
+logoip.de
+logoip.com
+
+// Securepoint GmbH : https://www.securepoint.de
+// Submitted by Erik Anders <erik.anders@securepoint.de>
+firewall-gateway.com
+firewall-gateway.de
+my-gateway.de
+my-router.de
+spdns.de
+spdns.eu
+firewall-gateway.net
+my-firewall.org
+myfirewall.org
+spdns.org
+
+// SensioLabs, SAS : https://sensiolabs.com/
+// Submitted by Fabien Potencier <fabien.potencier@sensiolabs.com>
+*.sensiosite.cloud
+
+// Service Online LLC : http://drs.ua/
+// Submitted by Serhii Bulakh <support@drs.ua>
+biz.ua
+co.ua
+pp.ua
+
+// ShiftEdit : https://shiftedit.net/
+// Submitted by Adam Jimenez <adam@shiftcreate.com>
+shiftedit.io
+
+// Shopblocks : http://www.shopblocks.com/
+// Submitted by Alex Bowers <alex@shopblocks.com>
+myshopblocks.com
+
+// SinaAppEngine : http://sae.sina.com.cn/
+// Submitted by SinaAppEngine <saesupport@sinacloud.com>
+1kapp.com
+appchizi.com
+applinzi.com
+sinaapp.com
+vipsinaapp.com
+
+// Skyhat : http://www.skyhat.io
+// Submitted by Shante Adam <shante@skyhat.io>
+bounty-full.com
+alpha.bounty-full.com
+beta.bounty-full.com
+
+// staticland : https://static.land
+// Submitted by Seth Vincent <sethvincent@gmail.com>
+static.land
+dev.static.land
+sites.static.land
+
+// SourceLair PC : https://www.sourcelair.com
+// Submitted by Antonis Kalipetis <akalipetis@sourcelair.com>
+apps.lair.io
+*.stolos.io
+
+// SpaceKit : https://www.spacekit.io/
+// Submitted by Reza Akhavan <spacekit.io@gmail.com>
+spacekit.io
+
+// Stackspace : https://www.stackspace.io/
+// Submitted by Lina He <info@stackspace.io>
+stackspace.space
+
+// Storj Labs Inc. : https://storj.io/
+// Submitted by Philip Hutchins <hostmaster@storj.io>
+storj.farm
+
+// Synology, Inc. : https://www.synology.com/
+// Submitted by Rony Weng <ronyweng@synology.com>
+diskstation.me
+dscloud.biz
+dscloud.me
+dscloud.mobi
+dsmynas.com
+dsmynas.net
+dsmynas.org
+familyds.com
+familyds.net
+familyds.org
+i234.me
+myds.me
+synology.me
+vpnplus.to
+
+// TAIFUN Software AG : http://taifun-software.de
+// Submitted by Bjoern Henke <dev-server@taifun-software.de>
+taifun-dns.de
+
+// TASK geographical domains (www.task.gda.pl/uslugi/dns)
+gda.pl
+gdansk.pl
+gdynia.pl
+med.pl
+sopot.pl
+
+// Thingdust AG : https://thingdust.com/
+// Submitted by Adrian Imboden <adi@thingdust.com>
+cust.dev.thingdust.io
+cust.disrec.thingdust.io
+cust.prod.thingdust.io
+cust.testing.thingdust.io
+
+// TownNews.com : http://www.townnews.com
+// Submitted by Dustin Ward <dward@townnews.com>
+bloxcms.com
+townnews-staging.com
+
+// TrafficPlex GmbH : https://www.trafficplex.de/
+// Submitted by Phillipp Röll <phillipp.roell@trafficplex.de>
+12hp.at
+2ix.at
+4lima.at
+lima-city.at
+12hp.ch
+2ix.ch
+4lima.ch
+lima-city.ch
+trafficplex.cloud
+de.cool
+12hp.de
+2ix.de
+4lima.de
+lima-city.de
+1337.pictures
+clan.rip
+lima-city.rocks
+webspace.rocks
+lima.zone
+
+// TransIP : htts://www.transip.nl
+// Submitted by Rory Breuk <rbreuk@transip.nl>
+*.transurl.be
+*.transurl.eu
+*.transurl.nl
+
+// TuxFamily : http://tuxfamily.org
+// Submitted by TuxFamily administrators <adm@staff.tuxfamily.org>
+tuxfamily.org
+
+// TwoDNS : https://www.twodns.de/
+// Submitted by TwoDNS-Support <support@two-dns.de>
+dd-dns.de
+diskstation.eu
+diskstation.org
+dray-dns.de
+draydns.de
+dyn-vpn.de
+dynvpn.de
+mein-vigor.de
+my-vigor.de
+my-wan.de
+syno-ds.de
+synology-diskstation.de
+synology-ds.de
+
+// Uberspace : https://uberspace.de
+// Submitted by Moritz Werner <mwerner@jonaspasche.com>
+uber.space
+
+// UDR Limited : http://www.udr.hk.com
+// Submitted by registry <hostmaster@udr.hk.com>
+hk.com
+hk.org
+ltd.hk
+inc.hk
+
+// .US
+// Submitted by Ed Moore <Ed.Moore@lib.de.us>
+lib.de.us
+
+// Viprinet Europe GmbH : http://www.viprinet.com
+// Submitted by Simon Kissel <hostmaster@viprinet.com>
+router.management
+
+// WeDeploy by Liferay, Inc. : https://www.wedeploy.com
+// Submitted by Henrique Vicente <security@wedeploy.com>
+wedeploy.io
+wedeploy.me
+
+// Western Digital Technologies, Inc : https://www.wdc.com
+// Submitted by Jung Jin <jungseok.jin@wdc.com>
+remotewd.com
+
+// Wikimedia Labs : https://wikitech.wikimedia.org
+// Submitted by Yuvi Panda <yuvipanda@wikimedia.org>
+wmflabs.org
+
+// XS4ALL Internet bv : https://www.xs4all.nl/
+// Submitted by Daniel Mostertman <unixbeheer+publicsuffix@xs4all.net>
+cistron.nl
+demon.nl
+xs4all.space
+
+// Yola : https://www.yola.com/
+// Submitted by Stefano Rivera <stefano@yola.com>
+yolasite.com
+
+// Yombo : https://yombo.net
+// Submitted by Mitch Schwenk <mitch@yombo.net>
+ybo.faith
+yombo.me
+homelink.one
+ybo.party
+ybo.review
+ybo.science
+ybo.trade
+
+// ZaNiC : http://www.za.net/
+// Submitted by registry <hostmaster@nic.za.net>
+za.net
+za.org
+
+// Zeit, Inc. : https://zeit.domains/
+// Submitted by Olli Vanhoja <olli@zeit.co>
+now.sh
+
+// ===END PRIVATE DOMAINS===
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "iputils.hh"
+#include "dns.hh"
+#include "dnsparser.hh"
+#include <map>
+#include <unordered_map>
+
+/* This class implements a filtering policy that is able to fully implement RPZ, but is not bound to it.
+ In other words, it is generic enough to support RPZ, but could get its data from other places.
+
+
+ We know the following actions:
+
+ No action - just pass it on
+ Drop - drop a query, no response
+ NXDOMAIN - fake up an NXDOMAIN for the query
+ NODATA - just return no data for this qtype
+ Truncate - set TC bit
+ Modified - "we fake an answer for you"
+
+ These actions can be caused by the following triggers:
+
+ qname - the query name
+ client-ip - the IP address of the requestor
+ response-ip - an IP address in the response
+ ns-name - the name of a server used in the delegation
+ ns-ip - the IP address of a server used in the delegation
+
+ This means we get several hook points:
+ 1) when the query comes in: qname & client-ip
+ 2) during processing: ns-name & ns-ip
+ 3) after processing: response-ip
+
+ Triggers meanwhile can apply to:
+ Verbatim domain names
+ Wildcard versions (*.domain.com does NOT match domain.com)
+ Netmasks (IPv4 and IPv6)
+ Finally, triggers are grouped in different zones. The "first" zone that has a match
+ is consulted. Then within that zone, rules again have precedences.
+*/
+
+
+class DNSFilterEngine
+{
+public:
+ enum class PolicyKind { NoAction, Drop, NXDOMAIN, NODATA, Truncate, Custom};
+ struct Policy
+ {
+ Policy(): d_kind(PolicyKind::NoAction), d_custom(nullptr), d_name(nullptr), d_ttl(0)
+ {
+ }
+ bool operator==(const Policy& rhs) const
+ {
+ return d_kind == rhs.d_kind; // XXX check d_custom too!
+ }
+ PolicyKind d_kind;
+ std::shared_ptr<DNSRecordContent> d_custom;
+ std::shared_ptr<std::string> d_name;
+ int d_ttl;
+ };
+
+ DNSFilterEngine();
+ void clear();
+ void clear(size_t zone);
+ void addClientTrigger(const Netmask& nm, Policy pol, size_t zone);
+ void addQNameTrigger(const DNSName& nm, Policy pol, size_t zone);
+ void addNSTrigger(const DNSName& dn, Policy pol, size_t zone);
+ void addNSIPTrigger(const Netmask& nm, Policy pol, size_t zone);
+ void addResponseTrigger(const Netmask& nm, Policy pol, size_t zone);
+
+ bool rmClientTrigger(const Netmask& nm, Policy pol, size_t zone);
+ bool rmQNameTrigger(const DNSName& nm, Policy pol, size_t zone);
+ bool rmNSTrigger(const DNSName& dn, Policy pol, size_t zone);
+ bool rmNSIPTrigger(const Netmask& nm, Policy pol, size_t zone);
+ bool rmResponseTrigger(const Netmask& nm, Policy pol, size_t zone);
+
+
+ Policy getQueryPolicy(const DNSName& qname, const ComboAddress& nm, const std::unordered_map<std::string,bool>& discardedPolicies) const;
+ Policy getProcessingPolicy(const DNSName& qname, const std::unordered_map<std::string,bool>& discardedPolicies) const;
+ Policy getProcessingPolicy(const ComboAddress& address, const std::unordered_map<std::string,bool>& discardedPolicies) const;
+ Policy getPostPolicy(const vector<DNSRecord>& records, const std::unordered_map<std::string,bool>& discardedPolicies) const;
+
+ size_t size() {
+ return d_zones.size();
+ }
+ void setPolicyName(size_t zoneIdx, std::string name)
+ {
+ assureZones(zoneIdx);
+ d_zones[zoneIdx].name = std::make_shared<std::string>(name);
+ }
+private:
+ void assureZones(size_t zone);
+ struct Zone {
+ std::map<DNSName, Policy> qpolName; // QNAME trigger (RPZ)
+ NetmaskTree<Policy> qpolAddr; // Source address
+ std::map<DNSName, Policy> propolName; // NSDNAME (RPZ)
+ NetmaskTree<Policy> propolNSAddr; // NSIP (RPZ)
+ NetmaskTree<Policy> postpolAddr; // IP trigger (RPZ)
+ std::shared_ptr<std::string> name;
+ };
+ vector<Zone> d_zones;
+
+};
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "gettime.hh"
+#include "config.h"
+
+#ifdef HAVE_CLOCK_GETTIME
+#include <time.h>
+
+#ifndef CLOCK_MONOTONIC_RAW
+#define CLOCK_MONOTONIC_RAW CLOCK_MONOTONIC
+#endif
+
+int gettime(struct timespec *tp, bool needRealTime)
+{
+ return clock_gettime(needRealTime ? CLOCK_REALTIME : CLOCK_MONOTONIC_RAW, tp);
+}
+
+#else
+#include <sys/time.h>
+
+int gettime(struct timespec *tp, bool needRealTime)
+{
+ struct timeval tv;
+
+ int ret = gettimeofday(&tv, NULL);
+ if(ret < 0) return ret;
+
+ tp->tv_sec = tv.tv_sec;
+ tp->tv_nsec = tv.tv_usec * 1000;
+ return ret;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+extern int gettime(struct timespec *tp, bool needRealTime=false);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <map>
+#include <string>
+#include "namespaces.hh"
+#include "dns.hh"
+#include "dnsparser.hh"
+#include "dnspacket.hh"
+#include "dnsrecords.hh"
+#include "logger.hh"
+#include "lock.hh"
+#include "arguments.hh"
+
+#include <boost/shared_ptr.hpp>
+#include <boost/make_shared.hpp>
+#include "gss_context.hh"
+
+#ifndef ENABLE_GSS_TSIG
+
+bool GssContext::supported() { return false; }
+GssContext::GssContext() { d_error = GSS_CONTEXT_UNSUPPORTED; d_type = GSS_CONTEXT_NONE; }
+GssContext::GssContext(const DNSName& label) { d_error = GSS_CONTEXT_UNSUPPORTED; d_type = GSS_CONTEXT_NONE; }
+void GssContext::setLocalPrincipal(const std::string& name) {}
+bool GssContext::getLocalPrincipal(std::string& name) { return false; }
+void GssContext::setPeerPrincipal(const std::string& name) {}
+bool GssContext::getPeerPrincipal(std::string& name) { return false; }
+void GssContext::generateLabel(const std::string& suffix) {}
+void GssContext::setLabel(const DNSName& label) {}
+bool GssContext::init(const std::string &input, std::string& output) { return false; }
+bool GssContext::accept(const std::string &input, std::string& output) { return false; }
+bool GssContext::destroy() { return false; }
+bool GssContext::expired() { return false; }
+bool GssContext::valid() { return false; }
+bool GssContext::sign(const std::string &input, std::string& output) { return false; }
+bool GssContext::verify(const std::string &input, const std::string &signature) { return false; }
+GssContextError GssContext::getError() { return GSS_CONTEXT_UNSUPPORTED; }
+
+#else
+
+class GssCredential : boost::noncopyable {
+public:
+ GssCredential(const std::string& name, const gss_cred_usage_t usage) {
+ gss_buffer_desc buffer;
+ d_name = GSS_C_NO_NAME;
+ d_nameS = name;
+ d_cred = GSS_C_NO_CREDENTIAL;
+
+ d_usage = usage;
+ d_valid = false;
+
+ if (name.empty() == false) {
+ buffer.length = name.size();
+ buffer.value = (void*)name.c_str();
+ d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name);
+ if (d_maj != GSS_S_COMPLETE) {
+ d_valid = false;
+ return;
+ }
+ }
+
+ renew();
+ };
+
+ ~GssCredential() {
+ OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ if (d_cred != GSS_C_NO_CREDENTIAL)
+ tmp_maj = gss_release_cred(&tmp_min, &d_cred);
+ if (d_name != GSS_C_NO_NAME)
+ tmp_maj = gss_release_name(&tmp_min, &d_name);
+ };
+
+ bool expired() const {
+ if (d_expires == -1) return false;
+ return time((time_t*)NULL)>d_expires;
+ }
+
+ bool renew() {
+ OM_uint32 time_rec, tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ d_maj = gss_acquire_cred(&d_min, d_name, GSS_C_INDEFINITE, GSS_C_NO_OID_SET, d_usage, &d_cred, NULL, &time_rec);
+
+ if (d_maj != GSS_S_COMPLETE) {
+ d_valid = false;
+ tmp_maj = gss_release_name(&tmp_min, &d_name);
+ d_name = GSS_C_NO_NAME;
+ return false;
+ }
+
+ d_valid = true;
+
+ if (time_rec > GSS_C_INDEFINITE) {
+ d_expires = time((time_t*)NULL)+time_rec;
+ } else {
+ d_expires = -1;
+ }
+
+ return true;
+ }
+
+ bool valid() {
+ return d_valid && !expired();
+ }
+
+ OM_uint32 d_maj,d_min;
+
+ bool d_valid;
+ int64_t d_expires;
+ std::string d_nameS;
+ gss_name_t d_name;
+ gss_cred_id_t d_cred;
+ gss_cred_usage_t d_usage;
+};
+
+std::map<std::string, boost::shared_ptr<GssCredential> > s_gss_accept_creds;
+std::map<std::string, boost::shared_ptr<GssCredential> > s_gss_init_creds;
+
+class GssSecContext : boost::noncopyable {
+public:
+ GssSecContext(boost::shared_ptr<GssCredential> cred) {
+ if (cred->valid() == false) throw PDNSException("Invalid credential " + cred->d_nameS);
+ d_cred = cred;
+ d_state = GssStateInitial;
+ d_ctx = GSS_C_NO_CONTEXT;
+ d_expires = 0;
+ d_maj = d_min = 0;
+ d_peer_name = GSS_C_NO_NAME;
+ d_type = GSS_CONTEXT_NONE;
+ }
+
+ ~GssSecContext() {
+ OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ if (d_ctx != GSS_C_NO_CONTEXT) {
+ tmp_maj = gss_delete_sec_context(&tmp_min, &d_ctx, GSS_C_NO_BUFFER);
+ }
+ if (d_peer_name != GSS_C_NO_NAME) {
+ tmp_maj = gss_release_name(&tmp_min, &(d_peer_name));
+ }
+ }
+
+ GssContextType d_type;
+ gss_ctx_id_t d_ctx;
+ gss_name_t d_peer_name;
+ int64_t d_expires;
+ boost::shared_ptr<GssCredential> d_cred;
+ OM_uint32 d_maj,d_min;
+
+ enum {
+ GssStateInitial,
+ GssStateNegotiate,
+ GssStateComplete,
+ GssStateError
+ } d_state;
+
+};
+
+std::map<DNSName, boost::shared_ptr<GssSecContext> > s_gss_sec_context;
+
+bool GssContext::supported() { return true; }
+
+void GssContext::initialize() {
+ d_peerPrincipal = "";
+ d_localPrincipal = "";
+ d_error = GSS_CONTEXT_NO_ERROR;
+ d_type = GSS_CONTEXT_NONE;
+}
+
+GssContext::GssContext() {
+ initialize();
+ generateLabel("pdns.tsig.");
+}
+
+GssContext::GssContext(const DNSName& label) {
+ initialize();
+ setLabel(label);
+}
+
+void GssContext::generateLabel(const std::string& suffix) {
+ std::ostringstream oss;
+ oss << std::hex << time((time_t*)NULL) << "." << suffix;
+ setLabel(DNSName(oss.str()));
+}
+
+void GssContext::setLabel(const DNSName& label) {
+ d_label = label;
+ if (s_gss_sec_context.find(d_label) != s_gss_sec_context.end()) {
+ d_ctx = s_gss_sec_context[d_label];
+ d_type = d_ctx->d_type;
+ }
+}
+
+bool GssContext::expired() {
+ return (!d_ctx || (d_ctx->d_expires > -1 && d_ctx->d_expires < time((time_t*)NULL)));
+}
+
+bool GssContext::valid() {
+ return (d_ctx && !expired() && d_ctx->d_state == GssSecContext::GssStateComplete);
+}
+
+bool GssContext::init(const std::string &input, std::string& output) {
+ OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ OM_uint32 maj,min;
+ gss_buffer_desc recv_tok, send_tok, buffer;
+ OM_uint32 flags;
+ OM_uint32 expires;
+
+ boost::shared_ptr<GssCredential> cred;
+ if (d_label.empty()) {
+ d_error = GSS_CONTEXT_INVALID;
+ return false;
+ }
+
+ d_type = GSS_CONTEXT_INIT;
+
+ if (s_gss_init_creds.find(d_localPrincipal) != s_gss_init_creds.end()) {
+ cred = s_gss_init_creds[d_localPrincipal];
+ } else {
+ s_gss_init_creds[d_localPrincipal] = boost::make_shared<GssCredential>(d_localPrincipal, GSS_C_INITIATE);
+ cred = s_gss_init_creds[d_localPrincipal];
+ }
+
+ // see if we can find a context in non-completed state
+ if (d_ctx) {
+ if (d_ctx->d_state != GssSecContext::GssStateNegotiate) {
+ d_error = GSS_CONTEXT_INVALID;
+ return false;
+ }
+ } else {
+ // make context
+ s_gss_sec_context[d_label] = boost::make_shared<GssSecContext>(cred);
+ s_gss_sec_context[d_label]->d_type = d_type;
+ d_ctx = s_gss_sec_context[d_label];
+ d_ctx->d_state = GssSecContext::GssStateNegotiate;
+ }
+
+ recv_tok.length = input.size();
+ recv_tok.value = (void*)input.c_str();
+
+ if (d_peerPrincipal.empty() == false) {
+ buffer.value = (void*)d_peerPrincipal.c_str();
+ buffer.length = d_peerPrincipal.size();
+ maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &(d_ctx->d_peer_name));
+ if (maj != GSS_S_COMPLETE) {
+ processError("gss_import_name", maj, min);
+ return false;
+ }
+ }
+
+ maj = gss_init_sec_context(&min, cred->d_cred, &(d_ctx->d_ctx), d_ctx->d_peer_name, GSS_C_NO_OID, GSS_C_MUTUAL_FLAG|GSS_C_REPLAY_FLAG, GSS_C_INDEFINITE, GSS_C_NO_CHANNEL_BINDINGS, &recv_tok, NULL, &send_tok, &flags, &expires);
+
+ if (send_tok.length>0) {
+ output.assign((const char*)send_tok.value, send_tok.length);
+ tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
+ }
+
+ if (maj == GSS_S_COMPLETE) {
+ if (expires > GSS_C_INDEFINITE) {
+ d_ctx->d_expires = time((time_t*)NULL) + expires;
+ } else {
+ d_ctx->d_expires = -1;
+ }
+ d_ctx->d_state = GssSecContext::GssStateComplete;
+ return true;
+ } else if (maj != GSS_S_CONTINUE_NEEDED) {
+ processError("gss_init_sec_context", maj,min);
+ }
+
+ return (maj == GSS_S_CONTINUE_NEEDED);
+}
+
+bool GssContext::accept(const std::string &input, std::string& output) {
+ OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ OM_uint32 maj,min;
+ gss_buffer_desc recv_tok, send_tok;
+ OM_uint32 flags;
+ OM_uint32 expires;
+
+ boost::shared_ptr<GssCredential> cred;
+ if (d_label.empty()) {
+ d_error = GSS_CONTEXT_INVALID;
+ return false;
+ }
+
+ d_type = GSS_CONTEXT_ACCEPT;
+
+ if (s_gss_accept_creds.find(d_localPrincipal) != s_gss_accept_creds.end()) {
+ cred = s_gss_accept_creds[d_localPrincipal];
+ } else {
+ s_gss_accept_creds[d_localPrincipal] = boost::make_shared<GssCredential>(d_localPrincipal, GSS_C_ACCEPT);
+ cred = s_gss_accept_creds[d_localPrincipal];
+ }
+
+ // see if we can find a context in non-completed state
+ if (d_ctx) {
+ if (d_ctx->d_state != GssSecContext::GssStateNegotiate) {
+ d_error = GSS_CONTEXT_INVALID;
+ return false;
+ }
+ } else {
+ // make context
+ s_gss_sec_context[d_label] = boost::make_shared<GssSecContext>(cred);
+ s_gss_sec_context[d_label]->d_type = d_type;
+ d_ctx = s_gss_sec_context[d_label];
+ d_ctx->d_state = GssSecContext::GssStateNegotiate;
+ }
+
+ recv_tok.length = input.size();
+ recv_tok.value = (void*)input.c_str();
+
+ maj = gss_accept_sec_context(&min, &(d_ctx->d_ctx), cred->d_cred, &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &(d_ctx->d_peer_name), NULL, &send_tok, &flags, &expires, NULL);
+
+ if (send_tok.length>0) {
+ output.assign((const char*)send_tok.value, send_tok.length);
+ tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
+ }
+
+ if (maj == GSS_S_COMPLETE) {
+ if (expires > GSS_C_INDEFINITE) {
+ d_ctx->d_expires = time((time_t*)NULL) + expires;
+ } else {
+ d_ctx->d_expires = -1;
+ }
+ d_ctx->d_state = GssSecContext::GssStateComplete;
+ return true;
+ } else if (maj != GSS_S_CONTINUE_NEEDED) {
+ processError("gss_accept_sec_context", maj,min);
+ }
+ return (maj == GSS_S_CONTINUE_NEEDED);
+};
+
+bool GssContext::sign(const std::string& input, std::string& output) {
+ OM_uint32 tmp_maj __attribute__((unused)), tmp_min __attribute__((unused));
+ OM_uint32 maj,min;
+
+ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc send_tok = GSS_C_EMPTY_BUFFER;
+
+ recv_tok.length = input.size();
+ recv_tok.value = (void*)input.c_str();
+
+ maj = gss_get_mic(&min, d_ctx->d_ctx, GSS_C_QOP_DEFAULT, &recv_tok, &send_tok);
+
+ if (send_tok.length>0) {
+ output.assign((const char*)send_tok.value, send_tok.length);
+ tmp_maj = gss_release_buffer(&tmp_min, &send_tok);
+ }
+
+ if (maj != GSS_S_COMPLETE) {
+ processError("gss_get_mic", maj,min);
+ }
+
+ return (maj == GSS_S_COMPLETE);
+}
+
+bool GssContext::verify(const std::string& input, const std::string& signature) {
+ OM_uint32 maj,min;
+
+ gss_buffer_desc recv_tok = GSS_C_EMPTY_BUFFER;
+ gss_buffer_desc sign_tok = GSS_C_EMPTY_BUFFER;
+
+ recv_tok.length = input.size();
+ recv_tok.value = (void*)input.c_str();
+ sign_tok.length = signature.size();
+ sign_tok.value = (void*)signature.c_str();
+
+ maj = gss_verify_mic(&min, d_ctx->d_ctx, &recv_tok, &sign_tok, NULL);
+
+ if (maj != GSS_S_COMPLETE) {
+ processError("gss_get_mic", maj,min);
+ }
+
+ return (maj == GSS_S_COMPLETE);
+}
+
+bool GssContext::destroy() {
+ return false;
+}
+
+void GssContext::setLocalPrincipal(const std::string& name) {
+ d_localPrincipal = name;
+}
+
+bool GssContext::getLocalPrincipal(std::string& name) {
+ name = d_localPrincipal;
+ return name.size()>0;
+}
+
+void GssContext::setPeerPrincipal(const std::string& name) {
+ d_peerPrincipal = name;
+}
+
+bool GssContext::getPeerPrincipal(std::string& name) {
+ gss_buffer_desc value;
+ OM_uint32 maj,min;
+
+ if (d_ctx->d_peer_name != GSS_C_NO_NAME) {
+ maj = gss_display_name(&min, d_ctx->d_peer_name, &value, NULL);
+ if (maj == GSS_S_COMPLETE && value.length > 0) {
+ name.assign((const char*)value.value, value.length);
+ maj = gss_release_buffer(&min, &value);
+ return true;
+ } else {
+ return false;
+ }
+ } else {
+ return false;
+ }
+}
+
+void GssContext::processError(const std::string& method, OM_uint32 maj, OM_uint32 min) {
+ OM_uint32 tmp_min;
+ gss_buffer_desc msg;
+ OM_uint32 msg_ctx;
+
+ msg_ctx = 0;
+ while (1) {
+ ostringstream oss;
+ gss_display_status(&tmp_min, maj, GSS_C_GSS_CODE, GSS_C_NULL_OID, &msg_ctx, &msg);
+ oss << method << ": " << (char*)msg.value;
+ d_gss_errors.push_back(oss.str());
+ if (!msg_ctx) break;
+ }
+ msg_ctx = 0;
+ while (1) {
+ ostringstream oss;
+ gss_display_status(&tmp_min, min, GSS_C_MECH_CODE, GSS_C_NULL_OID, &msg_ctx, &msg);
+ oss << method << ": " << (char*)msg.value;
+ d_gss_errors.push_back(oss.str());
+ if (!msg_ctx) break;
+ }
+}
+
+#endif
+
+bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac) {
+ string tmp_mac;
+ GssContext gssctx(context);
+ if (!gssctx.valid()) {
+ L<<Logger::Error<<"GSS context '"<<context<<"' is not valid"<<endl;
+ for(const string& error : gssctx.getErrorStrings()) {
+ L<<Logger::Error<<"GSS error: "<<error<<endl;;
+ }
+ return false;
+ }
+
+ if (!gssctx.sign(message, tmp_mac)) {
+ L<<Logger::Error<<"Could not sign message using GSS context '"<<context<<"'"<<endl;
+ for(const string& error : gssctx.getErrorStrings()) {
+ L<<Logger::Error<<"GSS error: "<<error<<endl;;
+ }
+ return false;
+ }
+ mac = tmp_mac;
+ return true;
+}
+
+bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac) {
+ GssContext gssctx(context);
+ if (!gssctx.valid()) {
+ L<<Logger::Error<<"GSS context '"<<context<<"' is not valid"<<endl;
+ for(const string& error : gssctx.getErrorStrings()) {
+ L<<Logger::Error<<"GSS error: "<<error<<endl;;
+ }
+ return false;
+ }
+
+ if (!gssctx.verify(message, mac)) {
+ L<<Logger::Error<<"Could not verify message using GSS context '"<<context<<"'"<<endl;
+ for(const string& error : gssctx.getErrorStrings()) {
+ L<<Logger::Error<<"GSS error: "<<error<<endl;;
+ }
+ return false;
+ }
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef GSS_CONTEXT_HH
+#define GSS_CONTEXT_HH
+#pragma once
+
+#ifdef ENABLE_GSS_TSIG
+#include <gssapi/gssapi.h>
+#include <gssapi/gssapi_krb5.h>
+#include <gssapi/gssapi_ext.h>
+#endif
+
+//! Generic errors
+enum GssContextError {
+ GSS_CONTEXT_NO_ERROR,
+ GSS_CONTEXT_UNSUPPORTED,
+ GSS_CONTEXT_NOT_FOUND,
+ GSS_CONTEXT_NOT_INITIALIZED,
+ GSS_CONTEXT_INVALID,
+ GSS_CONTEXT_EXPIRED,
+ GSS_CONTEXT_ALREADY_INITIALIZED
+};
+
+//! GSS context types
+enum GssContextType {
+ GSS_CONTEXT_NONE,
+ GSS_CONTEXT_INIT,
+ GSS_CONTEXT_ACCEPT
+};
+
+class GssSecContext;
+
+/*! Class for representing GSS names, such as host/host.domain.com@REALM.
+*/
+class GssName {
+public:
+ //! Initialize to empty name
+ GssName() {
+ setName("");
+ };
+
+ //! Initilize using specific name
+ GssName(const std::string& name) {
+ setName(name);
+ };
+
+ //! Parse name into native representation
+ bool setName(const std::string& name) {
+#ifdef ENABLE_GSS_TSIG
+ gss_buffer_desc buffer;
+ d_name = GSS_C_NO_NAME;
+
+ if (!name.empty()) {
+ buffer.length = name.size();
+ buffer.value = (void*)name.c_str();
+ d_maj = gss_import_name(&d_min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &d_name);
+ return d_maj == GSS_S_COMPLETE;
+ }
+
+ return true;
+#endif
+ return false;
+ };
+
+ ~GssName() {
+#ifdef ENABLE_GSS_TSIG
+ if (d_name != GSS_C_NO_NAME)
+ gss_release_name(&d_min, &d_name);
+#endif
+ };
+
+ //! Compare two Gss Names, if no gss support is compiled in, returns false always
+ //! This is not necessarely same as string comparison between two non-parsed names
+ bool operator==(const GssName& rhs) {
+#ifdef ENABLE_GSS_TSIG
+ OM_uint32 maj,min;
+ int result;
+ maj = gss_compare_name(&min, d_name, rhs.d_name, &result);
+ return (maj == GSS_S_COMPLETE && result != 0);
+#endif
+ return false;
+ }
+
+ //! Compare two Gss Names, if no gss support is compiled in, returns false always
+ //! This is not necessarely same as string comparison between two non-parsed names
+ bool match(const std::string& name) {
+#ifdef ENABLE_GSS_TSIG
+ OM_uint32 maj,min;
+ int result;
+ gss_name_t comp;
+ gss_buffer_desc buffer;
+ buffer.length = name.size();
+ buffer.value = (void*)name.c_str();
+ maj = gss_import_name(&min, &buffer, (gss_OID)GSS_KRB5_NT_PRINCIPAL_NAME, &comp);
+ if (maj != GSS_S_COMPLETE)
+ throw PDNSException("Could not import " + name + ": " + std::to_string(maj) + string(",") + std::to_string(min));
+ // do comparison
+ maj = gss_compare_name(&min, d_name, comp, &result);
+ gss_release_name(&min, &comp);
+ return (maj == GSS_S_COMPLETE && result != 0);
+#else
+ return false;
+#endif
+ };
+
+ //! Check if GSS name was parsed successfully.
+ bool valid() {
+#ifdef ENABLE_GSS_TSIG
+ return d_maj == GSS_S_COMPLETE;
+#else
+ return false;
+#endif
+ }
+private:
+#ifdef ENABLE_GSS_TSIG
+ OM_uint32 d_maj,d_min;
+ gss_name_t d_name;
+#endif
+};
+
+class GssContext {
+public:
+ static bool supported(); //<! Returns true if GSS is supported in the first place
+ GssContext(); //<! Construct new GSS context with random name
+ GssContext(const DNSName& label); //<! Create or open existing named context
+
+ void setLocalPrincipal(const std::string& name); //<! Set our gss name
+ bool getLocalPrincipal(std::string& name); //<! Get our name
+ void setPeerPrincipal(const std::string& name); //<! Set remote name (do not use after negotiation)
+ bool getPeerPrincipal(std::string &name); //<! Return remote name, returns actual name after negotatioan
+
+ void generateLabel(const std::string& suffix); //<! Generate random context name using suffix (such as mydomain.com)
+ void setLabel(const DNSName& label); //<! Set context name to this label
+ const DNSName& getLabel() { return d_label; } //<! Return context name
+
+ bool init(const std::string &input, std::string& output); //<! Perform GSS Initiate Security Context handshake
+ bool accept(const std::string &input, std::string& output); //<! Perform GSS Acccept Security Context handshake
+ bool destroy(); //<! Release the cached context
+ bool expired(); //<! Check if context is expired
+ bool valid(); //<! Check if context is valid
+
+ bool sign(const std::string &input, std::string& output); //<! Sign something using gss
+ bool verify(const std::string &input, const std::string &signature); //<! Validate gss signature with something
+
+ GssContextError getError(); //<! Get error
+ const std::vector<std::string> getErrorStrings() { return d_gss_errors; } //<! Get native error texts
+ private:
+ void release(); //<! Release context
+ void initialize(); //<! Initialize context
+#ifdef ENABLE_GSS_TSIG
+ void processError(const string& method, OM_uint32 maj, OM_uint32 min); //<! Process and fill error text vector
+#endif
+ DNSName d_label; //<! Context name
+ std::string d_peerPrincipal; //<! Remote name
+ std::string d_localPrincipal; //<! Our name
+ GssContextError d_error; //<! Context error
+ GssContextType d_type; //<! Context type
+ std::vector<std::string> d_gss_errors; //<! Native error string(s)
+ boost::shared_ptr<GssSecContext> d_ctx; //<! Attached security context
+};
+
+bool gss_add_signature(const DNSName& context, const std::string& message, std::string& mac); //<! Create signature
+bool gss_verify_signature(const DNSName& context, const std::string& message, const std::string& mac); //<! Validate signature
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <vector>
+#include <deque>
+#include <iostream>
+
+#include <boost/multi_index_container.hpp>
+#include <boost/format.hpp>
+#include <sys/time.h>
+#include <time.h>
+#include "iputils.hh"
+#include "statbag.hh"
+#include <sys/socket.h>
+
+#include "namespaces.hh"
+using namespace boost::multi_index;
+
+struct TimeTag{};
+
+template<typename Container, typename SenderReceiver> class Inflighter
+{
+public:
+ Inflighter(Container& c, SenderReceiver& sr) : d_container(c), d_sr(sr), d_init(false)
+ {
+ d_burst = 2;
+ d_maxInFlight = 5;
+ d_timeoutSeconds = 3;
+ d_unexpectedResponse = d_timeouts = 0;
+ }
+ void init()
+ {
+ d_iter = d_container.begin();
+ d_init=true;
+ }
+
+ bool run(); //!< keep calling this as long as it returns 1, or if it throws an exception
+
+ unsigned int d_maxInFlight;
+ unsigned int d_timeoutSeconds;
+ int d_burst;
+
+ uint64_t getTimeouts()
+ {
+ return d_timeouts;
+ }
+
+ uint64_t getUnexpecteds()
+ {
+ return d_unexpectedResponse;
+ }
+
+private:
+ struct TTDItem
+ {
+ typename Container::iterator iter;
+ typename SenderReceiver::Identifier id;
+ struct timeval sentTime, ttd;
+ };
+
+ typedef multi_index_container<
+ TTDItem,
+ indexed_by<
+ ordered_unique<
+ member<TTDItem, typename SenderReceiver::Identifier, &TTDItem::id>
+ >,
+ ordered_non_unique<
+ tag<TimeTag>,
+ member<TTDItem, struct timeval, &TTDItem::ttd>
+ >
+ >
+ >ttdwatch_t;
+
+ Container& d_container;
+ SenderReceiver& d_sr;
+
+ ttdwatch_t d_ttdWatch;
+ typename Container::iterator d_iter;
+ bool d_init;
+
+ uint64_t d_unexpectedResponse, d_timeouts;
+};
+
+template<typename Container, typename SendReceive> bool Inflighter<Container, SendReceive>::run()
+{
+ if(!d_init)
+ init();
+
+ for(;;) {
+ int burst = 0;
+
+ // 'send' as many items as allowed, limited by 'max in flight' and our burst parameter (which limits query rate growth)
+ while(d_iter != d_container.end() && d_ttdWatch.size() < d_maxInFlight) {
+ TTDItem ttdi;
+ ttdi.iter = d_iter++;
+ ttdi.id = d_sr.send(*ttdi.iter);
+ gettimeofday(&ttdi.sentTime, 0);
+ ttdi.ttd = ttdi.sentTime;
+ ttdi.ttd.tv_sec += d_timeoutSeconds;
+ if(d_ttdWatch.count(ttdi.id)) {
+// cerr<<"DUPLICATE INSERT!"<<endl;
+ }
+ d_ttdWatch.insert(ttdi);
+
+ if(++burst == d_burst)
+ break;
+ }
+ int processed=0;
+
+
+ // if there are queries in flight, handle responses
+ if(!d_ttdWatch.empty()) {
+ // cerr<<"Have "<< d_ttdWatch.size() <<" queries in flight"<<endl;
+ typename SendReceive::Answer answer;
+ typename SendReceive::Identifier id;
+
+ // get as many answers as available - 'receive' should block for a short while to wait for an answer
+ while(d_sr.receive(id, answer)) {
+ typename ttdwatch_t::iterator ival = d_ttdWatch.find(id); // match up what we received to what we were waiting for
+
+ if(ival != d_ttdWatch.end()) { // found something!
+ ++processed;
+ struct timeval now;
+ gettimeofday(&now, 0);
+ unsigned int usec = 1000000*(now.tv_sec - ival->sentTime.tv_sec) + (now.tv_usec - ival->sentTime.tv_usec);
+ d_sr.deliverAnswer(*ival->iter, answer, usec); // deliver to sender/receiver
+ d_ttdWatch.erase(ival);
+ break; // we can send new questions!
+ }
+ else {
+ // cerr<<"UNEXPECTED ANSWER: "<<id<<endl;
+ d_unexpectedResponse++;
+ }
+ }
+
+
+ if(!processed /* || d_ttdWatch.size() > 10000 */ ) { // no new responses, time for some cleanup of the ttdWatch
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ typedef typename ttdwatch_t::template index<TimeTag>::type waiters_by_ttd_index_t;
+ waiters_by_ttd_index_t& waiters_index = boost::multi_index::get<TimeTag>(d_ttdWatch);
+
+ // this provides a list of items sorted by age
+ for(typename waiters_by_ttd_index_t::iterator valiter = waiters_index.begin(); valiter != waiters_index.end(); ) {
+ if(valiter->ttd.tv_sec < now.tv_sec || (valiter->ttd.tv_sec == now.tv_sec && valiter->ttd.tv_usec < now.tv_usec)) {
+ d_sr.deliverTimeout(valiter->id); // so backend can release id
+ waiters_index.erase(valiter++);
+ // cerr<<"Have timeout for id="<< valiter->id <<endl;
+ d_timeouts++;
+ }
+ else
+ break; // if this one was too new, rest will be too
+ }
+ }
+ }
+ if(d_ttdWatch.empty() && d_iter == d_container.end())
+ break;
+ }
+ return false;
+}
+
+#if 0
+StatBag S;
+
+struct SendReceive
+{
+ typedef int Identifier;
+ typedef int Answer;
+ ComboAddress d_remote;
+ int d_socket;
+ int d_id;
+
+ SendReceive()
+ {
+ d_id = 0;
+ d_socket = socket(AF_INET, SOCK_DGRAM, 0);
+ int val=1;
+ setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, &val, sizeof(val));
+
+ ComboAddress local("0.0.0.0", 1024);
+ bind(d_socket, (struct sockaddr*)&local, local.getSocklen());
+
+ char buf[512];
+
+ socklen_t remotelen=sizeof(d_remote);
+ cerr<<"Waiting for 'hi' on "<<local.toStringWithPort()<<endl;
+ int len = recvfrom(d_socket, buf, sizeof(buf), 0, (struct sockaddr*)&d_remote, &remotelen);
+ cerr<<d_remote.toStringWithPort()<<" sent 'hi': "<<string(buf, len);
+ Utility::setNonBlocking(d_socket);
+ connect(d_socket, (struct sockaddr*) &d_remote, d_remote.getSocklen());
+ }
+
+ ~SendReceive()
+ {
+ ::send(d_socket, "done\r\n", 6, 0);
+ }
+
+ Identifier send(int& i)
+ {
+ cerr<<"Sending a '"<<i<<"'"<<endl;
+ string msg = (boost::format("%d %d\n") % d_id % i).str();
+ ::send(d_socket, msg.c_str(), msg.length(), 0);
+ return d_id++;
+ }
+
+ bool receive(Identifier& id, int& i)
+ {
+ if(waitForData(d_socket, 0, 500000) > 0) {
+ char buf[512];
+
+ int len = recv(d_socket, buf, sizeof(buf), 0);
+ string msg(buf, len);
+ if(sscanf(msg.c_str(), "%d %d", &id, &i) != 2) {
+ throw runtime_error("Invalid input");
+ }
+ return 1;
+ }
+ return 0;
+ }
+
+ void deliverAnswer(int& i, int j)
+ {
+ cerr<<"We sent "<<i<<", got back: "<<j<<endl;
+ }
+};
+
+
+int main()
+{
+ vector<int> numbers;
+ SendReceive sr;
+ Inflighter<vector<int>, SendReceive> inflighter(numbers, sr);
+
+ for(int n=0; n < 100; ++n)
+ numbers.push_back(n*n);
+
+
+ for(;;) {
+ try {
+ inflighter.run();
+ break;
+ }
+ catch(exception& e) {
+ cerr<<"Caught exception: "<<e.what()<<endl;
+ }
+ }
+
+}
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "iputils.hh"
+#include <sys/socket.h>
+
+/** these functions provide a very lightweight wrapper to the Berkeley sockets API. Errors -> exceptions! */
+
+static void RuntimeError(const boost::format& fmt)
+{
+ throw runtime_error(fmt.str());
+}
+
+
+int SSocket(int family, int type, int flags)
+{
+ int ret = socket(family, type, flags);
+ if(ret < 0)
+ RuntimeError(boost::format("creating socket of type %d: %s") % family % strerror(errno));
+ return ret;
+}
+
+int SConnect(int sockfd, const ComboAddress& remote)
+{
+ int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen());
+ if(ret < 0) {
+ int savederrno = errno;
+ RuntimeError(boost::format("connecting socket to %s: %s") % remote.toStringWithPort() % strerror(savederrno));
+ }
+ return ret;
+}
+
+int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout)
+{
+ int ret = connect(sockfd, (struct sockaddr*)&remote, remote.getSocklen());
+ if(ret < 0) {
+ int savederrno = errno;
+ if (savederrno == EINPROGRESS) {
+ /* we wait until the connection has been established */
+ bool error = false;
+ bool disconnected = false;
+ int res = waitForRWData(sockfd, false, timeout, 0, &error, &disconnected);
+ if (res == 1) {
+ if (error) {
+ savederrno = 0;
+ socklen_t errlen = sizeof(savederrno);
+ if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, (void *)&savederrno, &errlen) == 0) {
+ RuntimeError(boost::format("connecting to %s failed: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+ }
+ else {
+ RuntimeError(boost::format("connecting to %s failed") % remote.toStringWithPort());
+ }
+ }
+ if (disconnected) {
+ RuntimeError(boost::format("%s closed the connection") % remote.toStringWithPort());
+ }
+ return 0;
+ }
+ else if (res == 0) {
+ RuntimeError(boost::format("timeout while connecting to %s") % remote.toStringWithPort());
+ } else if (res < 0) {
+ savederrno = errno;
+ RuntimeError(boost::format("waiting to connect to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+ }
+ }
+ else {
+ RuntimeError(boost::format("connecting to %s: %s") % remote.toStringWithPort() % string(strerror(savederrno)));
+ }
+ }
+
+ return ret;
+}
+
+int SBind(int sockfd, const ComboAddress& local)
+{
+ int ret = bind(sockfd, (struct sockaddr*)&local, local.getSocklen());
+ if(ret < 0) {
+ int savederrno = errno;
+ RuntimeError(boost::format("binding socket to %s: %s") % local.toStringWithPort() % strerror(savederrno));
+ }
+ return ret;
+}
+
+int SAccept(int sockfd, ComboAddress& remote)
+{
+ socklen_t remlen = remote.getSocklen();
+
+ int ret = accept(sockfd, (struct sockaddr*)&remote, &remlen);
+ if(ret < 0)
+ RuntimeError(boost::format("accepting new connection on socket: %s") % strerror(errno));
+ return ret;
+}
+
+int SListen(int sockfd, int limit)
+{
+ int ret = listen(sockfd, limit);
+ if(ret < 0)
+ RuntimeError(boost::format("setting socket to listen: %s") % strerror(errno));
+ return ret;
+}
+
+int SSetsockopt(int sockfd, int level, int opname, int value)
+{
+ int ret = setsockopt(sockfd, level, opname, &value, sizeof(value));
+ if(ret < 0)
+ RuntimeError(boost::format("setsockopt for level %d and opname %d to %d failed: %s") % level % opname % value % strerror(errno));
+ return ret;
+}
+
+
+bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv)
+{
+#ifdef SO_TIMESTAMP
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh,cmsg)) {
+ if ((cmsg->cmsg_level == SOL_SOCKET) && (cmsg->cmsg_type == SO_TIMESTAMP || cmsg->cmsg_type == SCM_TIMESTAMP) &&
+ CMSG_LEN(sizeof(*tv)) == cmsg->cmsg_len) {
+ memcpy(tv, CMSG_DATA(cmsg), sizeof(*tv));
+ return true;
+ }
+ }
+#endif
+ return false;
+}
+bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination)
+{
+ memset(destination, 0, sizeof(*destination));
+ struct cmsghdr *cmsg;
+ for (cmsg = CMSG_FIRSTHDR(msgh); cmsg != NULL; cmsg = CMSG_NXTHDR(msgh,cmsg)) {
+#if defined(IP_PKTINFO)
+ if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_PKTINFO)) {
+ struct in_pktinfo *i = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ destination->sin4.sin_addr = i->ipi_addr;
+ destination->sin4.sin_family = AF_INET;
+ return true;
+ }
+#elif defined(IP_RECVDSTADDR)
+ if ((cmsg->cmsg_level == IPPROTO_IP) && (cmsg->cmsg_type == IP_RECVDSTADDR)) {
+ struct in_addr *i = (struct in_addr *) CMSG_DATA(cmsg);
+ destination->sin4.sin_addr = *i;
+ destination->sin4.sin_family = AF_INET;
+ return true;
+ }
+#endif
+
+ if ((cmsg->cmsg_level == IPPROTO_IPV6) && (cmsg->cmsg_type == IPV6_PKTINFO)) {
+ struct in6_pktinfo *i = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+ destination->sin6.sin6_addr = i->ipi6_addr;
+ destination->sin4.sin_family = AF_INET6;
+ return true;
+ }
+ }
+ return false;
+}
+
+bool IsAnyAddress(const ComboAddress& addr)
+{
+ if(addr.sin4.sin_family == AF_INET)
+ return addr.sin4.sin_addr.s_addr == 0;
+ else if(addr.sin4.sin_family == AF_INET6)
+ return !memcmp(&addr.sin6.sin6_addr, &in6addr_any, sizeof(addr.sin6.sin6_addr));
+
+ return false;
+}
+
+ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to)
+{
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+
+ /* Set up iov and msgh structures. */
+ memset(&msgh, 0, sizeof(struct msghdr));
+ iov.iov_base = (void*)data;
+ iov.iov_len = len;
+ msgh.msg_iov = &iov;
+ msgh.msg_iovlen = 1;
+ msgh.msg_name = (struct sockaddr*)&to;
+ msgh.msg_namelen = to.getSocklen();
+
+ if(from.sin4.sin_family) {
+ addCMsgSrcAddr(&msgh, cbuf, &from, 0);
+ }
+ else {
+ msgh.msg_control=NULL;
+ }
+ return sendmsg(sock, &msgh, flags);
+}
+
+// be careful: when using this for receive purposes, make sure addr->sin4.sin_family is set appropriately so getSocklen works!
+// be careful: when using this function for *send* purposes, be sure to set cbufsize to 0!
+// be careful: if you don't call addCMsgSrcAddr after fillMSGHdr, make sure to set msg_control to NULL
+void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr)
+{
+ iov->iov_base = data;
+ iov->iov_len = datalen;
+
+ memset(msgh, 0, sizeof(struct msghdr));
+
+ msgh->msg_control = cbuf;
+ msgh->msg_controllen = cbufsize;
+ msgh->msg_name = addr;
+ msgh->msg_namelen = addr->getSocklen();
+ msgh->msg_iov = iov;
+ msgh->msg_iovlen = 1;
+ msgh->msg_flags = 0;
+}
+
+void ComboAddress::truncate(unsigned int bits)
+{
+ uint8_t* start;
+ int len=4;
+ if(sin4.sin_family==AF_INET) {
+ if(bits >= 32)
+ return;
+ start = (uint8_t*)&sin4.sin_addr.s_addr;
+ len=4;
+ }
+ else {
+ if(bits >= 128)
+ return;
+ start = (uint8_t*)&sin6.sin6_addr.s6_addr;
+ len=16;
+ }
+
+ auto tozero= len*8 - bits; // if set to 22, this will clear 1 byte, as it should
+
+ memset(start + len - tozero/8, 0, tozero/8); // blot out the whole bytes on the right
+
+ auto bitsleft=tozero % 8; // 2 bits left to clear
+
+ // a b c d, to truncate to 22 bits, we just zeroed 'd' and need to zero 2 bits from c
+ // so and by '11111100', which is ~((1<<2)-1) = ~3
+ uint8_t* place = start + len - 1 - tozero/8;
+ *place &= (~((1<<bitsleft)-1));
+}
+
+ssize_t sendMsgWithTimeout(int fd, const char* buffer, size_t len, int timeout, ComboAddress& dest, const ComboAddress& local, unsigned int localItf)
+{
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+ bool firstTry = true;
+ fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), const_cast<char*>(buffer), len, &dest);
+ addCMsgSrcAddr(&msgh, cbuf, &local, localItf);
+
+ do {
+ ssize_t written = sendmsg(fd, &msgh, 0);
+
+ if (written > 0)
+ return written;
+
+ if (errno == EAGAIN) {
+ if (firstTry) {
+ int res = waitForRWData(fd, false, timeout, 0);
+ if (res > 0) {
+ /* there is room available */
+ firstTry = false;
+ }
+ else if (res == 0) {
+ throw runtime_error("Timeout while waiting to write data");
+ } else {
+ throw runtime_error("Error while waiting for room to write data");
+ }
+ }
+ else {
+ throw runtime_error("Timeout while waiting to write data");
+ }
+ }
+ else {
+ unixDie("failed in write2WithTimeout");
+ }
+ }
+ while (firstTry);
+
+ return 0;
+}
+
+template class NetmaskTree<bool>;
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_IPUTILSHH
+#define PDNS_IPUTILSHH
+
+#include <string>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <iostream>
+#include <stdio.h>
+#include <functional>
+#include <bitset>
+#include "pdnsexception.hh"
+#include "misc.hh"
+#include <sys/socket.h>
+#include <netdb.h>
+#include <sstream>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+
+#include "namespaces.hh"
+
+#ifdef __APPLE__
+#include <libkern/OSByteOrder.h>
+
+#define htobe16(x) OSSwapHostToBigInt16(x)
+#define htole16(x) OSSwapHostToLittleInt16(x)
+#define be16toh(x) OSSwapBigToHostInt16(x)
+#define le16toh(x) OSSwapLittleToHostInt16(x)
+
+#define htobe32(x) OSSwapHostToBigInt32(x)
+#define htole32(x) OSSwapHostToLittleInt32(x)
+#define be32toh(x) OSSwapBigToHostInt32(x)
+#define le32toh(x) OSSwapLittleToHostInt32(x)
+
+#define htobe64(x) OSSwapHostToBigInt64(x)
+#define htole64(x) OSSwapHostToLittleInt64(x)
+#define be64toh(x) OSSwapBigToHostInt64(x)
+#define le64toh(x) OSSwapLittleToHostInt64(x)
+#endif
+
+// for illumos
+#ifdef BE_64
+
+#define htobe16(x) BE_16(x)
+#define htole16(x) LE_16(x)
+#define be16toh(x) BE_IN16(x)
+#define le16toh(x) LE_IN16(x)
+
+#define htobe32(x) BE_32(x)
+#define htole32(x) LE_32(x)
+#define be32toh(x) BE_IN32(x)
+#define le32toh(x) LE_IN32(x)
+
+#define htobe64(x) BE_64(x)
+#define htole64(x) LE_64(x)
+#define be64toh(x) BE_IN64(x)
+#define le64toh(x) LE_IN64(x)
+
+#endif
+
+#ifdef __FreeBSD__
+#include <sys/endian.h>
+#endif
+
+union ComboAddress {
+ struct sockaddr_in sin4;
+ struct sockaddr_in6 sin6;
+
+ bool operator==(const ComboAddress& rhs) const
+ {
+ if(boost::tie(sin4.sin_family, sin4.sin_port) != boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
+ return false;
+ if(sin4.sin_family == AF_INET)
+ return sin4.sin_addr.s_addr == rhs.sin4.sin_addr.s_addr;
+ else
+ return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr))==0;
+ }
+
+ bool operator!=(const ComboAddress& rhs) const
+ {
+ return(!operator==(rhs));
+ }
+
+ bool operator<(const ComboAddress& rhs) const
+ {
+ if(sin4.sin_family == 0) {
+ return false;
+ }
+ if(boost::tie(sin4.sin_family, sin4.sin_port) < boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
+ return true;
+ if(boost::tie(sin4.sin_family, sin4.sin_port) > boost::tie(rhs.sin4.sin_family, rhs.sin4.sin_port))
+ return false;
+
+ if(sin4.sin_family == AF_INET)
+ return sin4.sin_addr.s_addr < rhs.sin4.sin_addr.s_addr;
+ else
+ return memcmp(&sin6.sin6_addr.s6_addr, &rhs.sin6.sin6_addr.s6_addr, sizeof(sin6.sin6_addr.s6_addr)) < 0;
+ }
+
+ bool operator>(const ComboAddress& rhs) const
+ {
+ return rhs.operator<(*this);
+ }
+
+ struct addressOnlyHash
+ {
+ uint32_t operator()(const ComboAddress& ca) const
+ {
+ const unsigned char* start;
+ int len;
+ if(ca.sin4.sin_family == AF_INET) {
+ start =(const unsigned char*)&ca.sin4.sin_addr.s_addr;
+ len=4;
+ }
+ else {
+ start =(const unsigned char*)&ca.sin6.sin6_addr.s6_addr;
+ len=16;
+ }
+ return burtle(start, len, 0);
+ }
+ };
+
+ struct addressOnlyLessThan: public std::binary_function<ComboAddress, ComboAddress, bool>
+ {
+ bool operator()(const ComboAddress& a, const ComboAddress& b) const
+ {
+ if(a.sin4.sin_family < b.sin4.sin_family)
+ return true;
+ if(a.sin4.sin_family > b.sin4.sin_family)
+ return false;
+ if(a.sin4.sin_family == AF_INET)
+ return a.sin4.sin_addr.s_addr < b.sin4.sin_addr.s_addr;
+ else
+ return memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr)) < 0;
+ }
+ };
+
+ struct addressOnlyEqual: public std::binary_function<ComboAddress, ComboAddress, bool>
+ {
+ bool operator()(const ComboAddress& a, const ComboAddress& b) const
+ {
+ if(a.sin4.sin_family != b.sin4.sin_family)
+ return false;
+ if(a.sin4.sin_family == AF_INET)
+ return a.sin4.sin_addr.s_addr == b.sin4.sin_addr.s_addr;
+ else
+ return !memcmp(&a.sin6.sin6_addr.s6_addr, &b.sin6.sin6_addr.s6_addr, sizeof(a.sin6.sin6_addr.s6_addr));
+ }
+ };
+
+
+ socklen_t getSocklen() const
+ {
+ if(sin4.sin_family == AF_INET)
+ return sizeof(sin4);
+ else
+ return sizeof(sin6);
+ }
+
+ ComboAddress()
+ {
+ sin4.sin_family=AF_INET;
+ sin4.sin_addr.s_addr=0;
+ sin4.sin_port=0;
+ }
+
+ ComboAddress(const struct sockaddr *sa, socklen_t salen) {
+ setSockaddr(sa, salen);
+ };
+
+ ComboAddress(const struct sockaddr_in6 *sa) {
+ setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in6));
+ };
+
+ ComboAddress(const struct sockaddr_in *sa) {
+ setSockaddr((const struct sockaddr*)sa, sizeof(struct sockaddr_in));
+ };
+
+ void setSockaddr(const struct sockaddr *sa, socklen_t salen) {
+ if (salen > sizeof(struct sockaddr_in6)) throw PDNSException("ComboAddress can't handle other than sockaddr_in or sockaddr_in6");
+ memcpy(this, sa, salen);
+ }
+
+ // 'port' sets a default value in case 'str' does not set a port
+ explicit ComboAddress(const string& str, uint16_t port=0)
+ {
+ memset(&sin6, 0, sizeof(sin6));
+ sin4.sin_family = AF_INET;
+ sin4.sin_port = 0;
+ if(makeIPv4sockaddr(str, &sin4)) {
+ sin6.sin6_family = AF_INET6;
+ if(makeIPv6sockaddr(str, &sin6) < 0)
+ throw PDNSException("Unable to convert presentation address '"+ str +"'");
+
+ }
+ if(!sin4.sin_port) // 'str' overrides port!
+ sin4.sin_port=htons(port);
+ }
+
+ bool isIPv6() const
+ {
+ return sin4.sin_family == AF_INET6;
+ }
+ bool isIPv4() const
+ {
+ return sin4.sin_family == AF_INET;
+ }
+
+ bool isMappedIPv4() const
+ {
+ if(sin4.sin_family!=AF_INET6)
+ return false;
+
+ int n=0;
+ const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
+ for(n=0; n < 10; ++n)
+ if(ptr[n])
+ return false;
+
+ for(; n < 12; ++n)
+ if(ptr[n]!=0xff)
+ return false;
+
+ return true;
+ }
+
+ ComboAddress mapToIPv4() const
+ {
+ if(!isMappedIPv4())
+ throw PDNSException("ComboAddress can't map non-mapped IPv6 address back to IPv4");
+ ComboAddress ret;
+ ret.sin4.sin_family=AF_INET;
+ ret.sin4.sin_port=sin4.sin_port;
+
+ const unsigned char*ptr = (unsigned char*) &sin6.sin6_addr.s6_addr;
+ ptr+=(sizeof(sin6.sin6_addr.s6_addr) - sizeof(ret.sin4.sin_addr.s_addr));
+ memcpy(&ret.sin4.sin_addr.s_addr, ptr, sizeof(ret.sin4.sin_addr.s_addr));
+ return ret;
+ }
+
+ string toString() const
+ {
+ char host[1024];
+ if(sin4.sin_family && !getnameinfo((struct sockaddr*) this, getSocklen(), host, sizeof(host),0, 0, NI_NUMERICHOST))
+ return host;
+ else
+ return "invalid";
+ }
+
+ string toStringWithPort() const
+ {
+ if(sin4.sin_family==AF_INET)
+ return toString() + ":" + std::to_string(ntohs(sin4.sin_port));
+ else
+ return "["+toString() + "]:" + std::to_string(ntohs(sin4.sin_port));
+ }
+
+ void truncate(unsigned int bits);
+};
+
+/** This exception is thrown by the Netmask class and by extension by the NetmaskGroup class */
+class NetmaskException: public PDNSException
+{
+public:
+ NetmaskException(const string &a) : PDNSException(a) {}
+};
+
+inline ComboAddress makeComboAddress(const string& str)
+{
+ ComboAddress address;
+ address.sin4.sin_family=AF_INET;
+ if(inet_pton(AF_INET, str.c_str(), &address.sin4.sin_addr) <= 0) {
+ address.sin4.sin_family=AF_INET6;
+ if(makeIPv6sockaddr(str, &address.sin6) < 0)
+ throw NetmaskException("Unable to convert '"+str+"' to a netmask");
+ }
+ return address;
+}
+
+/** This class represents a netmask and can be queried to see if a certain
+ IP address is matched by this mask */
+class Netmask
+{
+public:
+ Netmask()
+ {
+ d_network.sin4.sin_family=0; // disable this doing anything useful
+ d_network.sin4.sin_port = 0; // this guarantees d_network compares identical
+ d_mask=0;
+ d_bits=0;
+ }
+
+ Netmask(const ComboAddress& network, uint8_t bits=0xff)
+ {
+ d_network = network;
+
+ if(bits > 128)
+ bits = (network.sin4.sin_family == AF_INET) ? 32 : 128;
+
+ d_bits = bits;
+ if(d_bits<32)
+ d_mask=~(0xFFFFFFFF>>d_bits);
+ else
+ d_mask=0xFFFFFFFF; // not actually used for IPv6
+ }
+
+ //! Constructor supplies the mask, which cannot be changed
+ Netmask(const string &mask)
+ {
+ pair<string,string> split=splitField(mask,'/');
+ d_network=makeComboAddress(split.first);
+
+ if(!split.second.empty()) {
+ d_bits = (uint8_t)pdns_stou(split.second);
+ if(d_bits<32)
+ d_mask=~(0xFFFFFFFF>>d_bits);
+ else
+ d_mask=0xFFFFFFFF;
+ }
+ else if(d_network.sin4.sin_family==AF_INET) {
+ d_bits = 32;
+ d_mask = 0xFFFFFFFF;
+ }
+ else {
+ d_bits=128;
+ d_mask=0; // silence silly warning - d_mask is unused for IPv6
+ }
+ }
+
+ bool match(const ComboAddress& ip) const
+ {
+ return match(&ip);
+ }
+
+ //! If this IP address in socket address matches
+ bool match(const ComboAddress *ip) const
+ {
+ if(d_network.sin4.sin_family != ip->sin4.sin_family) {
+ return false;
+ }
+ if(d_network.sin4.sin_family == AF_INET) {
+ return match4(htonl((unsigned int)ip->sin4.sin_addr.s_addr));
+ }
+ if(d_network.sin6.sin6_family == AF_INET6) {
+ uint8_t bytes=d_bits/8, n;
+ const uint8_t *us=(const uint8_t*) &d_network.sin6.sin6_addr.s6_addr;
+ const uint8_t *them=(const uint8_t*) &ip->sin6.sin6_addr.s6_addr;
+
+ for(n=0; n < bytes; ++n) {
+ if(us[n]!=them[n]) {
+ return false;
+ }
+ }
+ // still here, now match remaining bits
+ uint8_t bits= d_bits % 8;
+ uint8_t mask= (uint8_t) ~(0xFF>>bits);
+
+ return((us[n] & mask) == (them[n] & mask));
+ }
+ return false;
+ }
+
+ //! If this ASCII IP address matches
+ bool match(const string &ip) const
+ {
+ ComboAddress address=makeComboAddress(ip);
+ return match(&address);
+ }
+
+ //! If this IP address in native format matches
+ bool match4(uint32_t ip) const
+ {
+ return (ip & d_mask) == (ntohl(d_network.sin4.sin_addr.s_addr) & d_mask);
+ }
+
+ string toString() const
+ {
+ return d_network.toString()+"/"+std::to_string((unsigned int)d_bits);
+ }
+
+ string toStringNoMask() const
+ {
+ return d_network.toString();
+ }
+ const ComboAddress& getNetwork() const
+ {
+ return d_network;
+ }
+ const ComboAddress getMaskedNetwork() const
+ {
+ ComboAddress result(d_network);
+ if(isIpv4()) {
+ result.sin4.sin_addr.s_addr = htonl(ntohl(result.sin4.sin_addr.s_addr) & d_mask);
+ }
+ else if(isIpv6()) {
+ size_t idx;
+ uint8_t bytes=d_bits/8;
+ uint8_t *us=(uint8_t*) &result.sin6.sin6_addr.s6_addr;
+ uint8_t bits= d_bits % 8;
+ uint8_t mask= (uint8_t) ~(0xFF>>bits);
+
+ if (bytes < sizeof(result.sin6.sin6_addr.s6_addr)) {
+ us[bytes] &= mask;
+ }
+
+ for(idx = bytes + 1; idx < sizeof(result.sin6.sin6_addr.s6_addr); ++idx) {
+ us[idx] = 0;
+ }
+ }
+ return result;
+ }
+ int getBits() const
+ {
+ return d_bits;
+ }
+ bool isIpv6() const
+ {
+ return d_network.sin6.sin6_family == AF_INET6;
+ }
+ bool isIpv4() const
+ {
+ return d_network.sin4.sin_family == AF_INET;
+ }
+
+ bool operator<(const Netmask& rhs) const
+ {
+ return tie(d_network, d_bits) < tie(rhs.d_network, rhs.d_bits);
+ }
+
+ bool operator==(const Netmask& rhs) const
+ {
+ return tie(d_network, d_bits) == tie(rhs.d_network, rhs.d_bits);
+ }
+
+ bool empty() const
+ {
+ return d_network.sin4.sin_family==0;
+ }
+
+private:
+ ComboAddress d_network;
+ uint32_t d_mask;
+ uint8_t d_bits;
+};
+
+/** Per-bit binary tree map implementation with <Netmask,T> pair.
+ *
+ * This is an binary tree implementation for storing attributes for IPv4 and IPv6 prefixes.
+ * The most simple use case is simple NetmaskTree<bool> used by NetmaskGroup, which only
+ * wants to know if given IP address is matched in the prefixes stored.
+ *
+ * This element is useful for anything that needs to *STORE* prefixes, and *MATCH* IP addresses
+ * to a *LIST* of *PREFIXES*. Not the other way round.
+ *
+ * You can store IPv4 and IPv6 addresses to same tree, separate payload storage is kept per AFI.
+ *
+ * To erase something copy values to new tree sans the value you want to erase.
+ *
+ * Use swap if you need to move the tree to another NetmaskTree instance, it is WAY faster
+ * than using copy ctor or assigment operator, since it moves the nodes and tree root to
+ * new home instead of actually recreating the tree.
+ *
+ * Please see NetmaskGroup for example of simple use case. Other usecases can be found
+ * from GeoIPBackend and Sortlist, and from dnsdist.
+ */
+template <typename T>
+class NetmaskTree {
+public:
+ typedef Netmask key_type;
+ typedef T value_type;
+ typedef std::pair<key_type,value_type> node_type;
+ typedef size_t size_type;
+
+private:
+ /** Single node in tree, internal use only.
+ */
+ class TreeNode : boost::noncopyable {
+ public:
+ explicit TreeNode(int bits) noexcept : parent(NULL),d_bits(bits) {
+ }
+
+ //<! Makes a left node with one more bit than parent
+ TreeNode* make_left() {
+ if (!left) {
+ left = unique_ptr<TreeNode>(new TreeNode(d_bits+1));
+ left->parent = this;
+ }
+ return left.get();
+ }
+
+ //<! Makes a right node with one more bit than parent
+ TreeNode* make_right() {
+ if (!right) {
+ right = unique_ptr<TreeNode>(new TreeNode(d_bits+1));
+ right->parent = this;
+ }
+ return right.get();
+ }
+
+ unique_ptr<TreeNode> left;
+ unique_ptr<TreeNode> right;
+ TreeNode* parent;
+
+ unique_ptr<node_type> node4; //<! IPv4 value-pair
+ unique_ptr<node_type> node6; //<! IPv6 value-pair
+
+ int d_bits; //<! How many bits have been used so far
+ };
+
+public:
+ NetmaskTree() noexcept {
+ }
+
+ NetmaskTree(const NetmaskTree& rhs) {
+ // it is easier to copy the nodes than tree.
+ // also acts as handy compactor
+ for(auto const& node: rhs._nodes)
+ insert(node->first).second = node->second;
+ }
+
+ NetmaskTree& operator=(const NetmaskTree& rhs) {
+ clear();
+ // see above.
+ for(auto const& node: rhs._nodes)
+ insert(node->first).second = node->second;
+ return *this;
+ }
+
+ const typename std::vector<node_type*>::const_iterator begin() const { return _nodes.begin(); }
+ const typename std::vector<node_type*>::const_iterator end() const { return _nodes.end(); }
+
+ typename std::vector<node_type*>::iterator begin() { return _nodes.begin(); }
+ typename std::vector<node_type*>::iterator end() { return _nodes.end(); }
+
+ node_type& insert(const string &mask) {
+ return insert(key_type(mask));
+ }
+
+ //<! Creates new value-pair in tree and returns it.
+ node_type& insert(const key_type& key) {
+ // lazily initialize tree on first insert.
+ if (!root) root = unique_ptr<TreeNode>(new TreeNode(0));
+ TreeNode* node = root.get();
+ node_type* value = nullptr;
+
+ if (key.getNetwork().sin4.sin_family == AF_INET) {
+ std::bitset<32> addr(be32toh(key.getNetwork().sin4.sin_addr.s_addr));
+ int bits = 0;
+ // we turn left on 0 and right on 1
+ while(bits < key.getBits()) {
+ uint8_t val = addr[31-bits];
+ if (val)
+ node = node->make_right();
+ else
+ node = node->make_left();
+ bits++;
+ }
+ // only create node if not yet assigned
+ if (!node->node4) {
+ node->node4 = unique_ptr<node_type>(new node_type());
+ _nodes.push_back(node->node4.get());
+ }
+ value = node->node4.get();
+ } else {
+ uint64_t* addr = (uint64_t*)key.getNetwork().sin6.sin6_addr.s6_addr;
+ std::bitset<64> addr_low(be64toh(addr[1]));
+ std::bitset<64> addr_high(be64toh(addr[0]));
+ int bits = 0;
+ while(bits < key.getBits()) {
+ uint8_t val;
+ // we use high address until we are
+ if (bits < 64) val = addr_high[63-bits];
+ // past 64 bits, and start using low address
+ else val = addr_low[127-bits];
+
+ // we turn left on 0 and right on 1
+ if (val)
+ node = node->make_right();
+ else
+ node = node->make_left();
+ bits++;
+ }
+ // only create node if not yet assigned
+ if (!node->node6) {
+ node->node6 = unique_ptr<node_type>(new node_type());
+ _nodes.push_back(node->node6.get());
+ }
+ value = node->node6.get();
+ }
+ // assign key
+ value->first = key;
+ return *value;
+ }
+
+ //<! Creates or updates value
+ void insert_or_assign(const key_type& mask, const value_type& value) {
+ insert(mask).second = value;
+ }
+
+ void insert_or_assign(const string& mask, const value_type& value) {
+ insert(key_type(mask)).second = value;
+ }
+
+ //<! check if given key is present in TreeMap
+ bool has_key(const key_type& key) const {
+ const node_type *ptr = lookup(key);
+ return ptr && ptr->first == key;
+ }
+
+ //<! Returns "best match" for key_type, which might not be value
+ const node_type* lookup(const key_type& value) const {
+ return lookup(value.getNetwork(), value.getBits());
+ }
+
+ //<! Perform best match lookup for value, using at most max_bits
+ const node_type* lookup(const ComboAddress& value, int max_bits = 128) const {
+ if (!root) return nullptr;
+
+ TreeNode *node = root.get();
+ node_type *ret = nullptr;
+
+ // exact same thing as above, except
+ if (value.sin4.sin_family == AF_INET) {
+ max_bits = std::max(0,std::min(max_bits,32));
+ std::bitset<32> addr(be32toh(value.sin4.sin_addr.s_addr));
+ int bits = 0;
+
+ while(bits < max_bits) {
+ // ...we keep track of last non-empty node
+ if (node->node4) ret = node->node4.get();
+ uint8_t val = addr[31-bits];
+ // ...and we don't create left/right hand
+ if (val) {
+ if (node->right) node = node->right.get();
+ // ..and we break when road ends
+ else break;
+ } else {
+ if (node->left) node = node->left.get();
+ else break;
+ }
+ bits++;
+ }
+ // needed if we did not find one in loop
+ if (node->node4) ret = node->node4.get();
+ } else {
+ uint64_t* addr = (uint64_t*)value.sin6.sin6_addr.s6_addr;
+ max_bits = std::max(0,std::min(max_bits,128));
+ std::bitset<64> addr_low(be64toh(addr[1]));
+ std::bitset<64> addr_high(be64toh(addr[0]));
+ int bits = 0;
+ while(bits < max_bits) {
+ if (node->node6) ret = node->node6.get();
+ uint8_t val;
+ if (bits < 64) val = addr_high[63-bits];
+ else val = addr_low[127-bits];
+ if (val) {
+ if (node->right) node = node->right.get();
+ else break;
+ } else {
+ if (node->left) node = node->left.get();
+ else break;
+ }
+ bits++;
+ }
+ if (node->node6) ret = node->node6.get();
+ }
+
+ // this can be nullptr.
+ return ret;
+ }
+
+ //<! Removes key from TreeMap. This does not clean up the tree.
+ void erase(const key_type& key) {
+ TreeNode *node = root.get();
+
+ // no tree, no value
+ if ( node == nullptr ) return;
+
+ // exact same thing as above, except
+ if (key.getNetwork().sin4.sin_family == AF_INET) {
+ std::bitset<32> addr(be32toh(key.getNetwork().sin4.sin_addr.s_addr));
+ int bits = 0;
+ while(node && bits < key.getBits()) {
+ uint8_t val = addr[31-bits];
+ if (val) {
+ node = node->right.get();
+ } else {
+ node = node->left.get();
+ }
+ bits++;
+ }
+ if (node) {
+ for(auto it = _nodes.begin(); it != _nodes.end(); ) {
+ if (node->node4.get() == *it)
+ it = _nodes.erase(it);
+ else
+ it++;
+ }
+ node->node4.reset();
+ }
+ } else {
+ uint64_t* addr = (uint64_t*)key.getNetwork().sin6.sin6_addr.s6_addr;
+ std::bitset<64> addr_low(be64toh(addr[1]));
+ std::bitset<64> addr_high(be64toh(addr[0]));
+ int bits = 0;
+ while(node && bits < key.getBits()) {
+ uint8_t val;
+ if (bits < 64) val = addr_high[63-bits];
+ else val = addr_low[127-bits];
+ if (val) {
+ node = node->right.get();
+ } else {
+ node = node->left.get();
+ }
+ bits++;
+ }
+ if (node) {
+ for(auto it = _nodes.begin(); it != _nodes.end(); ) {
+ if (node->node6.get() == *it)
+ it = _nodes.erase(it);
+ else
+ it++;
+ }
+
+ node->node6.reset();
+ }
+ }
+ }
+
+ void erase(const string& key) {
+ erase(key_type(key));
+ }
+
+ //<! checks whether the container is empty.
+ bool empty() const {
+ return _nodes.empty();
+ }
+
+ //<! returns the number of elements
+ size_type size() const {
+ return _nodes.size();
+ }
+
+ //<! See if given ComboAddress matches any prefix
+ bool match(const ComboAddress& value) const {
+ return (lookup(value) != nullptr);
+ }
+
+ bool match(const std::string& value) const {
+ return match(ComboAddress(value));
+ }
+
+ //<! Clean out the tree
+ void clear() {
+ _nodes.clear();
+ root.reset(nullptr);
+ }
+
+ //<! swaps the contents, rhs is left with nullptr.
+ void swap(NetmaskTree& rhs) {
+ root.swap(rhs.root);
+ _nodes.swap(rhs._nodes);
+ }
+
+private:
+ unique_ptr<TreeNode> root; //<! Root of our tree
+ std::vector<node_type*> _nodes; //<! Container for actual values
+};
+
+/** This class represents a group of supplemental Netmask classes. An IP address matchs
+ if it is matched by zero or more of the Netmask classes within.
+*/
+class NetmaskGroup
+{
+public:
+ //! If this IP address is matched by any of the classes within
+
+ bool match(const ComboAddress *ip) const
+ {
+ return tree.match(*ip);
+ }
+
+ bool match(const ComboAddress& ip) const
+ {
+ return match(&ip);
+ }
+
+ //! Add this string to the list of possible matches
+ void addMask(const string &ip)
+ {
+ addMask(Netmask(ip));
+ }
+
+ //! Add this Netmask to the list of possible matches
+ void addMask(const Netmask& nm)
+ {
+ tree.insert(nm);
+ }
+
+ void clear()
+ {
+ tree.clear();
+ }
+
+ bool empty() const
+ {
+ return tree.empty();
+ }
+
+ size_t size() const
+ {
+ return tree.size();
+ }
+
+ string toString() const
+ {
+ ostringstream str;
+ for(auto iter = tree.begin(); iter != tree.end(); ++iter) {
+ if(iter != tree.begin())
+ str <<", ";
+ str<<(*iter)->first.toString();
+ }
+ return str.str();
+ }
+
+ void toStringVector(vector<string>* vec) const
+ {
+ for(auto iter = tree.begin(); iter != tree.end(); ++iter)
+ vec->push_back((*iter)->first.toString());
+ }
+
+ void toMasks(const string &ips)
+ {
+ vector<string> parts;
+ stringtok(parts, ips, ", \t");
+
+ for (vector<string>::const_iterator iter = parts.begin(); iter != parts.end(); ++iter)
+ addMask(*iter);
+ }
+
+private:
+ NetmaskTree<bool> tree;
+};
+
+
+struct SComboAddress
+{
+ SComboAddress(const ComboAddress& orig) : ca(orig) {}
+ ComboAddress ca;
+ bool operator<(const SComboAddress& rhs) const
+ {
+ return ComboAddress::addressOnlyLessThan()(ca, rhs.ca);
+ }
+ operator const ComboAddress&()
+ {
+ return ca;
+ }
+};
+
+
+int SSocket(int family, int type, int flags);
+int SConnect(int sockfd, const ComboAddress& remote);
+/* tries to connect to remote for a maximum of timeout seconds.
+ sockfd should be set to non-blocking beforehand.
+ returns 0 on success (the socket is writable), throw a
+ runtime_error otherwise */
+int SConnectWithTimeout(int sockfd, const ComboAddress& remote, int timeout);
+int SBind(int sockfd, const ComboAddress& local);
+int SAccept(int sockfd, ComboAddress& remote);
+int SListen(int sockfd, int limit);
+int SSetsockopt(int sockfd, int level, int opname, int value);
+
+#if defined(IP_PKTINFO)
+ #define GEN_IP_PKTINFO IP_PKTINFO
+#elif defined(IP_RECVDSTADDR)
+ #define GEN_IP_PKTINFO IP_RECVDSTADDR
+#endif
+bool IsAnyAddress(const ComboAddress& addr);
+bool HarvestDestinationAddress(struct msghdr* msgh, ComboAddress* destination);
+bool HarvestTimestamp(struct msghdr* msgh, struct timeval* tv);
+void fillMSGHdr(struct msghdr* msgh, struct iovec* iov, char* cbuf, size_t cbufsize, char* data, size_t datalen, ComboAddress* addr);
+ssize_t sendfromto(int sock, const char* data, size_t len, int flags, const ComboAddress& from, const ComboAddress& to);
+ssize_t sendMsgWithTimeout(int fd, const char* buffer, size_t len, int timeout, ComboAddress& dest, const ComboAddress& local, unsigned int localItf);
+
+#endif
+
+extern template class NetmaskTree<bool>;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "ixfr.hh"
+#include "sstuff.hh"
+#include "dns_random.hh"
+#include "dnsrecords.hh"
+#include "dnssecinfra.hh"
+#include "tsigverifier.hh"
+
+// Returns pairs of "remove & add" vectors. If you get an empty remove, it means you got an AXFR!
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone, const DNSRecord& oursr,
+ const TSIGTriplet& tt, const ComboAddress* laddr, size_t maxReceivedBytes)
+{
+ vector<pair<vector<DNSRecord>, vector<DNSRecord> > > ret;
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, zone, QType::IXFR);
+ pw.getHeader()->qr=0;
+ pw.getHeader()->rd=0;
+ pw.getHeader()->id=dns_random(0xffff);
+ pw.startRecord(zone, QType::SOA, 0, QClass::IN, DNSResourceRecord::AUTHORITY);
+ oursr.d_content->toPacket(pw);
+
+ pw.commit();
+ TSIGRecordContent trc;
+ TSIGTCPVerifier tsigVerifier(tt, master, trc);
+ if(!tt.algo.empty()) {
+ TSIGHashEnum the;
+ getTSIGHashEnum(tt.algo, the);
+ try {
+ trc.d_algoName = getTSIGAlgoName(the);
+ } catch(PDNSException& pe) {
+ throw std::runtime_error("TSIG algorithm '"+tt.algo.toString()+"' is unknown.");
+ }
+ trc.d_time = time((time_t*)NULL);
+ trc.d_fudge = 300;
+ trc.d_origID=ntohs(pw.getHeader()->id);
+ trc.d_eRcode=0;
+ addTSIG(pw, &trc, tt.name, tt.secret, "", false);
+ }
+ uint16_t len=htons(packet.size());
+ string msg((const char*)&len, 2);
+ msg.append((const char*)&packet[0], packet.size());
+
+ Socket s(master.sin4.sin_family, SOCK_STREAM);
+ // cout<<"going to connect"<<endl;
+ if(laddr)
+ s.bind(*laddr);
+ s.connect(master);
+ // cout<<"Connected"<<endl;
+ s.writen(msg);
+
+ // CURRENT MASTER SOA
+ // REPEAT:
+ // SOA WHERE THIS DELTA STARTS
+ // RECORDS TO REMOVE
+ // SOA WHERE THIS DELTA GOES
+ // RECORDS TO ADD
+ // CURRENT MASTER SOA
+ shared_ptr<SOARecordContent> masterSOA;
+ vector<DNSRecord> records;
+ size_t receivedBytes = 0;
+
+ for(;;) {
+ if(s.read((char*)&len, 2)!=2)
+ break;
+ len=ntohs(len);
+ // cout<<"Got chunk of "<<len<<" bytes"<<endl;
+ if(!len)
+ break;
+
+ if (maxReceivedBytes > 0 && (maxReceivedBytes - receivedBytes) < (size_t) len)
+ throw std::runtime_error("Reached the maximum number of received bytes in an IXFR delta for zone '"+zone.toString()+"' from master '"+master.toStringWithPort());
+
+ char reply[len];
+ readn2(s.getHandle(), reply, len);
+ receivedBytes += len;
+ MOADNSParser mdp(false, string(reply, len));
+ if(mdp.d_header.rcode)
+ throw std::runtime_error("Got an error trying to IXFR zone '"+zone.toString()+"' from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
+
+ // cout<<"Got a response, rcode: "<<mdp.d_header.rcode<<", got "<<mdp.d_answers.size()<<" answers"<<endl;
+
+ if(!tt.algo.empty()) { // TSIG verify message
+ tsigVerifier.check(std::string(reply, len), mdp);
+ }
+
+ for(auto& r: mdp.d_answers) {
+ if(r.first.d_type == QType::TSIG)
+ continue;
+ // cout<<r.first.d_name<< " " <<r.first.d_content->getZoneRepresentation()<<endl;
+ r.first.d_name = r.first.d_name.makeRelative(zone);
+ records.push_back(r.first);
+ if(r.first.d_type == QType::SOA) {
+ auto sr = getRR<SOARecordContent>(r.first);
+ if(sr) {
+ if(!masterSOA) {
+ if(sr->d_st.serial == std::dynamic_pointer_cast<SOARecordContent>(oursr.d_content)->d_st.serial) { // we are up to date
+ goto done;
+ }
+ masterSOA=sr;
+ }
+ else if(sr->d_st.serial == masterSOA->d_st.serial)
+ goto done;
+ }
+ }
+ }
+ }
+ // cout<<"Got "<<records.size()<<" records"<<endl;
+ done:;
+ for(unsigned int pos = 1;pos < records.size();) {
+ auto sr = getRR<SOARecordContent>(records[pos]);
+ vector<DNSRecord> remove, add;
+ if(!sr) { // this is an actual AXFR!
+ return {{remove, records}};
+ }
+ if(sr->d_st.serial == masterSOA->d_st.serial)
+ break;
+
+
+ remove.push_back(records[pos]); // this adds the SOA
+ for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
+ remove.push_back(records[pos]);
+ }
+ sr = getRR<SOARecordContent>(records[pos]);
+
+ add.push_back(records[pos]); // this adds the new SOA
+ for(pos++; pos < records.size() && records[pos].d_type != QType::SOA; ++pos) {
+ add.push_back(records[pos]);
+ }
+ ret.push_back(make_pair(remove,add));
+ }
+ return ret;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include "namespaces.hh"
+#include "iputils.hh"
+#include "dnsparser.hh"
+
+vector<pair<vector<DNSRecord>, vector<DNSRecord> > > getIXFRDeltas(const ComboAddress& master, const DNSName& zone,
+ const DNSRecord& sr, const TSIGTriplet& tt=TSIGTriplet(),
+ const ComboAddress* laddr=0, size_t maxReceivedBytes=0);
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "arguments.hh"
+#include "base64.hh"
+#include <sys/types.h>
+#include <dirent.h>
+
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "base32.hh"
+#include "dnssecinfra.hh"
+
+#include "dns_random.hh"
+#include "gss_context.hh"
+#include "zoneparser-tng.hh"
+#include <boost/multi_index_container.hpp>
+#include "resolver.hh"
+#include <fstream>
+#include "ixfr.hh"
+using namespace boost::multi_index;
+StatBag S;
+
+ArgvMap &arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+
+struct CIContentCompareStruct
+{
+ bool operator()(const shared_ptr<DNSRecordContent>&a, const shared_ptr<DNSRecordContent>& b) const
+ {
+ return toLower(a->getZoneRepresentation()) < toLower(b->getZoneRepresentation());
+ }
+};
+
+
+typedef multi_index_container<
+ DNSRecord,
+ indexed_by<
+ ordered_non_unique<
+ composite_key<DNSRecord,
+ member<DNSRecord, DNSName, &DNSRecord::d_name>,
+ member<DNSRecord, uint16_t, &DNSRecord::d_type>,
+ member<DNSRecord, uint16_t, &DNSRecord::d_class>,
+ member<DNSRecord, shared_ptr<DNSRecordContent>, &DNSRecord::d_content> >,
+ composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<uint16_t>, CIContentCompareStruct >
+
+ >
+ >
+ >records_t;
+
+uint32_t getSerialFromMaster(const ComboAddress& master, const DNSName& zone, shared_ptr<SOARecordContent>& sr, const TSIGTriplet& tt = TSIGTriplet())
+{
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, zone, QType::SOA);
+ if(!tt.algo.empty()) {
+ TSIGRecordContent trc;
+ trc.d_algoName = tt.algo;
+ trc.d_time = time((time_t*)NULL);
+ trc.d_fudge = 300;
+ trc.d_origID=ntohs(pw.getHeader()->id);
+ trc.d_eRcode=0;
+ addTSIG(pw, &trc, tt.name, tt.secret, "", false);
+ }
+
+ Socket s(master.sin4.sin_family, SOCK_DGRAM);
+ s.connect(master);
+ string msg((const char*)&packet[0], packet.size());
+ s.writen(msg);
+
+ string reply;
+ s.read(reply);
+ MOADNSParser mdp(false, reply);
+ if(mdp.d_header.rcode) {
+ throw std::runtime_error("Unable to retrieve SOA serial from master '"+master.toStringWithPort()+"': "+RCode::to_s(mdp.d_header.rcode));
+ }
+ for(const auto& r: mdp.d_answers) {
+ if(r.first.d_type == QType::SOA) {
+ sr = std::dynamic_pointer_cast<SOARecordContent>(r.first.d_content);
+ return sr->d_st.serial;
+ }
+ }
+ return 0;
+}
+
+
+uint32_t getSerialsFromDir(const std::string& dir)
+{
+ uint32_t ret=0;
+ DIR* dirhdl=opendir(dir.c_str());
+ if(!dirhdl)
+ throw runtime_error("Could not open IXFR directory");
+ struct dirent *entry;
+
+ while((entry = readdir(dirhdl))) {
+ uint32_t num = atoi(entry->d_name);
+ if(std::to_string(num) == entry->d_name)
+ ret = max(num, ret);
+ }
+ closedir(dirhdl);
+ return ret;
+}
+
+uint32_t getSerialFromRecords(const records_t& records, DNSRecord& soaret)
+{
+ DNSName root(".");
+ uint16_t t=QType::SOA;
+
+ auto found = records.equal_range(tie(root, t));
+
+ for(auto iter = found.first; iter != found.second; ++iter) {
+ auto soa = std::dynamic_pointer_cast<SOARecordContent>(iter->d_content);
+ soaret = *iter;
+ return soa->d_st.serial;
+ }
+ return 0;
+}
+
+void writeZoneToDisk(const records_t& records, const DNSName& zone, const std::string& directory)
+{
+ DNSRecord soa;
+ int serial = getSerialFromRecords(records, soa);
+ string fname=directory +"/"+std::to_string(serial);
+ FILE* fp=fopen((fname+".partial").c_str(), "w");
+ if(!fp)
+ throw runtime_error("Unable to open file '"+fname+".partial' for writing: "+string(strerror(errno)));
+
+ records_t soarecord;
+ soarecord.insert(soa);
+ fprintf(fp, "$ORIGIN %s\n", zone.toString().c_str());
+ for(const auto& outer : {soarecord, records, soarecord} ) {
+ for(const auto& r: outer) {
+ fprintf(fp, "%s\tIN\t%s\t%s\n",
+ r.d_name.isRoot() ? "@" : r.d_name.toStringNoDot().c_str(),
+ DNSRecordContent::NumberToType(r.d_type).c_str(),
+ r.d_content->getZoneRepresentation().c_str());
+ }
+ }
+ fclose(fp);
+ rename( (fname+".partial").c_str(), fname.c_str());
+}
+
+void loadZoneFromDisk(records_t& records, const string& fname, const DNSName& zone)
+{
+ ZoneParserTNG zpt(fname, zone);
+
+ DNSResourceRecord rr;
+ bool seenSOA=false;
+ unsigned int nrecords=0;
+ while(zpt.get(rr)) {
+ ++nrecords;
+ if(rr.qtype.getCode() == QType::CNAME && rr.content.empty())
+ rr.content=".";
+ rr.qname = rr.qname.makeRelative(zone);
+
+ if(rr.qtype.getCode() != QType::SOA || seenSOA==false)
+ records.insert(DNSRecord(rr));
+ if(rr.qtype.getCode() == QType::SOA) {
+ seenSOA=true;
+ }
+ }
+ cout<<"Parsed "<<nrecords<<" records"<<endl;
+ if(rr.qtype.getCode() == QType::SOA && seenSOA) {
+ cout<<"Zone was complete (SOA at end)"<<endl;
+ }
+ else {
+ records.clear();
+ throw runtime_error("Zone not complete!");
+ }
+}
+
+void usage() {
+ cerr<<"Syntax: ixplore diff ZONE BEFORE_FILE AFTER_FILE"<<endl;
+ cerr<<"Syntax: ixplore track IP-ADDRESS PORT ZONE DIRECTORY [TSIGKEY TSIGALGO TSIGSECRET]"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ for(int n=1 ; n < argc; ++n) {
+ if ((string) argv[n] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[n] == "--version") {
+ cerr<<"ixplore "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ reportAllTypes();
+ string command;
+ if(argc < 5 || (command=argv[1], (command!="diff" && command !="track"))) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+ if(command=="diff") {
+ records_t before, after;
+ DNSName zone(argv[2]);
+ cout<<"Loading before from "<<argv[3]<<endl;
+ loadZoneFromDisk(before, argv[3], zone);
+ cout<<"Loading after from "<<argv[4]<<endl;
+ loadZoneFromDisk(after, argv[4], zone);
+
+ vector<DNSRecord> diff;
+
+ set_difference(before.cbegin(), before.cend(), after.cbegin(), after.cend(), back_inserter(diff), before.value_comp());
+ for(const auto& d : diff) {
+ cout<<'-'<< (d.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation()<<endl;
+ }
+ diff.clear();
+ set_difference(after.cbegin(), after.cend(), before.cbegin(), before.cend(), back_inserter(diff), before.value_comp());
+ for(const auto& d : diff) {
+ cout<<'+'<< (d.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation()<<endl;
+ }
+ exit(1);
+ }
+
+ // must be "track" then
+
+ /* goal in life:
+ in directory/zone-name we leave files with their name the serial number
+ at startup, retrieve current SOA SERIAL for domain from master server
+
+ compare with what the best is we have in our directory, IXFR from that.
+ Store result in memory, read that best zone in memory, apply deltas, write it out.
+
+ Next up, loop this every REFRESH seconds */
+ dns_random_init("0123456789abcdef");
+
+ DNSName zone(argv[4]);
+ ComboAddress master(argv[2], atoi(argv[3]));
+ string directory(argv[5]);
+ records_t records;
+
+ uint32_t ourSerial = getSerialsFromDir(directory);
+
+ cout<<"Loading zone, our highest available serial is "<< ourSerial<<endl;
+
+ TSIGTriplet tt;
+ if(argc > 6)
+ tt.name=DNSName(toLower(argv[6]));
+ if(argc > 7)
+ tt.algo=DNSName(toLower(argv[7]));
+
+ if(argc > 8) {
+ if(B64Decode(argv[8], tt.secret) < 0) {
+ cerr<<"Could not decode tsig secret!"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ try {
+ if(!ourSerial)
+ throw std::runtime_error("There is no local zone available");
+ string fname=directory+"/"+std::to_string(ourSerial);
+ cout<<"Loading serial number "<<ourSerial<<" from file "<<fname<<endl;
+ loadZoneFromDisk(records, fname, zone);
+ }
+ catch(std::exception& e) {
+ cout<<"Could not load zone from disk: "<<e.what()<<endl;
+ cout<<"Retrieving latest from master "<<master.toStringWithPort()<<endl;
+ ComboAddress local = master.sin4.sin_family == AF_INET ? ComboAddress("0.0.0.0") : ComboAddress("::");
+ AXFRRetriever axfr(master, zone, tt, &local);
+ unsigned int nrecords=0;
+ Resolver::res_t nop;
+ vector<DNSRecord> chunk;
+ char wheel[]="|/-\\";
+ int count=0;
+ time_t last=0;
+ while(axfr.getChunk(nop, &chunk)) {
+ for(auto& dr : chunk) {
+ if(dr.d_type == QType::TSIG)
+ continue;
+ dr.d_name.makeUsRelative(zone);
+ records.insert(dr);
+ nrecords++;
+ }
+
+ if(last != time(0)) {
+ cout << '\r' << wheel[count % (sizeof(wheel)-1)] << ' ' <<nrecords;
+ count++;
+ cout.flush();
+ last=time(0);
+ }
+ }
+ cout <<"\rDone, got "<<nrecords<<" "<<endl;
+ cout<<"Writing to disk.."<<endl;
+ writeZoneToDisk(records, zone, directory);
+ }
+
+ for(;;) {
+ DNSRecord ourSoa;
+ ourSerial = getSerialFromRecords(records, ourSoa);
+
+ cout<<"Checking for update, our serial number is "<<ourSerial<<".. ";
+ cout.flush();
+ shared_ptr<SOARecordContent> sr;
+ uint32_t serial = getSerialFromMaster(master, zone, sr, tt);
+ if(ourSerial == serial) {
+ cout<<"still up to date, their serial is "<<serial<<", sleeping "<<sr->d_st.refresh<<" seconds"<<endl;
+ sleep(sr->d_st.refresh);
+ continue;
+ }
+
+ cout<<"got new serial: "<<serial<<", initiating IXFR!"<<endl;
+ auto deltas = getIXFRDeltas(master, zone, ourSoa, tt);
+ cout<<"Got "<<deltas.size()<<" deltas, applying.."<<endl;
+
+ for(const auto& delta : deltas) {
+
+ const auto& remove = delta.first;
+ const auto& add = delta.second;
+
+ ourSerial=getSerialFromRecords(records, ourSoa);
+ uint32_t newserial=0;
+ for(const auto& rr : add) {
+ if(rr.d_type == QType::SOA) {
+ newserial=std::dynamic_pointer_cast<SOARecordContent>(rr.d_content)->d_st.serial;
+ }
+ }
+
+ cout<<"This delta ("<<ourSerial<<" - "<<newserial<<") has "<<remove.size()<<" removals, "<<add.size()<<" additions"<<endl;
+ ofstream report(directory +"/delta."+std::to_string(ourSerial)+"-"+std::to_string(newserial));
+ if(remove.empty()) {
+ cout<<"This delta is a whole new zone"<<endl;
+ report<<"- everything, whole new zone update follow"<<endl;
+ records.clear();
+ }
+
+ bool stop=false;
+
+ for(const auto& rr : remove) {
+ report<<'-'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl;
+ auto range = records.equal_range(tie(rr.d_name, rr.d_type, rr.d_class, rr.d_content));
+ if(range.first == range.second) {
+ cout<<endl<<" !! Could not find record "<<rr.d_name<<" to remove!!"<<endl;
+ // stop=true;
+ report.flush();
+ }
+ records.erase(range.first, range.second);
+ }
+
+ for(const auto& rr : add) {
+ report<<'+'<< (rr.d_name+zone) <<" IN "<<DNSRecordContent::NumberToType(rr.d_type)<<" "<<rr.d_content->getZoneRepresentation()<<endl;
+ records.insert(rr);
+ }
+ if(stop) {
+ cerr<<"Had error condition, stopping.."<<endl;
+ report.flush();
+ exit(1);
+ }
+ }
+ cout<<"Writing zone to disk.. "; cout.flush();
+ writeZoneToDisk(records, zone, directory);
+ cout<<"Done"<<endl;
+ }
+}
+catch(PDNSException &e2) {
+ cerr<<"Fatal: "<<e2.reason<<endl;
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+catch(...)
+{
+ cerr<<"Any other exception"<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "json.hh"
+#include "namespaces.hh"
+#include "misc.hh"
+
+using json11::Json;
+
+int intFromJson(const Json container, const std::string& key)
+{
+ auto val = container[key];
+ if (val.is_number()) {
+ return val.int_value();
+ } else if (val.is_string()) {
+ return std::stoi(val.string_value());
+ } else {
+ throw JsonException("Key '" + string(key) + "' not an Integer or not present");
+ }
+}
+
+int intFromJson(const Json container, const std::string& key, const int default_value)
+{
+ auto val = container[key];
+ if (val.is_number()) {
+ return val.int_value();
+ } else if (val.is_string()) {
+ return std::stoi(val.string_value());
+ } else {
+ // TODO: check if value really isn't present
+ return default_value;
+ }
+}
+
+double doubleFromJson(const Json container, const std::string& key)
+{
+ auto val = container[key];
+ if (val.is_number()) {
+ return val.number_value();
+ } else if (val.is_string()) {
+ return std::stod(val.string_value());
+ } else {
+ throw JsonException("Key '" + string(key) + "' not an Integer or not present");
+ }
+}
+
+double doubleFromJson(const Json container, const std::string& key, const double default_value)
+{
+ auto val = container[key];
+ if (val.is_number()) {
+ return val.number_value();
+ } else if (val.is_string()) {
+ return std::stod(val.string_value());
+ } else {
+ // TODO: check if value really isn't present
+ return default_value;
+ }
+}
+
+string stringFromJson(const Json container, const std::string &key)
+{
+ const Json val = container[key];
+ if (val.is_string()) {
+ return val.string_value();
+ } else {
+ throw JsonException("Key '" + string(key) + "' not present or not a String");
+ }
+}
+
+bool boolFromJson(const Json container, const std::string& key)
+{
+ auto val = container[key];
+ if (val.is_bool()) {
+ return val.bool_value();
+ }
+ throw JsonException("Key '" + string(key) + "' not present or not a Bool");
+}
+
+bool boolFromJson(const Json container, const std::string& key, const bool default_value)
+{
+ auto val = container[key];
+ if (val.is_bool()) {
+ return val.bool_value();
+ }
+ return default_value;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once // it is 2012, deal with it
+
+#include <string>
+#include <stdexcept>
+#include "json11.hpp"
+
+int intFromJson(const json11::Json container, const std::string& key);
+int intFromJson(const json11::Json container, const std::string& key, const int default_value);
+double doubleFromJson(const json11::Json container, const std::string& key);
+double doubleFromJson(const json11::Json container, const std::string& key, const double default_value);
+std::string stringFromJson(const json11::Json container, const std::string &key);
+bool boolFromJson(const json11::Json container, const std::string& key);
+bool boolFromJson(const json11::Json container, const std::string& key, const bool default_value);
+
+class JsonException : public std::runtime_error
+{
+public:
+ JsonException(const std::string& what) : std::runtime_error(what) {
+ }
+};
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "iputils.hh"
+#include "sstuff.hh"
+#include "statbag.hh"
+
+/* This tool REALLY wants to be rewritten in Python, by ahu does not speak it very well.
+ What it does is provide answers to queries from the Lua generic UDP Question/Answer
+ stuff in kv-example-script.lua */
+
+StatBag S;
+
+int main(int argc, char** argv)
+try
+{
+ if(argc != 3) {
+ cerr<<"Syntax: kvresp local-address local-port"<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ ComboAddress local(argv[1], atoi(argv[2]));
+ Socket s(local.sin4.sin_family, SOCK_DGRAM);
+
+ s.bind(local);
+ cout<<"Bound to "<<local.toStringWithPort()<<endl;
+
+ char buffer[1500];
+
+ int len;
+ ComboAddress rem=local;
+ socklen_t socklen = rem.getSocklen();
+ for(;;) {
+ len=recvfrom(s.getHandle(), buffer, sizeof(buffer), 0, (struct sockaddr*)&rem, &socklen);
+ if(len < 0)
+ unixDie("recvfrom");
+ string query(buffer, len);
+ cout<<"Had packet: "<<query<<endl;
+ vector<string> parts;
+ stringtok(parts, query);
+ if(parts.size()<2)
+ continue;
+ string response;
+ if(parts[0]=="DOMAIN")
+ response= (parts[1].find("xxx") != string::npos) ? "1" : "0";
+ else if(parts[0]=="IP")
+ response= (parts[1]=="127.0.0.1") ? "1" : "0";
+ else
+ response= "???";
+
+ cout<<"Our reply: "<<response<<endl;
+ if(sendto(s.getHandle(), response.c_str(), response.length(), 0, (struct sockaddr*)&rem, socklen) < 0)
+ unixDie("sendto");
+ }
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal error: "<<e.what()<<endl;
+ exit(EXIT_FAILURE);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef LOCK_HH
+#define LOCK_HH
+
+#include <pthread.h>
+#include <errno.h>
+#include "misc.hh"
+#include "pdnsexception.hh"
+
+extern bool g_singleThreaded;
+
+class Lock
+{
+ pthread_mutex_t *d_lock;
+public:
+
+ Lock(pthread_mutex_t *lock) : d_lock(lock)
+ {
+ if(g_singleThreaded)
+ return;
+ if((errno=pthread_mutex_lock(d_lock)))
+ throw PDNSException("error acquiring lock: "+stringerror());
+ }
+ ~Lock()
+ {
+ if(g_singleThreaded)
+ return;
+
+ pthread_mutex_unlock(d_lock);
+ }
+};
+
+class WriteLock
+{
+ pthread_rwlock_t *d_lock;
+public:
+
+ WriteLock(pthread_rwlock_t *lock) : d_lock(lock)
+ {
+ if(g_singleThreaded)
+ return;
+
+ if((errno=pthread_rwlock_wrlock(d_lock))) {
+ throw PDNSException("error acquiring rwlock wrlock: "+stringerror());
+ }
+ }
+ ~WriteLock()
+ {
+ if(g_singleThreaded)
+ return;
+
+ pthread_rwlock_unlock(d_lock);
+ }
+};
+
+class TryWriteLock
+{
+ pthread_rwlock_t *d_lock;
+ bool d_havelock;
+public:
+
+ TryWriteLock(pthread_rwlock_t *lock) : d_lock(lock)
+ {
+ if(g_singleThreaded) {
+ d_havelock=true;
+ return;
+ }
+
+ d_havelock=false;
+ if((errno=pthread_rwlock_trywrlock(d_lock)) && errno!=EBUSY)
+ throw PDNSException("error acquiring rwlock tryrwlock: "+stringerror());
+ d_havelock=(errno==0);
+ }
+ ~TryWriteLock()
+ {
+ if(g_singleThreaded)
+ return;
+
+ if(d_havelock)
+ pthread_rwlock_unlock(d_lock);
+ }
+ bool gotIt()
+ {
+ if(g_singleThreaded)
+ return true;
+
+ return d_havelock;
+ }
+};
+
+class TryReadLock
+{
+ pthread_rwlock_t *d_lock;
+ bool d_havelock;
+public:
+
+ TryReadLock(pthread_rwlock_t *lock) : d_lock(lock)
+ {
+ if(g_singleThreaded) {
+ d_havelock=true;
+ return;
+ }
+
+ if((errno=pthread_rwlock_tryrdlock(d_lock)) && errno!=EBUSY)
+ throw PDNSException("error acquiring rwlock tryrdlock: "+stringerror());
+ d_havelock=(errno==0);
+ }
+ ~TryReadLock()
+ {
+ if(g_singleThreaded)
+ return;
+
+ if(d_havelock)
+ pthread_rwlock_unlock(d_lock);
+ }
+ bool gotIt()
+ {
+ if(g_singleThreaded)
+ return true;
+
+ return d_havelock;
+ }
+};
+
+
+class ReadLock
+{
+ pthread_rwlock_t *d_lock;
+public:
+
+ ReadLock(pthread_rwlock_t *lock) : d_lock(lock)
+ {
+ if(g_singleThreaded)
+ return;
+
+ if((errno=pthread_rwlock_rdlock(d_lock)))
+ throw PDNSException("error acquiring rwlock tryrwlock: "+stringerror());
+ }
+ ~ReadLock()
+ {
+ if(g_singleThreaded)
+ return;
+
+ pthread_rwlock_unlock(d_lock);
+ }
+
+ void upgrade()
+ {
+ if(g_singleThreaded)
+ return;
+
+ pthread_rwlock_unlock(d_lock);
+ pthread_rwlock_wrlock(d_lock);
+ }
+};
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "logger.hh"
+#include "misc.hh"
+#ifndef RECURSOR
+#include "statbag.hh"
+extern StatBag S;
+#endif
+#include "lock.hh"
+#include "namespaces.hh"
+
+pthread_once_t Logger::s_once;
+pthread_key_t Logger::s_loggerKey;
+
+Logger &theL(const string &pname)
+{
+ static Logger l("", LOG_DAEMON);
+ if(!pname.empty())
+ l.setName(pname);
+ return l;
+}
+
+void Logger::log(const string &msg, Urgency u)
+{
+#ifndef RECURSOR
+ bool mustAccount(false);
+#endif
+ struct tm tm;
+ time_t t;
+ time(&t);
+ tm=*localtime(&t);
+
+ if(u<=consoleUrgency) {
+ char buffer[50];
+ strftime(buffer,sizeof(buffer),"%b %d %H:%M:%S ", &tm);
+ static pthread_mutex_t m = PTHREAD_MUTEX_INITIALIZER;
+ Lock l(&m); // the C++-2011 spec says we need this, and OSX actually does
+ clog << string(buffer) + msg <<endl;
+#ifndef RECURSOR
+ mustAccount=true;
+#endif
+ }
+ if( u <= d_loglevel && !d_disableSyslog ) {
+ syslog(u,"%s",msg.c_str());
+#ifndef RECURSOR
+ mustAccount=true;
+#endif
+ }
+
+#ifndef RECURSOR
+ if(mustAccount)
+ S.ringAccount("logmessages",msg);
+#endif
+}
+
+void Logger::setLoglevel( Urgency u )
+{
+ d_loglevel = u;
+}
+
+
+void Logger::toConsole(Urgency u)
+{
+ consoleUrgency=u;
+}
+
+void Logger::open()
+{
+ if(opened)
+ closelog();
+ openlog(name.c_str(),flags,d_facility);
+ opened=true;
+}
+
+void Logger::setName(const string &_name)
+{
+ name=_name;
+ open();
+}
+
+void Logger::initKey()
+{
+ if(pthread_key_create(&s_loggerKey, perThreadDestructor))
+ unixDie("Creating thread key for logger");
+}
+
+Logger::Logger(const string &n, int facility)
+{
+ opened=false;
+ flags=LOG_PID|LOG_NDELAY;
+ d_facility=facility;
+ d_loglevel=Logger::None;
+ d_disableSyslog=false;
+ consoleUrgency=Error;
+ name=n;
+
+ if(pthread_once(&s_once, initKey))
+ unixDie("Creating thread key for logger");
+
+ open();
+
+}
+
+Logger& Logger::operator<<(Urgency u)
+{
+ getPerThread()->d_urgency=u;
+ return *this;
+}
+
+void Logger::perThreadDestructor(void* buf)
+{
+ PerThread* pt = (PerThread*) buf;
+ delete pt;
+}
+
+Logger::PerThread* Logger::getPerThread()
+{
+ void *buf=pthread_getspecific(s_loggerKey);
+ PerThread* ret;
+ if(buf)
+ ret = (PerThread*) buf;
+ else {
+ ret = new PerThread();
+ pthread_setspecific(s_loggerKey, (void*)ret);
+ }
+ return ret;
+}
+
+Logger& Logger::operator<<(const string &s)
+{
+ PerThread* pt =getPerThread();
+ pt->d_output.append(s);
+ return *this;
+}
+
+Logger& Logger::operator<<(const char *s)
+{
+ *this<<string(s);
+ return *this;
+}
+
+Logger& Logger::operator<<(int i)
+{
+ ostringstream tmp;
+ tmp<<i;
+
+ *this<<tmp.str();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(double i)
+{
+ ostringstream tmp;
+ tmp<<i;
+ *this<<tmp.str();
+ return *this;
+}
+
+Logger& Logger::operator<<(unsigned int i)
+{
+ ostringstream tmp;
+ tmp<<i;
+
+ *this<<tmp.str();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(unsigned long i)
+{
+ ostringstream tmp;
+ tmp<<i;
+
+ *this<<tmp.str();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(unsigned long long i)
+{
+ ostringstream tmp;
+ tmp<<i;
+
+ *this<<tmp.str();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(long i)
+{
+ ostringstream tmp;
+ tmp<<i;
+
+ *this<<tmp.str();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(ostream & (&)(ostream &))
+{
+ PerThread* pt =getPerThread();
+
+ log(pt->d_output, pt->d_urgency);
+ pt->d_output.clear();
+ pt->d_urgency=Info;
+ return *this;
+}
+
+Logger& Logger::operator<<(const DNSName &d)
+{
+ *this<<d.toLogString();
+
+ return *this;
+}
+
+Logger& Logger::operator<<(const ComboAddress &ca)
+{
+ *this<<ca.toString();
+ return *this;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <string>
+#include <ctime>
+#include <iostream>
+#include <sstream>
+#include <syslog.h>
+#include <pthread.h>
+
+#include "namespaces.hh"
+#include "dnsname.hh"
+#include "iputils.hh"
+
+//! The Logger class can be used to log messages in various ways.
+class Logger
+{
+public:
+ Logger(const string &, int facility=LOG_DAEMON); //!< pass the identification you wish to appear in the log
+
+ //! The urgency of a log message
+ enum Urgency {All=32767,Alert=LOG_ALERT, Critical=LOG_CRIT, Error=LOG_ERR, Warning=LOG_WARNING,
+ Notice=LOG_NOTICE,Info=LOG_INFO, Debug=LOG_DEBUG, None=-1};
+
+ /** Log a message.
+ \param msg Message you wish to log
+ \param u Urgency of the message you wish to log
+ */
+ void log(const string &msg, Urgency u=Notice);
+
+ void setFacility(int f){d_facility=f;open();} //!< Choose logging facility
+ void setFlag(int f){flags|=f;open();} //!< set a syslog flag
+ void setName(const string &);
+
+ //! set lower limit of urgency needed for console display. Messages of this urgency, and higher, will be displayed
+ void toConsole(Urgency);
+ void setLoglevel( Urgency );
+
+ void disableSyslog(bool d) {
+ d_disableSyslog = d;
+ }
+
+ //! Log to a file.
+ void toFile( const string & filename );
+
+ void resetFlags(){flags=0;open();} //!< zero the flags
+ /** Use this to stream to your log, like this:
+ \code
+ L<<"This is an informational message"<<endl; // logged at default loglevel (Info)
+ L<<Logger::Warning<<"Out of diskspace"<<endl; // Logged as a warning
+ L<<"This is an informational message"<<endl; // logged AGAIN at default loglevel (Info)
+ \endcode
+ */
+ Logger& operator<<(const char *s);
+ Logger& operator<<(const string &s); //!< log a string
+ Logger& operator<<(int); //!< log an int
+ Logger& operator<<(double); //!< log a double
+ Logger& operator<<(unsigned int); //!< log an unsigned int
+ Logger& operator<<(long); //!< log an unsigned int
+ Logger& operator<<(unsigned long); //!< log an unsigned int
+ Logger& operator<<(unsigned long long); //!< log an unsigned 64 bit int
+ Logger& operator<<(const DNSName&);
+ Logger& operator<<(const ComboAddress&); //!< log an address
+ Logger& operator<<(Urgency); //!< set the urgency, << style
+
+ Logger& operator<<(std::ostream & (&)(std::ostream &)); //!< this is to recognise the endl, and to commit the log
+
+private:
+ struct PerThread
+ {
+ PerThread()
+ {
+ d_urgency=Info;
+ }
+ string d_output;
+ Urgency d_urgency;
+ };
+ static void initKey();
+ static void perThreadDestructor(void *);
+ PerThread* getPerThread();
+ void open();
+
+ string name;
+ int flags;
+ int d_facility;
+ Urgency d_loglevel;
+ Urgency consoleUrgency;
+ bool opened;
+ bool d_disableSyslog;
+ static pthread_once_t s_once;
+ static pthread_key_t s_loggerKey;
+};
+
+extern Logger &theL(const string &pname="");
+
+#ifdef VERBOSELOG
+#define DLOG(x) x
+#else
+#define DLOG(x) ((void)0)
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "lua-auth.hh"
+
+#if !defined(HAVE_LUA)
+
+AuthLua::AuthLua(const std::string &fname)
+ : PowerDNSLua(fname)
+{
+ // empty
+}
+
+DNSPacket* AuthLua::prequery(DNSPacket *p)
+{
+ return 0;
+}
+
+int AuthLua::police(DNSPacket *req, DNSPacket *resp, bool isTcp)
+{
+ return PolicyDecision::PASS;
+}
+
+string AuthLua::policycmd(const vector<string>&parts) {
+ return "no policy script loaded";
+}
+
+bool AuthLua::axfrfilter(const ComboAddress& remote, const DNSName& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
+{
+ return false;
+}
+
+#else
+
+
+extern "C" {
+#undef L
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
+
+#include "logger.hh"
+#include "namespaces.hh"
+
+AuthLua::AuthLua(const std::string &fname)
+ : PowerDNSLua(fname)
+{
+ registerLuaDNSPacket();
+ pthread_mutex_init(&d_lock,0);
+}
+
+bool AuthLua::axfrfilter(const ComboAddress& remote, const DNSName& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out)
+{
+ lua_getglobal(d_lua, "axfrfilter");
+ if(!lua_isfunction(d_lua, -1)) {
+ // cerr<<"No such function 'axfrfilter'\n";
+ lua_pop(d_lua, 1);
+ return false;
+ }
+
+ lua_pushstring(d_lua, remote.toString().c_str() );
+ lua_pushstring(d_lua, zone.toString().c_str() ); // FIXME400 expose DNSName to Lua?
+ lua_pushstring(d_lua, in.qname.toString().c_str() );
+ lua_pushnumber(d_lua, in.qtype.getCode() );
+ lua_pushnumber(d_lua, in.ttl );
+ lua_pushstring(d_lua, in.content.c_str() );
+
+ if(lua_pcall(d_lua, 6, 2, 0)) { // error
+ string error=string("lua error in axfrfilter: ")+lua_tostring(d_lua, -1);
+ lua_pop(d_lua, 1);
+ throw runtime_error(error);
+ return false;
+ }
+
+ int newres = (int)lua_tonumber(d_lua, 1); // did we handle it?
+ if(newres < 0) {
+ //cerr << "handler did not handle"<<endl;
+ lua_pop(d_lua, 2);
+ return false;
+ }
+
+ /* get the result */
+ DNSResourceRecord rr;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rr.ttl = 3600;
+ rr.domain_id = in.domain_id;
+
+ out.clear();
+
+ /* 1 2 3 4 */
+ /* stack: boolean table key row */
+
+ int tableLen = getLuaTableLength(d_lua, 2);
+ for(int n=1; n < tableLen + 1; ++n) {
+ lua_pushnumber(d_lua, n);
+ lua_gettable(d_lua, 2);
+
+ uint32_t tmpnum=0;
+ if(!getFromTable("qtype", tmpnum))
+ rr.qtype=QType::A;
+ else
+ rr.qtype=tmpnum;
+
+ getFromTable("content", rr.content);
+ if(!getFromTable("ttl", rr.ttl))
+ rr.ttl=3600;
+
+ string qname;
+ if(!getFromTable("qname", qname))
+ rr.qname = zone;
+ else
+ rr.qname=DNSName(qname);
+
+ if(!getFromTable("place", tmpnum))
+ rr.d_place = DNSResourceRecord::ANSWER;
+ else
+ rr.d_place = static_cast<DNSResourceRecord::Place>(tmpnum);
+
+ /* removes 'value'; keeps 'key' for next iteration */
+ lua_pop(d_lua, 1); // table
+
+ // cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
+ rr.qname.makeUsLowerCase();
+ out.push_back(rr);
+ }
+ lua_pop(d_lua, 2); // c
+ return true;
+}
+
+struct LuaDNSPacket
+{
+ DNSPacket *d_p;
+};
+
+static DNSPacket* ldp_checkDNSPacket(lua_State *L) {
+ void *ud = luaL_checkudata(L, 1, "LuaDNSPacket");
+ luaL_argcheck(L, ud != NULL, 1, "`LuaDNSPacket' expected");
+ return ((LuaDNSPacket *)ud)->d_p;
+}
+
+static int ldp_setRcode(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+#if LUA_VERSION_NUM < 503
+ int rcode = luaL_checkint(L, 2);
+#else
+ int rcode = (int)luaL_checkinteger(L, 2);
+#endif
+ p->setRcode(rcode);
+ return 0;
+}
+
+static int ldp_getQuestion(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ lua_pushstring(L, p->qdomain.toString().c_str());
+ lua_pushnumber(L, p->qtype.getCode());
+ return 2;
+}
+
+static int ldp_getWild(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ if(p->qdomainwild.empty())
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, p->qdomainwild.toString().c_str());
+ return 1;
+}
+
+static int ldp_getZone(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ if(p->qdomainzone.empty())
+ lua_pushnil(L);
+ else
+ lua_pushstring(L, p->qdomainzone.toString().c_str());
+ return 1;
+}
+
+static int ldp_addRecords(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ vector<DNSRecord> rrs;
+ popResourceRecordsTable(L, DNSName("BOGUS"), rrs);
+ for(const DNSRecord& dr : rrs) {
+ p->addRecord(DNSResourceRecord(dr));
+ }
+ return 0;
+}
+
+static int ldp_getRemote(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ lua_pushstring(L, p->getRemote().toString().c_str());
+ return 1;
+}
+
+static int ldp_getRemoteRaw(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ const ComboAddress& ca=p->getRemote();
+ if(ca.sin4.sin_family == AF_INET) {
+ lua_pushlstring(L, (const char*)&ca.sin4.sin_addr.s_addr, 4);
+ }
+ else {
+ lua_pushlstring(L, (const char*)&ca.sin6.sin6_addr.s6_addr, 16);
+ }
+ return 1;
+}
+
+static int ldp_getRcode(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ lua_pushnumber(L, p->d.rcode);
+ return 1;
+}
+
+static int ldp_getSize(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ lua_pushnumber(L, p->getString().size());
+ return 1;
+}
+
+static int ldp_getRRCounts(lua_State *L) {
+ DNSPacket *p=ldp_checkDNSPacket(L);
+ lua_pushnumber(L, ntohs(p->d.ancount));
+ lua_pushnumber(L, ntohs(p->d.nscount));
+ lua_pushnumber(L, ntohs(p->d.arcount));
+ return 3;
+}
+
+// these functions are used for PowerDNS recursor regression testing against auth,
+// and for the Lua Policy Engine. The Lua 5.2 implementation is untested.
+static const struct luaL_Reg ldp_methods [] = {
+ {"setRcode", ldp_setRcode},
+ {"getQuestion", ldp_getQuestion},
+ {"getWild", ldp_getWild},
+ {"getZone", ldp_getZone},
+ {"addRecords", ldp_addRecords},
+ {"getRemote", ldp_getRemote},
+ {"getRemoteRaw", ldp_getRemoteRaw},
+ {"getSize", ldp_getSize},
+ {"getRRCounts", ldp_getRRCounts},
+ {"getRcode", ldp_getRcode},
+ {NULL, NULL}
+ };
+
+#if LUA_VERSION_NUM < 502
+void AuthLua::registerLuaDNSPacket(void) {
+
+ luaL_newmetatable(d_lua, "LuaDNSPacket");
+
+ lua_pushstring(d_lua, "__index");
+ lua_pushvalue(d_lua, -2); /* pushes the metatable */
+ lua_settable(d_lua, -3); /* metatable.__index = metatable */
+
+ luaL_openlib(d_lua, NULL, ldp_methods, 0);
+
+ lua_pop(d_lua, 1);
+}
+#else
+
+void AuthLua::registerLuaDNSPacket(void) {
+
+ luaL_newmetatable(d_lua, "LuaDNSPacket");
+
+ lua_pushstring(d_lua, "__index");
+ lua_pushvalue(d_lua, -2); /* pushes the metatable */
+ lua_settable(d_lua, -3); /* metatable.__index = metatable */
+
+ luaL_setfuncs(d_lua, ldp_methods, 0);
+
+ lua_pop(d_lua, 1);
+}
+#endif
+
+DNSPacket* AuthLua::prequery(DNSPacket *p)
+{
+ lua_getglobal(d_lua,"prequery");
+ if(!lua_isfunction(d_lua, -1)) {
+ // cerr<<"No such function 'prequery'\n";
+ lua_pop(d_lua, 1);
+ return 0;
+ }
+
+ DNSPacket *r=0;
+ // allocate a fresh packet and prefill the question
+ r=p->replyPacket();
+
+ // wrap it
+ LuaDNSPacket* lua_dp = (LuaDNSPacket *)lua_newuserdata(d_lua, sizeof(LuaDNSPacket));
+ lua_dp->d_p=r;
+
+ // make it of the right type
+ luaL_getmetatable(d_lua, "LuaDNSPacket");
+ lua_setmetatable(d_lua, -2);
+
+ if(lua_pcall(d_lua, 1, 1, 0)) { // error
+ string error=string("lua error in prequery: ")+lua_tostring(d_lua, -1);
+ theL()<<Logger::Error<<error<<endl;
+
+ lua_pop(d_lua, 1);
+ throw runtime_error(error);
+ }
+ bool res=lua_toboolean(d_lua, 1);
+ lua_pop(d_lua, 1);
+ if(res) {
+ // prequery created our response, use it
+ theL()<<Logger::Info<<"overriding query from lua prequery result"<<endl;
+ return r;
+ }
+ else
+ {
+ // prequery wanted nothing to do with this question
+ delete r;
+ return 0;
+ }
+}
+
+int AuthLua::police(DNSPacket *req, DNSPacket *resp, bool isTcp)
+{
+ Lock l(&d_lock);
+
+ lua_getglobal(d_lua, "police");
+ if(!lua_isfunction(d_lua, -1)) {
+ // cerr<<"No such function 'police'\n"; FIXME: raise Exception? check this beforehand so we can log it once?
+ lua_pop(d_lua, 1);
+ return PolicyDecision::PASS;
+ }
+
+ /* wrap request */
+ LuaDNSPacket* lreq = (LuaDNSPacket *)lua_newuserdata(d_lua, sizeof(LuaDNSPacket));
+ lreq->d_p=req;
+ luaL_getmetatable(d_lua, "LuaDNSPacket");
+ lua_setmetatable(d_lua, -2);
+
+ /* wrap response */
+ if(resp) {
+ LuaDNSPacket* lresp = (LuaDNSPacket *)lua_newuserdata(d_lua, sizeof(LuaDNSPacket));
+ lresp->d_p=resp;
+ luaL_getmetatable(d_lua, "LuaDNSPacket");
+ lua_setmetatable(d_lua, -2);
+ }
+ else
+ {
+ lua_pushnil(d_lua);
+ }
+
+ lua_pushboolean(d_lua, isTcp);
+
+ if(lua_pcall(d_lua, 3, 1, 0)) {
+ string error=string("lua error in police: ")+lua_tostring(d_lua, -1);
+ lua_pop(d_lua, 1);
+ theL()<<Logger::Error<<"police error: "<<error<<endl;
+
+ throw runtime_error(error);
+ }
+
+ int res = (int) lua_tonumber(d_lua, 1);
+ lua_pop(d_lua, 1);
+
+ return res;
+}
+
+string AuthLua::policycmd(const vector<string>&parts) {
+ Lock l(&d_lock);
+
+ lua_getglobal(d_lua, "policycmd");
+ if(!lua_isfunction(d_lua, -1)) {
+ // cerr<<"No such function 'police'\n"; FIXME: raise Exception? check this beforehand so we can log it once?
+ lua_pop(d_lua, 1);
+ return "no policycmd function in policy script";
+ }
+
+ for(vector<string>::size_type i=1; i<parts.size(); i++)
+ lua_pushstring(d_lua, parts[i].c_str());
+
+ if(lua_pcall(d_lua, parts.size()-1, 1, 0)) {
+ string error = string("lua error in policycmd: ")+lua_tostring(d_lua, -1);
+ lua_pop(d_lua, 1);
+ return error;
+ }
+
+ const char *ret = lua_tostring(d_lua, 1);
+ string rets;
+ if(ret)
+ rets = ret;
+
+ lua_pop(d_lua, 1);
+
+ return rets;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_LUA_AUTH_HH
+#define PDNS_LUA_AUTH_HH
+#include "dns.hh"
+#include "iputils.hh"
+#include "dnspacket.hh"
+#include "lua-pdns.hh"
+#include "lock.hh"
+
+class AuthLua : public PowerDNSLua
+{
+public:
+ explicit AuthLua(const std::string& fname);
+ // ~AuthLua();
+ bool axfrfilter(const ComboAddress& remote, const DNSName& zone, const DNSResourceRecord& in, vector<DNSResourceRecord>& out);
+ DNSPacket* prequery(DNSPacket *p);
+ int police(DNSPacket *req, DNSPacket *resp, bool isTcp=false);
+ string policycmd(const vector<string>&parts);
+
+private:
+ void registerLuaDNSPacket(void);
+
+ pthread_mutex_t d_lock;
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#ifdef HAVE_LUA
+extern "C" {
+#include <lua.h>
+#include <lauxlib.h>
+}
+#include <iostream>
+#include "iputils.hh"
+#include <string>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+#include <string.h>
+#include <netdb.h>
+#include "namespaces.hh"
+#undef L
+
+#if !defined LUA_VERSION_NUM || LUA_VERSION_NUM==501
+/*
+** Adapted from Lua 5.2.0
+*/
+static void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) {
+ luaL_checkstack(L, nup+1, "too many upvalues");
+ for (; l->name != NULL; l++) { /* fill the table with given functions */
+ int i;
+ lua_pushstring(L, l->name);
+ for (i = 0; i < nup; i++) /* copy upvalues to the top */
+ lua_pushvalue(L, -(nup+1));
+ lua_pushcclosure(L, l->func, nup); /* closure with those upvalues */
+ lua_settable(L, -(nup + 3));
+ }
+ lua_pop(L, nup); /* remove upvalues */
+}
+#endif
+
+
+/////////////////////////////////
+
+static int l_new_ca(lua_State* L)
+{
+ ComboAddress* ca=(ComboAddress*)lua_newuserdata(L, sizeof(ComboAddress));
+ memset(ca, 0, sizeof(ComboAddress));
+ *ca=ComboAddress(luaL_checkstring(L, 1));
+ luaL_getmetatable(L, "iputils.ca");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int l_ca_tostring(lua_State* L)
+{
+ ComboAddress* ca = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca");
+
+ string ret=ca->toString();
+ lua_pushstring(L, ret.c_str());
+ return 1;
+}
+
+static int l_ca_tostringWithPort(lua_State* L)
+{
+ ComboAddress* ca = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca");
+
+ string ret=ca->toStringWithPort();
+ lua_pushstring(L, ret.c_str());
+ return 1;
+}
+
+static int l_ca_equal(lua_State* L)
+{
+ ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 1, "iputils.ca");
+ ComboAddress* ca2 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca");
+ lua_pushboolean(L, *ca1==*ca2);
+ return 1;
+}
+
+static const struct luaL_Reg iputils_ca_methods[]={
+ {"tostring", l_ca_tostring},
+ {"__tostring", l_ca_tostring},
+ {"__eq", l_ca_equal},
+ {"tostringwithport", l_ca_tostringWithPort},
+ {NULL, NULL}
+};
+
+
+/////////////////////////////
+
+typedef set<ComboAddress, ComboAddress::addressOnlyLessThan> ourset_t;
+
+static int l_ipset_index(lua_State* L)
+{
+ ourset_t *ourset = (ourset_t*)luaL_checkudata(L, 1, "iputils.ipset");
+ ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca");
+ if(ourset->count(*ca1)) {
+ lua_pushboolean(L, 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+static int l_ipset_newindex(lua_State* L)
+{
+ ourset_t*ourset = (ourset_t*)luaL_checkudata(L, 1, "iputils.ipset");
+ ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca");
+ ourset->insert(*ca1);
+ return 0;
+}
+
+static int l_newipset(lua_State* L)
+{
+ new(lua_newuserdata(L, sizeof(ourset_t))) ourset_t();
+ luaL_getmetatable(L, "iputils.ipset");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int l_ipset_gc(lua_State* L)
+{
+ ourset_t*ourset = (ourset_t*)luaL_checkudata(L, 1, "iputils.ipset");
+ ourset->~ourset_t();
+ return 0;
+}
+
+static const struct luaL_Reg ipset_methods[]={
+ {"__index", l_ipset_index},
+ {"__newindex", l_ipset_newindex},
+ {"__gc", l_ipset_gc},
+ {NULL, NULL}
+};
+
+////////////////////////////////////////////////////
+
+
+static int l_netmask_tostring(lua_State* L)
+{
+ Netmask* nm = (Netmask*)luaL_checkudata(L, 1, "iputils.netmask");
+ string ret=nm->toString();
+ lua_pushstring(L, ret.c_str());
+ return 1;
+}
+
+static int l_new_netmask(lua_State* L)
+{
+ /*Netmask* nm=*/ new(lua_newuserdata(L, sizeof(Netmask))) Netmask(luaL_checkstring(L, 1));
+ luaL_getmetatable(L, "iputils.netmask");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int l_netmask_match(lua_State* L)
+{
+ Netmask* nm=(Netmask*)luaL_checkudata(L, 1, "iputils.netmask");
+ ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca");
+ lua_pushboolean(L, nm->match(*ca1));
+ return 1;
+}
+
+static int l_netmask_gc(lua_State* L)
+{
+ Netmask* nm = (Netmask*)luaL_checkudata(L, 1, "iputils.netmask");
+ nm->~Netmask();
+ return 0;
+}
+
+static const struct luaL_Reg iputils_netmask_methods[]={
+ {"__tostring", l_netmask_tostring},
+ {"tostring", l_netmask_tostring},
+ {"match", l_netmask_match},
+ {"__gc", l_netmask_gc},
+ {NULL, NULL}
+};
+
+
+//////////////////////
+
+static int l_nmgroup_tostring(lua_State* L)
+{
+ NetmaskGroup* nmg = (NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup");
+
+ string ret=nmg->toString();
+ lua_pushstring(L, ret.c_str());
+ return 1;
+}
+
+static int l_new_nmgroup(lua_State* L)
+{
+ /*NetmaskGroup*nmg= */ new(lua_newuserdata(L, sizeof(NetmaskGroup))) NetmaskGroup();
+ luaL_getmetatable(L, "iputils.nmgroup");
+ lua_setmetatable(L, -2);
+ return 1;
+}
+
+static int l_nmgroup_match(lua_State* L)
+{
+ NetmaskGroup* nm=(NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup");
+ ComboAddress* ca1 = (ComboAddress*)luaL_checkudata(L, 2, "iputils.ca");
+ lua_pushboolean(L, nm->match(*ca1));
+ return 1;
+}
+
+static int l_nmgroup_add(lua_State* L)
+{
+ NetmaskGroup* nm=(NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup");
+ nm->addMask(luaL_checkstring(L, 2));
+ return 0;
+}
+
+
+static int l_nmgroup_gc(lua_State* L)
+{
+ NetmaskGroup* nm = (NetmaskGroup*)luaL_checkudata(L, 1, "iputils.nmgroup");
+ nm->~NetmaskGroup();
+ return 0;
+}
+
+static const struct luaL_Reg iputils_nmgroup_methods[]={
+ {"__tostring", l_nmgroup_tostring},
+ {"tostring", l_nmgroup_tostring},
+ {"match", l_nmgroup_match},
+ {"add", l_nmgroup_add},
+ {"__gc", l_nmgroup_gc},
+ {NULL, NULL}
+};
+
+////////////
+
+static const struct luaL_Reg iputils[]={
+ {"newca", l_new_ca},
+ {"newipset", l_newipset},
+ {"newnm", l_new_netmask},
+ {"newnmgroup", l_new_nmgroup},
+ {NULL, NULL}
+};
+
+
+extern "C" int luaopen_iputils(lua_State* L)
+{
+ luaL_newmetatable(L, "iputils.ca");
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_setfuncs(L, iputils_ca_methods, 0);
+
+ luaL_newmetatable(L, "iputils.ipset");
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_setfuncs(L, ipset_methods, 0);
+
+ luaL_newmetatable(L, "iputils.netmask");
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_setfuncs(L, iputils_netmask_methods, 0);
+
+ luaL_newmetatable(L, "iputils.nmgroup");
+ lua_pushvalue(L, -1);
+ lua_setfield(L, -2, "__index");
+ luaL_setfuncs(L, iputils_nmgroup_methods, 0);
+
+#if LUA_VERSION_NUM < 502
+ luaL_register(L, "iputils", iputils);
+#else
+ luaL_newlib(L, iputils);
+#endif
+ return 1;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "lua-pdns.hh"
+// #include "syncres.hh"
+
+
+#if !defined(HAVE_LUA)
+
+// stub implementation
+
+PowerDNSLua::PowerDNSLua(const std::string& fname)
+{
+ throw runtime_error("Lua support disabled");
+}
+
+
+PowerDNSLua::~PowerDNSLua()
+{
+
+}
+
+#else
+
+extern "C" {
+#undef L
+/* Include the Lua API header files. */
+#include <lua.h>
+#include <lauxlib.h>
+#include <lualib.h>
+}
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string>
+#include <vector>
+#include <stdexcept>
+#include "logger.hh"
+#include "namespaces.hh"
+#include "dnsparser.hh"
+#undef L
+
+bool netmaskMatchTable(lua_State* lua, const std::string& ip)
+{
+ lua_pushnil(lua); /* first key */
+ while (lua_next(lua, 2) != 0) {
+ string netmask=lua_tostring(lua, -1);
+ Netmask nm(netmask);
+ ComboAddress ca(ip);
+ lua_pop(lua, 1);
+
+ if(nm.match(ip))
+ return true;
+ }
+ return false;
+}
+
+static bool getFromTable(lua_State *lua, const std::string &key, std::string& value)
+{
+ lua_pushstring(lua, key.c_str()); // 4 is now '1'
+ lua_gettable(lua, -2); // replace by the first entry of our table we hope
+
+ bool ret=false;
+ if(!lua_isnil(lua, -1)) {
+ value = lua_tostring(lua, -1);
+ ret=true;
+ }
+ lua_pop(lua, 1);
+ return ret;
+}
+
+static bool getFromTable(lua_State *lua, const std::string &key, uint32_t& value)
+{
+ lua_pushstring(lua, key.c_str()); // 4 is now '1'
+ lua_gettable(lua, -2); // replace by the first entry of our table we hope
+
+ bool ret=false;
+
+ if(!lua_isnil(lua, -1)) {
+ value = (uint32_t)lua_tonumber(lua, -1);
+ ret=true;
+ }
+ lua_pop(lua, 1);
+ return ret;
+}
+
+
+void pushLuaTable(lua_State* lua, const vector<pair<string,string>>& table)
+{
+ lua_newtable(lua);
+ for(const auto& e : table) {
+ lua_pushstring(lua, e.second.c_str());
+ lua_setfield(lua, -2, e.first.c_str());
+ }
+}
+
+vector<pair<string,string>> getLuaTable(lua_State* lua, int index)
+{
+ vector<pair<string,string>> ret;
+ // Push another reference to the table on top of the stack (so we know
+ // where it is, and this function can work for negative, positive and
+ // pseudo indices
+ lua_pushvalue(lua, index);
+ // stack now contains: -1 => table
+ lua_pushnil(lua);
+ // stack now contains: -1 => nil; -2 => table
+ while (lua_next(lua, -2)) {
+ // stack now contains: -1 => value; -2 => key; -3 => table
+ // copy the key so that lua_tostring does not modify the original
+ lua_pushvalue(lua, -2);
+ // stack now contains: -1 => key; -2 => value; -3 => key; -4 => table
+ const char *key = lua_tostring(lua, -1);
+ const char *value = lua_tostring(lua, -2);
+ ret.push_back({key,value});
+ // pop value + copy of key, leaving original key
+ lua_pop(lua, 2);
+ // stack now contains: -1 => key; -2 => table
+ }
+ // stack now contains: -1 => table (when lua_next returns 0 it pops the key
+ // but does not push anything.)
+ // Pop table
+ lua_pop(lua, 1);
+ // Stack is now the same as it was on entry to this function
+ return ret;
+}
+
+
+void pushResourceRecordsTable(lua_State* lua, const vector<DNSRecord>& records)
+{
+ // make a table of tables
+ lua_newtable(lua);
+
+ int pos=0;
+ for(const auto& rr: records)
+ {
+ // row number, used by 'lua_settable' below
+ lua_pushnumber(lua, ++pos);
+ // "row" table
+ lua_newtable(lua);
+
+ lua_pushstring(lua, rr.d_name.toString().c_str());
+ lua_setfield(lua, -2, "qname"); // pushes value at the top of the stack to the table immediately below that (-1 = top, -2 is below)
+
+ lua_pushstring(lua, rr.d_content->getZoneRepresentation().c_str());
+ lua_setfield(lua, -2, "content");
+
+ lua_pushnumber(lua, rr.d_type);
+ lua_setfield(lua, -2, "qtype");
+
+ lua_pushnumber(lua, rr.d_ttl);
+ lua_setfield(lua, -2, "ttl");
+
+ lua_pushnumber(lua, rr.d_place);
+ lua_setfield(lua, -2, "place");
+
+ lua_pushnumber(lua, rr.d_class);
+ lua_setfield(lua, -2, "qclass");
+
+ lua_settable(lua, -3); // pushes the table we just built into the master table at position pushed above
+ }
+}
+// override the __index metatable under loglevels to return Logger::Error to account for nil accesses to the loglevels table
+int loglevels_index(lua_State* lua)
+{
+ lua_pushnumber(lua, Logger::Error);
+ return 1;
+}
+// push the loglevel subtable onto the stack that will eventually be the pdns table
+void pushSyslogSecurityLevelTable(lua_State* lua)
+{
+ lua_newtable(lua);
+// this function takes the global lua_state from the PowerDNSLua constructor and populates it with the syslog enums values
+ lua_pushnumber(lua, Logger::All);
+ lua_setfield(lua, -2, "All");
+ lua_pushnumber(lua, Logger::Alert);
+ lua_setfield(lua, -2, "Alert");
+ lua_pushnumber(lua, Logger::Critical);
+ lua_setfield(lua, -2, "Critical");
+ lua_pushnumber(lua, Logger::Error);
+ lua_setfield(lua, -2, "Error");
+ lua_pushnumber(lua, Logger::Warning);
+ lua_setfield(lua, -2, "Warning");
+ lua_pushnumber(lua, Logger::Notice);
+ lua_setfield(lua, -2, "Notice");
+ lua_pushnumber(lua, Logger::Info);
+ lua_setfield(lua, -2, "Info");
+ lua_pushnumber(lua, Logger::Debug);
+ lua_setfield(lua, -2, "Debug");
+ lua_pushnumber(lua, Logger::None);
+ lua_setfield(lua, -2, "None");
+ lua_createtable(lua, 0, 1);
+ lua_pushcfunction(lua, loglevels_index);
+ lua_setfield(lua, -2, "__index");
+ lua_setmetatable(lua, -2);
+}
+int getLuaTableLength(lua_State* lua, int depth)
+{
+#ifndef LUA_VERSION_NUM
+ return luaL_getn(lua, 2);
+#elif LUA_VERSION_NUM < 502
+ return lua_objlen(lua, 2);
+#else
+ return lua_rawlen(lua, 2);
+#endif
+}
+
+// expects a table at offset 2, and, importantly DOES NOT POP IT from the stack - only the contents
+void popResourceRecordsTable(lua_State *lua, const DNSName &query, vector<DNSRecord>& ret)
+{
+ /* get the result */
+ DNSRecord rr;
+ rr.d_name = query;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rr.d_ttl = 3600;
+
+ int tableLen = getLuaTableLength(lua, 2);
+
+ for(int n=1; n < tableLen + 1; ++n) {
+ lua_pushnumber(lua, n);
+ lua_gettable(lua, 2);
+
+ uint32_t tmpnum=0;
+ if(!getFromTable(lua, "qtype", tmpnum))
+ rr.d_type=QType::A;
+ else
+ rr.d_type=tmpnum;
+
+ if(!getFromTable(lua, "qclass", tmpnum))
+ rr.d_class = QClass::IN;
+ else {
+ rr.d_class = tmpnum;
+ }
+
+
+ string content;
+ getFromTable(lua, "content", content);
+ rr.d_content=shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.d_type, rr.d_class, content));
+
+ if(!getFromTable(lua, "ttl", rr.d_ttl))
+ rr.d_ttl=3600;
+
+ string qname;
+ if(getFromTable(lua, "qname", qname))
+ rr.d_name = DNSName(qname);
+ else
+ rr.d_name = query;
+
+ if(!getFromTable(lua, "place", tmpnum))
+ rr.d_place = DNSResourceRecord::ANSWER;
+ else {
+ rr.d_place = static_cast<DNSResourceRecord::Place>(tmpnum);
+ if(rr.d_place > DNSResourceRecord::ADDITIONAL)
+ rr.d_place = DNSResourceRecord::ADDITIONAL;
+ }
+
+
+ /* removes 'value'; keeps 'key' for next iteration */
+ lua_pop(lua, 1); // table
+
+ // cerr<<"Adding content '"<<rr.content<<"' with place "<<(int)rr.d_place<<" \n";
+ ret.push_back(rr);
+ }
+}
+
+extern "C" {
+
+int netmaskMatchLua(lua_State *lua)
+{
+ bool result=false;
+ if(lua_gettop(lua) >= 2) {
+ string ip=lua_tostring(lua, 1);
+ if(lua_istable(lua, 2)) {
+ result = netmaskMatchTable(lua, ip);
+ }
+ else {
+ for(int n=2 ; n <= lua_gettop(lua); ++n) {
+ string netmask=lua_tostring(lua, n);
+ Netmask nm(netmask);
+ ComboAddress ca(ip);
+
+ result = nm.match(ip);
+ if(result)
+ break;
+ }
+ }
+ }
+
+ lua_pushboolean(lua, result);
+ return 1;
+}
+
+int getLocalAddressLua(lua_State* lua)
+{
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
+ PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
+
+ lua_pushstring(lua, pl->getLocal().toString().c_str());
+ return 1;
+}
+
+// called by lua to indicate that this answer is 'variable' and should not be cached
+int setVariableLua(lua_State* lua)
+{
+ lua_getfield(lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
+ PowerDNSLua* pl = (PowerDNSLua*)lua_touserdata(lua, -1);
+ pl->setVariable();
+ return 0;
+}
+
+int logLua(lua_State *lua)
+{
+ // get # of arguments from the pdnslog() lua stack
+ // if it is 1, then the old pdnslog(msg) is used, which we keep for posterity and to prevent lua scripts from breaking
+ // if it is >= 2, then we process it as pdnslog(msg, urgencylevel) for more granular logging
+ int argc = lua_gettop(lua);
+ if(argc == 1) {
+ string message=lua_tostring(lua, 1);
+ theL()<<Logger::Error<<"From Lua script: "<<message<<endl;
+ } else if(argc >= 2) {
+ string message=lua_tostring(lua, 1);
+ int urgencylevel = lua_tonumber(lua, 2);
+ theL()<<urgencylevel<<" "<<message<<endl;
+ }
+ return 0;
+}
+}
+
+PowerDNSLua::PowerDNSLua(const std::string& fname)
+{
+ d_lua = luaL_newstate();
+
+ // create module iputils & load it
+#if LUA_VERSION_NUM < 502
+ luaopen_iputils(d_lua);
+#else
+ luaL_requiref(d_lua, "iputils", luaopen_iputils, 1);
+#endif
+
+ lua_pushcfunction(d_lua, netmaskMatchLua);
+ lua_setglobal(d_lua, "matchnetmask");
+
+ lua_pushcfunction(d_lua, logLua);
+ lua_setglobal(d_lua, "pdnslog");
+
+ lua_newtable(d_lua);
+
+ for(vector<QType::namenum>::const_iterator iter = QType::names.begin(); iter != QType::names.end(); ++iter) {
+ lua_pushnumber(d_lua, iter->second);
+ lua_setfield(d_lua, -2, iter->first.c_str());
+ }
+ lua_pushnumber(d_lua, 0);
+ lua_setfield(d_lua, -2, "NOERROR");
+ lua_pushnumber(d_lua, 1);
+ lua_setfield(d_lua, -2, "FORMERR");
+ lua_pushnumber(d_lua, 2);
+ lua_setfield(d_lua, -2, "SERVFAIL");
+ lua_pushnumber(d_lua, 3);
+ lua_setfield(d_lua, -2, "NXDOMAIN");
+ lua_pushnumber(d_lua, 4);
+ lua_setfield(d_lua, -2, "NOTIMP");
+ lua_pushnumber(d_lua, 5);
+ lua_setfield(d_lua, -2, "REFUSED");
+ // set syslog codes used by Logger/enum Urgency
+ pushSyslogSecurityLevelTable(d_lua);
+ lua_setfield(d_lua, -2, "loglevels");
+ lua_pushnumber(d_lua, PolicyDecision::PASS);
+ lua_setfield(d_lua, -2, "PASS");
+ lua_pushnumber(d_lua, PolicyDecision::DROP);
+ lua_setfield(d_lua, -2, "DROP");
+ lua_pushnumber(d_lua, PolicyDecision::TRUNCATE);
+ lua_setfield(d_lua, -2, "TRUNCATE");
+
+ lua_setglobal(d_lua, "pdns");
+
+#ifndef LUA_VERSION_NUM
+ luaopen_base(d_lua);
+ luaopen_string(d_lua);
+
+ if(lua_dofile(d_lua, fname.c_str()))
+#else
+ luaL_openlibs(d_lua);
+ if(luaL_dofile(d_lua, fname.c_str()))
+#endif
+ throw runtime_error(string("Error loading Lua file '")+fname+"': "+ string(lua_isstring(d_lua, -1) ? lua_tostring(d_lua, -1) : "unknown error"));
+
+ lua_settop(d_lua, 0);
+
+ lua_pushcfunction(d_lua, setVariableLua);
+ lua_setglobal(d_lua, "setvariable");
+
+ lua_pushcfunction(d_lua, getLocalAddressLua);
+ lua_setglobal(d_lua, "getlocaladdress");
+
+ lua_pushlightuserdata(d_lua, (void*)this);
+ lua_setfield(d_lua, LUA_REGISTRYINDEX, "__PowerDNSLua");
+}
+
+bool PowerDNSLua::getFromTable(const std::string& key, std::string& value)
+{
+ return ::getFromTable(d_lua, key, value);
+}
+
+bool PowerDNSLua::getFromTable(const std::string& key, uint32_t& value)
+{
+ return ::getFromTable(d_lua, key, value);
+}
+
+PowerDNSLua::~PowerDNSLua()
+{
+ lua_close(d_lua);
+}
+
+#if 0
+void luaStackDump (lua_State *Lua) {
+ int i;
+ int top = lua_gettop(Lua);
+ for (i = 1; i <= top; i++) { /* repeat for each level */
+ int t = lua_type(Lua, i);
+ switch (t) {
+
+ case LUA_TSTRING: /* strings */
+ printf("`%s'", lua_tostring(Lua, i));
+ break;
+
+ case LUA_TBOOLEAN: /* booleans */
+ printf(lua_toboolean(Lua, i) ? "true" : "false");
+ break;
+
+ case LUA_TNUMBER: /* numbers */
+ printf("%g", lua_tonumber(Lua, i));
+ break;
+
+ default: /* other values */
+ printf("%s", lua_typename(Lua, t));
+ break;
+
+ }
+ printf(" "); /* put a separator */
+ }
+ printf("\n"); /* end the listing */
+}
+#endif
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_LUA_PDNS_HH
+#define PDNS_LUA_PDNS_HH
+
+#include "dns.hh"
+#include "iputils.hh"
+struct lua_State;
+
+class PowerDNSLua
+{
+public:
+ explicit PowerDNSLua(const std::string& fname);
+ ~PowerDNSLua();
+ void reload();
+ ComboAddress getLocal()
+ {
+ return d_local;
+ }
+
+ void setVariable()
+ {
+ d_variable=true;
+ }
+
+protected: // FIXME?
+ lua_State* d_lua;
+ bool passthrough(const string& func, const ComboAddress& remote,const ComboAddress& local, const string& query, const QType& qtype, vector<DNSResourceRecord>& ret, int& res, bool* variable);
+ bool getFromTable(const std::string& key, std::string& value);
+ bool getFromTable(const std::string& key, uint32_t& value);
+
+ ComboAddress d_local;
+ bool d_failed;
+ bool d_variable;
+};
+
+void pushResourceRecordsTable(lua_State* lua, const vector<DNSRecord>& records);
+void popResourceRecordsTable(lua_State *lua, const DNSName &query, vector<DNSRecord>& ret);
+void pushSyslogSecurityLevelTable(lua_State *lua);
+int getLuaTableLength(lua_State* lua, int depth);
+std::vector<std::pair<std::string, std::string>> getLuaTable(lua_State* lua, int index=0);
+void pushLuaTable(lua_State* lua, const vector<pair<string,string>>& table);
+void luaStackDump (lua_State *lua);
+extern "C" int luaopen_iputils(lua_State*);
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include <errno.h>
+#include "communicator.hh"
+#include <set>
+#include <boost/utility.hpp>
+
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "packethandler.hh"
+#include "nameserver.hh"
+#include "resolver.hh"
+#include "logger.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include "packetcache.hh"
+#include "base64.hh"
+#include "namespaces.hh"
+
+
+void CommunicatorClass::queueNotifyDomain(const DNSName &domain, UeberBackend *B)
+{
+ bool hasQueuedItem=false;
+ set<string> nsset, ips;
+ DNSResourceRecord rr;
+ FindNS fns;
+
+ if (d_onlyNotify.size()) {
+ B->lookup(QType(QType::NS),domain);
+ while(B->get(rr))
+ nsset.insert(rr.content);
+
+ for(set<string>::const_iterator j=nsset.begin();j!=nsset.end();++j) {
+ vector<string> nsips=fns.lookup(DNSName(*j), B);
+ if(nsips.empty())
+ L<<Logger::Warning<<"Unable to queue notification of domain '"<<domain<<"': nameservers do not resolve!"<<endl;
+ else
+ for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
+ const ComboAddress caIp(*k, 53);
+ if(!d_preventSelfNotification || !AddressIsUs(caIp)) {
+ if(!d_onlyNotify.match(&caIp))
+ L<<Logger::Info<<"Skipped notification of domain '"<<domain<<"' to "<<*j<<" because it does not match only-notify."<<endl;
+ else
+ ips.insert(caIp.toStringWithPort());
+ }
+ }
+ }
+
+ for(set<string>::const_iterator j=ips.begin();j!=ips.end();++j) {
+ L<<Logger::Warning<<"Queued notification of domain '"<<domain<<"' to "<<*j<<endl;
+ d_nq.add(domain,*j);
+ hasQueuedItem=true;
+ }
+ }
+
+ set<string> alsoNotify(d_alsoNotify);
+ B->alsoNotifies(domain, &alsoNotify);
+
+ for(set<string>::const_iterator j=alsoNotify.begin();j!=alsoNotify.end();++j) {
+ try {
+ const ComboAddress caIp(*j, 53);
+ L<<Logger::Warning<<"Queued also-notification of domain '"<<domain<<"' to "<<caIp.toStringWithPort()<<endl;
+ if (!ips.count(caIp.toStringWithPort())) {
+ ips.insert(caIp.toStringWithPort());
+ d_nq.add(domain, caIp.toStringWithPort());
+ }
+ hasQueuedItem=true;
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Warning<<"Unparseable IP in ALSO-NOTIFY metadata of domain '"<<domain<<"'. Warning: "<<e.reason<<endl;
+ }
+ }
+
+ if (!hasQueuedItem)
+ L<<Logger::Warning<<"Request to queue notification for domain '"<<domain<<"' was processed, but no valid nameservers or ALSO-NOTIFYs found. Not notifying!"<<endl;
+}
+
+
+bool CommunicatorClass::notifyDomain(const DNSName &domain)
+{
+ DomainInfo di;
+ UeberBackend B;
+ if(!B.getDomainInfo(domain, di)) {
+ L<<Logger::Error<<"No such domain '"<<domain<<"' in our database"<<endl;
+ return false;
+ }
+ queueNotifyDomain(domain, &B);
+ // call backend and tell them we sent out the notification - even though that is premature
+ di.backend->setNotified(di.id, di.serial);
+
+ return true;
+}
+
+void NotificationQueue::dump()
+{
+ cerr<<"Waiting for notification responses: "<<endl;
+ for(NotificationRequest& nr : d_nqueue) {
+ cerr<<nr.domain<<", "<<nr.ip<<endl;
+ }
+}
+
+void CommunicatorClass::masterUpdateCheck(PacketHandler *P)
+{
+ if(!::arg().mustDo("master"))
+ return;
+
+ UeberBackend *B=P->getBackend();
+ vector<DomainInfo> cmdomains;
+ B->getUpdatedMasters(&cmdomains);
+
+ if(cmdomains.empty()) {
+ if(d_masterschanged)
+ L<<Logger::Warning<<"No master domains need notifications"<<endl;
+ d_masterschanged=false;
+ }
+ else {
+ d_masterschanged=true;
+ L<<Logger::Error<<cmdomains.size()<<" domain"<<(cmdomains.size()>1 ? "s" : "")<<" for which we are master need"<<
+ (cmdomains.size()>1 ? "" : "s")<<
+ " notifications"<<endl;
+ }
+
+ // figure out A records of everybody needing notification
+ // do this via the FindNS class, d_fns
+
+ for(vector<DomainInfo>::const_iterator i=cmdomains.begin();i!=cmdomains.end();++i) {
+ extern PacketCache PC;
+ PC.purgeExact(i->zone);
+ queueNotifyDomain(i->zone,P->getBackend());
+ i->backend->setNotified(i->id,i->serial);
+ }
+}
+
+time_t CommunicatorClass::doNotifications()
+{
+ ComboAddress from;
+ Utility::socklen_t fromlen;
+ char buffer[1500];
+ int sock;
+ ssize_t size;
+
+ // receive incoming notifications on the nonblocking socket and take them off the list
+ while(waitFor2Data(d_nsock4, d_nsock6, 0, 0, &sock) > 0) {
+ fromlen=sizeof(from);
+ size=recvfrom(sock,buffer,sizeof(buffer),0,(struct sockaddr *)&from,&fromlen);
+ if(size < 0)
+ break;
+ DNSPacket p(true);
+
+ p.setRemote(&from);
+
+ if(p.parse(buffer,(size_t)size)<0) {
+ L<<Logger::Warning<<"Unable to parse SOA notification answer from "<<p.getRemote()<<endl;
+ continue;
+ }
+
+ if(p.d.rcode)
+ L<<Logger::Warning<<"Received unsuccessful notification report for '"<<p.qdomain<<"' from "<<from.toStringWithPort()<<", error: "<<RCode::to_s(p.d.rcode)<<endl;
+
+ if(d_nq.removeIf(from.toStringWithPort(), p.d.id, p.qdomain))
+ L<<Logger::Warning<<"Removed from notification list: '"<<p.qdomain<<"' to "<<from.toStringWithPort()<<" "<< (p.d.rcode ? RCode::to_s(p.d.rcode) : "(was acknowledged)")<<endl;
+ else {
+ L<<Logger::Warning<<"Received spurious notify answer for '"<<p.qdomain<<"' from "<< from.toStringWithPort()<<endl;
+ //d_nq.dump();
+ }
+ }
+
+ // send out possible new notifications
+ DNSName domain;
+ string ip;
+ uint16_t id;
+
+ bool purged;
+ while(d_nq.getOne(domain, ip, &id, purged)) {
+ if(!purged) {
+ try {
+ ComboAddress remote(ip, 53); // default to 53
+ if((d_nsock6 < 0 && remote.sin4.sin_family == AF_INET6) ||
+ (d_nsock4 < 0 && remote.sin4.sin_family == AF_INET))
+ continue; // don't try to notify what we can't!
+ if(d_preventSelfNotification && AddressIsUs(remote))
+ continue;
+
+ sendNotification(remote.sin4.sin_family == AF_INET ? d_nsock4 : d_nsock6, domain, remote, id);
+ drillHole(domain, ip);
+ }
+ catch(ResolverException &re) {
+ L<<Logger::Error<<"Error trying to resolve '"<<ip<<"' for notifying '"<<domain<<"' to server: "<<re.reason<<endl;
+ }
+ }
+ else
+ L<<Logger::Error<<"Notification for "<<domain<<" to "<<ip<<" failed after retries"<<endl;
+ }
+
+ return d_nq.earliest();
+}
+
+void CommunicatorClass::sendNotification(int sock, const DNSName& domain, const ComboAddress& remote, uint16_t id)
+{
+ UeberBackend B;
+ vector<string> meta;
+ DNSName tsigkeyname;
+ DNSName tsigalgorithm;
+ string tsigsecret64;
+ string tsigsecret;
+
+ if (B.getDomainMetadata(domain, "TSIG-ALLOW-AXFR", meta) && meta.size() > 0) {
+ tsigkeyname = DNSName(meta[0]);
+ }
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, domain, QType::SOA, 1, Opcode::Notify);
+ pw.getHeader()->id = id;
+ pw.getHeader()->aa = true;
+
+ if (tsigkeyname.empty() == false) {
+ B.getTSIGKey(tsigkeyname, &tsigalgorithm, &tsigsecret64);
+ TSIGRecordContent trc;
+ if (tsigalgorithm.toStringNoDot() == "hmac-md5")
+ trc.d_algoName = DNSName(tsigalgorithm.toStringNoDot() + ".sig-alg.reg.int.");
+ else
+ trc.d_algoName = tsigalgorithm;
+ trc.d_time = time(0);
+ trc.d_fudge = 300;
+ trc.d_origID=ntohs(id);
+ trc.d_eRcode=0;
+ B64Decode(tsigsecret64, tsigsecret);
+ addTSIG(pw, &trc, tsigkeyname, tsigsecret, "", false);
+ }
+
+ if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
+ throw ResolverException("Unable to send notify to "+remote.toStringWithPort()+": "+stringerror());
+ }
+}
+
+void CommunicatorClass::drillHole(const DNSName &domain, const string &ip)
+{
+ Lock l(&d_holelock);
+ d_holes[make_pair(domain,ip)]=time(0);
+}
+
+bool CommunicatorClass::justNotified(const DNSName &domain, const string &ip)
+{
+ Lock l(&d_holelock);
+ if(d_holes.find(make_pair(domain,ip))==d_holes.end()) // no hole
+ return false;
+
+ if(d_holes[make_pair(domain,ip)]>time(0)-900) // recent hole
+ return true;
+
+ // do we want to purge this? XXX FIXME
+ return false;
+}
+
+void CommunicatorClass::makeNotifySockets()
+{
+ d_nsock4 = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
+ if(!::arg()["query-local-address6"].empty())
+ d_nsock6 = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
+ else
+ d_nsock6 = -1;
+}
+
+void CommunicatorClass::notify(const DNSName &domain, const string &ip)
+{
+ d_nq.add(domain, ip);
+ d_any_sem.post();
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef _MD5_H
+#define _MD5_H
+
+#include <string>
+#include <stdint.h>
+#include <openssl/md5.h>
+
+inline std::string pdns_md5sum(const std::string& input)
+{
+ unsigned char result[16] = {0};
+ MD5(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), result);
+ return std::string(result, result + sizeof result);
+}
+
+#endif /* md5.h */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sys/param.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <netdb.h>
+#include <sys/time.h>
+#include <time.h>
+#include <sys/resource.h>
+#include <netinet/in.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <fstream>
+#include "misc.hh"
+#include <vector>
+#include <sstream>
+#include <errno.h>
+#include <cstring>
+#include <iostream>
+#include <sys/types.h>
+#include <dirent.h>
+#include <algorithm>
+#include <boost/optional.hpp>
+#include <poll.h>
+#include <iomanip>
+#include <netinet/tcp.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include "pdnsexception.hh"
+#include <sys/types.h>
+#include <boost/algorithm/string.hpp>
+#include "iputils.hh"
+#include "dnsparser.hh"
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+
+bool g_singleThreaded;
+
+size_t writen2(int fd, const void *buf, size_t count)
+{
+ const char *ptr = (char*)buf;
+ const char *eptr = ptr + count;
+
+ ssize_t res;
+ while(ptr != eptr) {
+ res = ::write(fd, ptr, eptr - ptr);
+ if(res < 0) {
+ if (errno == EAGAIN)
+ throw std::runtime_error("used writen2 on non-blocking socket, got EAGAIN");
+ else
+ unixDie("failed in writen2");
+ }
+ else if (res == 0)
+ throw std::runtime_error("could not write all bytes, got eof in writen2");
+
+ ptr += (size_t) res;
+ }
+
+ return count;
+}
+
+size_t readn2(int fd, void* buffer, size_t len)
+{
+ size_t pos=0;
+ ssize_t res;
+ for(;;) {
+ res = read(fd, (char*)buffer + pos, len - pos);
+ if(res == 0)
+ throw runtime_error("EOF while reading message");
+ if(res < 0) {
+ if (errno == EAGAIN)
+ throw std::runtime_error("used readn2 on non-blocking socket, got EAGAIN");
+ else
+ unixDie("failed in readn2");
+ }
+
+ pos+=(size_t)res;
+ if(pos == len)
+ break;
+ }
+ return len;
+}
+
+size_t readn2WithTimeout(int fd, void* buffer, size_t len, int timeout)
+{
+ size_t pos = 0;
+ do {
+ ssize_t got = read(fd, (char *)buffer + pos, len - pos);
+ if (got > 0) {
+ pos += (size_t) got;
+ }
+ else if (got == 0) {
+ throw runtime_error("EOF while reading message");
+ }
+ else {
+ if (errno == EAGAIN) {
+ int res = waitForData(fd, timeout);
+ if (res > 0) {
+ /* there is data available */
+ }
+ else if (res == 0) {
+ throw runtime_error("Timeout while waiting for data to read");
+ } else {
+ throw runtime_error("Error while waiting for data to read");
+ }
+ }
+ else {
+ unixDie("failed in readn2WithTimeout");
+ }
+ }
+ }
+ while (pos < len);
+
+ return len;
+}
+
+size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout)
+{
+ size_t pos = 0;
+ do {
+ ssize_t written = write(fd, (char *)buffer + pos, len - pos);
+
+ if (written > 0) {
+ pos += (size_t) written;
+ }
+ else if (written == 0)
+ throw runtime_error("EOF while writing message");
+ else {
+ if (errno == EAGAIN) {
+ int res = waitForRWData(fd, false, timeout, 0);
+ if (res > 0) {
+ /* there is room available */
+ }
+ else if (res == 0) {
+ throw runtime_error("Timeout while waiting to write data");
+ } else {
+ throw runtime_error("Error while waiting for room to write data");
+ }
+ }
+ else {
+ unixDie("failed in write2WithTimeout");
+ }
+ }
+ }
+ while (pos < len);
+
+ return len;
+}
+
+string nowTime()
+{
+ time_t now = time(nullptr);
+ struct tm* tm = localtime(&now);
+ char buffer[30];
+ // YYYY-mm-dd HH:MM:SS TZOFF
+ strftime(buffer, sizeof(buffer), "%F %T %z", tm);
+ buffer[sizeof(buffer)-1] = '\0';
+ return buffer;
+}
+
+uint16_t getShort(const unsigned char *p)
+{
+ return p[0] * 256 + p[1];
+}
+
+
+uint16_t getShort(const char *p)
+{
+ return getShort((const unsigned char *)p);
+}
+
+uint32_t getLong(const unsigned char* p)
+{
+ return (p[0]<<24) + (p[1]<<16) + (p[2]<<8) + p[3];
+}
+
+uint32_t getLong(const char* p)
+{
+ return getLong((unsigned char *)p);
+}
+
+static bool ciEqual(const string& a, const string& b)
+{
+ if(a.size()!=b.size())
+ return false;
+
+ string::size_type pos=0, epos=a.size();
+ for(;pos < epos; ++pos)
+ if(dns_tolower(a[pos])!=dns_tolower(b[pos]))
+ return false;
+ return true;
+}
+
+/** does domain end on suffix? Is smart about "wwwds9a.nl" "ds9a.nl" not matching */
+static bool endsOn(const string &domain, const string &suffix)
+{
+ if( suffix.empty() || ciEqual(domain, suffix) )
+ return true;
+
+ if(domain.size()<=suffix.size())
+ return false;
+
+ string::size_type dpos=domain.size()-suffix.size()-1, spos=0;
+
+ if(domain[dpos++]!='.')
+ return false;
+
+ for(; dpos < domain.size(); ++dpos, ++spos)
+ if(dns_tolower(domain[dpos]) != dns_tolower(suffix[spos]))
+ return false;
+
+ return true;
+}
+
+/** strips a domain suffix from a domain, returns true if it stripped */
+bool stripDomainSuffix(string *qname, const string &domain)
+{
+ if(!endsOn(*qname, domain))
+ return false;
+
+ if(toLower(*qname)==toLower(domain))
+ *qname="@";
+ else {
+ if((*qname)[qname->size()-domain.size()-1]!='.')
+ return false;
+
+ qname->resize(qname->size()-domain.size()-1);
+ }
+ return true;
+}
+
+static void parseService4(const string &descr, ServiceTuple &st)
+{
+ vector<string>parts;
+ stringtok(parts,descr,":");
+ if(parts.empty())
+ throw PDNSException("Unable to parse '"+descr+"' as a service");
+ st.host=parts[0];
+ if(parts.size()>1)
+ st.port=pdns_stou(parts[1]);
+}
+
+static void parseService6(const string &descr, ServiceTuple &st)
+{
+ string::size_type pos=descr.find(']');
+ if(pos == string::npos)
+ throw PDNSException("Unable to parse '"+descr+"' as an IPv6 service");
+
+ st.host=descr.substr(1, pos-1);
+ if(pos + 2 < descr.length())
+ st.port=pdns_stou(descr.substr(pos+2));
+}
+
+
+void parseService(const string &descr, ServiceTuple &st)
+{
+ if(descr.empty())
+ throw PDNSException("Unable to parse '"+descr+"' as a service");
+
+ vector<string> parts;
+ stringtok(parts, descr, ":");
+
+ if(descr[0]=='[') {
+ parseService6(descr, st);
+ }
+ else if(descr[0]==':' || parts.size() > 2 || descr.find("::") != string::npos) {
+ st.host=descr;
+ }
+ else {
+ parseService4(descr, st);
+ }
+}
+
+// returns -1 in case if error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
+int waitForData(int fd, int seconds, int useconds)
+{
+ return waitForRWData(fd, true, seconds, useconds);
+}
+
+int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error, bool* disconnected)
+{
+ int ret;
+
+ struct pollfd pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = fd;
+
+ if(waitForRead)
+ pfd.events=POLLIN;
+ else
+ pfd.events=POLLOUT;
+
+ ret = poll(&pfd, 1, seconds * 1000 + useconds/1000);
+ if ( ret == -1 ) {
+ errno = ETIMEDOUT; // ???
+ }
+ else if (ret > 0) {
+ if (error && (pfd.revents & POLLERR)) {
+ *error = true;
+ }
+ if (disconnected && (pfd.revents & POLLHUP)) {
+ *disconnected = true;
+ }
+ }
+
+ return ret;
+}
+
+// returns -1 in case of error, 0 if no data is available, 1 if there is. In the first two cases, errno is set
+int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int*fd)
+{
+ int ret;
+
+ struct pollfd pfds[2];
+ memset(&pfds[0], 0, 2*sizeof(struct pollfd));
+ pfds[0].fd = fd1;
+ pfds[1].fd = fd2;
+
+ pfds[0].events= pfds[1].events = POLLIN;
+
+ int nsocks = 1 + (fd2 >= 0); // fd2 can optionally be -1
+
+ if(seconds >= 0)
+ ret = poll(pfds, nsocks, seconds * 1000 + useconds/1000);
+ else
+ ret = poll(pfds, nsocks, -1);
+ if(!ret || ret < 0)
+ return ret;
+
+ if((pfds[0].revents & POLLIN) && !(pfds[1].revents & POLLIN))
+ *fd = pfds[0].fd;
+ else if((pfds[1].revents & POLLIN) && !(pfds[0].revents & POLLIN))
+ *fd = pfds[1].fd;
+ else if(ret == 2) {
+ *fd = pfds[random()%2].fd;
+ }
+ else
+ *fd = -1; // should never happen
+
+ return 1;
+}
+
+
+string humanDuration(time_t passed)
+{
+ ostringstream ret;
+ if(passed<60)
+ ret<<passed<<" seconds";
+ else if(passed<3600)
+ ret<<std::setprecision(2)<<passed/60.0<<" minutes";
+ else if(passed<86400)
+ ret<<std::setprecision(3)<<passed/3600.0<<" hours";
+ else if(passed<(86400*30.41))
+ ret<<std::setprecision(3)<<passed/86400.0<<" days";
+ else
+ ret<<std::setprecision(3)<<passed/(86400*30.41)<<" months";
+
+ return ret.str();
+}
+
+DTime::DTime()
+{
+// set(); // saves lots of gettimeofday calls
+ d_set.tv_sec=d_set.tv_usec=0;
+}
+
+DTime::DTime(const DTime &dt)
+{
+ d_set=dt.d_set;
+}
+
+time_t DTime::time()
+{
+ return d_set.tv_sec;
+}
+
+const string unquotify(const string &item)
+{
+ if(item.size()<2)
+ return item;
+
+ string::size_type bpos=0, epos=item.size();
+
+ if(item[0]=='"')
+ bpos=1;
+
+ if(item[epos-1]=='"')
+ epos-=1;
+
+ return item.substr(bpos,epos-bpos);
+}
+
+void stripLine(string &line)
+{
+ string::size_type pos=line.find_first_of("\r\n");
+ if(pos!=string::npos) {
+ line.resize(pos);
+ }
+}
+
+string urlEncode(const string &text)
+{
+ string ret;
+ for(string::const_iterator i=text.begin();i!=text.end();++i)
+ if(*i==' ')ret.append("%20");
+ else ret.append(1,*i);
+ return ret;
+}
+
+string getHostname()
+{
+#ifndef MAXHOSTNAMELEN
+#define MAXHOSTNAMELEN 255
+#endif
+
+ char tmp[MAXHOSTNAMELEN];
+ if(gethostname(tmp, MAXHOSTNAMELEN))
+ return "UNKNOWN";
+
+ return tmp;
+}
+
+string itoa(int i)
+{
+ ostringstream o;
+ o<<i;
+ return o.str();
+}
+
+string uitoa(unsigned int i) // MSVC 6 doesn't grok overloading (un)signed
+{
+ ostringstream o;
+ o<<i;
+ return o.str();
+}
+
+string bitFlip(const string &str)
+{
+ string::size_type pos=0, epos=str.size();
+ string ret;
+ ret.reserve(epos);
+ for(;pos < epos; ++pos)
+ ret.append(1, ~str[pos]);
+ return ret;
+}
+
+string stringerror()
+{
+ return strerror(errno);
+}
+
+string netstringerror()
+{
+ return stringerror();
+}
+
+void cleanSlashes(string &str)
+{
+ string::const_iterator i;
+ string out;
+ for(i=str.begin();i!=str.end();++i) {
+ if(*i=='/' && i!=str.begin() && *(i-1)=='/')
+ continue;
+ out.append(1,*i);
+ }
+ str=out;
+}
+
+
+bool IpToU32(const string &str, uint32_t *ip)
+{
+ if(str.empty()) {
+ *ip=0;
+ return true;
+ }
+
+ struct in_addr inp;
+ if(inet_aton(str.c_str(), &inp)) {
+ *ip=inp.s_addr;
+ return true;
+ }
+ return false;
+}
+
+string U32ToIP(uint32_t val)
+{
+ char tmp[17];
+ snprintf(tmp, sizeof(tmp)-1, "%u.%u.%u.%u",
+ (val >> 24)&0xff,
+ (val >> 16)&0xff,
+ (val >> 8)&0xff,
+ (val )&0xff);
+ return tmp;
+}
+
+
+string makeHexDump(const string& str)
+{
+ char tmp[5];
+ string ret;
+ ret.reserve((int)(str.size()*2.2));
+
+ for(string::size_type n=0;n<str.size();++n) {
+ sprintf(tmp,"%02x ", (unsigned char)str[n]);
+ ret+=tmp;
+ }
+ return ret;
+}
+
+// shuffle, maintaining some semblance of order
+void shuffle(vector<DNSResourceRecord>& rrs)
+{
+ vector<DNSResourceRecord>::iterator first, second;
+ for(first=rrs.begin();first!=rrs.end();++first)
+ if(first->d_place==DNSResourceRecord::ANSWER && first->qtype.getCode() != QType::CNAME) // CNAME must come first
+ break;
+ for(second=first;second!=rrs.end();++second)
+ if(second->d_place!=DNSResourceRecord::ANSWER)
+ break;
+
+ if(second-first>1)
+ random_shuffle(first,second);
+
+ // now shuffle the additional records
+ for(first=second;first!=rrs.end();++first)
+ if(first->d_place==DNSResourceRecord::ADDITIONAL && first->qtype.getCode() != QType::CNAME) // CNAME must come first
+ break;
+ for(second=first;second!=rrs.end();++second)
+ if(second->d_place!=DNSResourceRecord::ADDITIONAL)
+ break;
+
+ if(second-first>1)
+ random_shuffle(first,second);
+
+ // we don't shuffle the rest
+}
+
+
+// shuffle, maintaining some semblance of order
+void shuffle(vector<DNSRecord>& rrs)
+{
+ vector<DNSRecord>::iterator first, second;
+ for(first=rrs.begin();first!=rrs.end();++first)
+ if(first->d_place==DNSResourceRecord::ANSWER && first->d_type != QType::CNAME) // CNAME must come first
+ break;
+ for(second=first;second!=rrs.end();++second)
+ if(second->d_place!=DNSResourceRecord::ANSWER || second->d_type == QType::RRSIG) // leave RRSIGs at the end
+ break;
+
+ if(second-first>1)
+ random_shuffle(first,second);
+
+ // now shuffle the additional records
+ for(first=second;first!=rrs.end();++first)
+ if(first->d_place==DNSResourceRecord::ADDITIONAL && first->d_type != QType::CNAME) // CNAME must come first
+ break;
+ for(second=first; second!=rrs.end(); ++second)
+ if(second->d_place!=DNSResourceRecord::ADDITIONAL)
+ break;
+
+ if(second-first>1)
+ random_shuffle(first,second);
+
+ // we don't shuffle the rest
+}
+
+static uint16_t mapTypesToOrder(uint16_t type)
+{
+ if(type == QType::CNAME)
+ return 0;
+ if(type == QType::RRSIG)
+ return 65535;
+ else
+ return 1;
+}
+
+// make sure rrs is sorted in d_place order to avoid surprises later
+// then shuffle the parts that desire shuffling
+void orderAndShuffle(vector<DNSRecord>& rrs)
+{
+ std::stable_sort(rrs.begin(), rrs.end(), [](const DNSRecord&a, const DNSRecord& b) {
+ return std::make_tuple(a.d_place, mapTypesToOrder(a.d_type)) < std::make_tuple(b.d_place, mapTypesToOrder(b.d_type));
+ });
+ shuffle(rrs);
+}
+
+void normalizeTV(struct timeval& tv)
+{
+ if(tv.tv_usec > 1000000) {
+ ++tv.tv_sec;
+ tv.tv_usec-=1000000;
+ }
+ else if(tv.tv_usec < 0) {
+ --tv.tv_sec;
+ tv.tv_usec+=1000000;
+ }
+}
+
+const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs)
+{
+ struct timeval ret;
+ ret.tv_sec=lhs.tv_sec + rhs.tv_sec;
+ ret.tv_usec=lhs.tv_usec + rhs.tv_usec;
+ normalizeTV(ret);
+ return ret;
+}
+
+const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs)
+{
+ struct timeval ret;
+ ret.tv_sec=lhs.tv_sec - rhs.tv_sec;
+ ret.tv_usec=lhs.tv_usec - rhs.tv_usec;
+ normalizeTV(ret);
+ return ret;
+}
+
+pair<string, string> splitField(const string& inp, char sepa)
+{
+ pair<string, string> ret;
+ string::size_type cpos=inp.find(sepa);
+ if(cpos==string::npos)
+ ret.first=inp;
+ else {
+ ret.first=inp.substr(0, cpos);
+ ret.second=inp.substr(cpos+1);
+ }
+ return ret;
+}
+
+int logFacilityToLOG(unsigned int facility)
+{
+ switch(facility) {
+ case 0:
+ return LOG_LOCAL0;
+ case 1:
+ return(LOG_LOCAL1);
+ case 2:
+ return(LOG_LOCAL2);
+ case 3:
+ return(LOG_LOCAL3);
+ case 4:
+ return(LOG_LOCAL4);
+ case 5:
+ return(LOG_LOCAL5);
+ case 6:
+ return(LOG_LOCAL6);
+ case 7:
+ return(LOG_LOCAL7);
+ default:
+ return -1;
+ }
+}
+
+string stripDot(const string& dom)
+{
+ if(dom.empty())
+ return dom;
+
+ if(dom[dom.size()-1]!='.')
+ return dom;
+
+ return dom.substr(0,dom.size()-1);
+}
+
+
+string labelReverse(const std::string& qname)
+{
+ if(qname.empty())
+ return qname;
+
+ bool dotName = qname.find('.') != string::npos;
+
+ vector<string> labels;
+ stringtok(labels, qname, ". ");
+ if(labels.size()==1)
+ return qname;
+
+ string ret; // vv const_reverse_iter http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11729
+ for(vector<string>::reverse_iterator iter = labels.rbegin(); iter != labels.rend(); ++iter) {
+ if(iter != labels.rbegin())
+ ret.append(1, dotName ? ' ' : '.');
+ ret+=*iter;
+ }
+ return ret;
+}
+
+// do NOT feed trailing dots!
+// www.powerdns.com, powerdns.com -> www
+string makeRelative(const std::string& fqdn, const std::string& zone)
+{
+ if(zone.empty())
+ return fqdn;
+ if(toLower(fqdn) != toLower(zone))
+ return fqdn.substr(0, fqdn.size() - zone.length() - 1); // strip domain name
+ return "";
+}
+
+string dotConcat(const std::string& a, const std::string &b)
+{
+ if(a.empty() || b.empty())
+ return a+b;
+ else
+ return a+"."+b;
+}
+
+int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret)
+{
+ if(addr.empty())
+ return -1;
+ string ourAddr(addr);
+ bool portSet = false;
+ unsigned int port;
+ if(addr[0]=='[') { // [::]:53 style address
+ string::size_type pos = addr.find(']');
+ if(pos == string::npos || pos + 2 > addr.size() || addr[pos+1]!=':')
+ return -1;
+ ourAddr.assign(addr.c_str() + 1, pos-1);
+ try {
+ port = pdns_stou(addr.substr(pos+2));
+ portSet = true;
+ }
+ catch(std::out_of_range) {
+ return -1;
+ }
+ }
+ ret->sin6_scope_id=0;
+ ret->sin6_family=AF_INET6;
+
+ if(inet_pton(AF_INET6, ourAddr.c_str(), (void*)&ret->sin6_addr) != 1) {
+ struct addrinfo* res;
+ struct addrinfo hints;
+ memset(&hints, 0, sizeof(hints));
+
+ hints.ai_family = AF_INET6;
+ hints.ai_flags = AI_NUMERICHOST;
+
+ int error;
+ if((error=getaddrinfo(ourAddr.c_str(), 0, &hints, &res))) { // this is correct
+ return -1;
+ }
+
+ memcpy(ret, res->ai_addr, res->ai_addrlen);
+ freeaddrinfo(res);
+ }
+
+ if(portSet) {
+ if(port > 65535)
+ return -1;
+
+ ret->sin6_port = htons(port);
+ }
+
+ return 0;
+}
+
+int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret)
+{
+ if(str.empty()) {
+ return -1;
+ }
+ struct in_addr inp;
+
+ string::size_type pos = str.find(':');
+ if(pos == string::npos) { // no port specified, not touching the port
+ if(inet_aton(str.c_str(), &inp)) {
+ ret->sin_addr.s_addr=inp.s_addr;
+ return 0;
+ }
+ return -1;
+ }
+ if(!*(str.c_str() + pos + 1)) // trailing :
+ return -1;
+
+ char *eptr = (char*)str.c_str() + str.size();
+ int port = strtol(str.c_str() + pos + 1, &eptr, 10);
+ if (port < 0 || port > 65535)
+ return -1;
+
+ if(*eptr)
+ return -1;
+
+ ret->sin_port = htons(port);
+ if(inet_aton(str.substr(0, pos).c_str(), &inp)) {
+ ret->sin_addr.s_addr=inp.s_addr;
+ return 0;
+ }
+ return -1;
+}
+
+int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret)
+{
+ if (path.empty())
+ return -1;
+
+ memset(ret, 0, sizeof(struct sockaddr_un));
+ ret->sun_family = AF_UNIX;
+ if (path.length() >= sizeof(ret->sun_path))
+ return -1;
+
+ path.copy(ret->sun_path, sizeof(ret->sun_path), 0);
+ return 0;
+}
+
+//! read a line of text from a FILE* to a std::string, returns false on 'no data'
+bool stringfgets(FILE* fp, std::string& line)
+{
+ char buffer[1024];
+ line.clear();
+
+ do {
+ if(!fgets(buffer, sizeof(buffer), fp))
+ return !line.empty();
+
+ line.append(buffer);
+ } while(!strchr(buffer, '\n'));
+ return true;
+}
+
+bool readFileIfThere(const char* fname, std::string* line)
+{
+ line->clear();
+ FILE* fp = fopen(fname, "r");
+ if(!fp)
+ return false;
+ stringfgets(fp, *line);
+ fclose(fp);
+ return true;
+}
+
+Regex::Regex(const string &expr)
+{
+ if(regcomp(&d_preg, expr.c_str(), REG_ICASE|REG_NOSUB|REG_EXTENDED))
+ throw PDNSException("Regular expression did not compile");
+}
+
+// if you end up here because valgrind told you were are doing something wrong
+// with msgh->msg_controllen, please refer to https://github.com/PowerDNS/pdns/pull/3962
+// first.
+void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source, int itfIndex)
+{
+ struct cmsghdr *cmsg = NULL;
+
+ if(source->sin4.sin_family == AF_INET6) {
+ struct in6_pktinfo *pkt;
+
+ msgh->msg_control = cmsgbuf;
+ msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
+
+ cmsg = CMSG_FIRSTHDR(msgh);
+ cmsg->cmsg_level = IPPROTO_IPV6;
+ cmsg->cmsg_type = IPV6_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
+
+ pkt = (struct in6_pktinfo *) CMSG_DATA(cmsg);
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->ipi6_addr = source->sin6.sin6_addr;
+ pkt->ipi6_ifindex = itfIndex;
+ }
+ else {
+#ifdef IP_PKTINFO
+ struct in_pktinfo *pkt;
+
+ msgh->msg_control = cmsgbuf;
+ msgh->msg_controllen = CMSG_SPACE(sizeof(*pkt));
+
+ cmsg = CMSG_FIRSTHDR(msgh);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_PKTINFO;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*pkt));
+
+ pkt = (struct in_pktinfo *) CMSG_DATA(cmsg);
+ memset(pkt, 0, sizeof(*pkt));
+ pkt->ipi_spec_dst = source->sin4.sin_addr;
+ pkt->ipi_ifindex = itfIndex;
+#endif
+#ifdef IP_SENDSRCADDR
+ struct in_addr *in;
+
+ msgh->msg_control = cmsgbuf;
+ msgh->msg_controllen = CMSG_SPACE(sizeof(*in));
+
+ cmsg = CMSG_FIRSTHDR(msgh);
+ cmsg->cmsg_level = IPPROTO_IP;
+ cmsg->cmsg_type = IP_SENDSRCADDR;
+ cmsg->cmsg_len = CMSG_LEN(sizeof(*in));
+
+ in = (struct in_addr *) CMSG_DATA(cmsg);
+ *in = source->sin4.sin_addr;
+#endif
+ }
+}
+
+unsigned int getFilenumLimit(bool hardOrSoft)
+{
+ struct rlimit rlim;
+ if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ unixDie("Requesting number of available file descriptors");
+ return hardOrSoft ? rlim.rlim_max : rlim.rlim_cur;
+}
+
+void setFilenumLimit(unsigned int lim)
+{
+ struct rlimit rlim;
+
+ if(getrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ unixDie("Requesting number of available file descriptors");
+ rlim.rlim_cur=lim;
+ if(setrlimit(RLIMIT_NOFILE, &rlim) < 0)
+ unixDie("Setting number of available file descriptors");
+}
+
+#define burtlemix(a,b,c) \
+{ \
+ a -= b; a -= c; a ^= (c>>13); \
+ b -= c; b -= a; b ^= (a<<8); \
+ c -= a; c -= b; c ^= (b>>13); \
+ a -= b; a -= c; a ^= (c>>12); \
+ b -= c; b -= a; b ^= (a<<16); \
+ c -= a; c -= b; c ^= (b>>5); \
+ a -= b; a -= c; a ^= (c>>3); \
+ b -= c; b -= a; b ^= (a<<10); \
+ c -= a; c -= b; c ^= (b>>15); \
+}
+
+uint32_t burtle(const unsigned char* k, uint32_t length, uint32_t initval)
+{
+ uint32_t a,b,c,len;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = initval; /* the previous hash value */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 12) {
+ a += (k[0] +((uint32_t)k[1]<<8) +((uint32_t)k[2]<<16) +((uint32_t)k[3]<<24));
+ b += (k[4] +((uint32_t)k[5]<<8) +((uint32_t)k[6]<<16) +((uint32_t)k[7]<<24));
+ c += (k[8] +((uint32_t)k[9]<<8) +((uint32_t)k[10]<<16)+((uint32_t)k[11]<<24));
+ burtlemix(a,b,c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += length;
+ switch(len) { /* all the case statements fall through */
+ case 11: c+=((uint32_t)k[10]<<24);
+ case 10: c+=((uint32_t)k[9]<<16);
+ case 9 : c+=((uint32_t)k[8]<<8);
+ /* the first byte of c is reserved for the length */
+ case 8 : b+=((uint32_t)k[7]<<24);
+ case 7 : b+=((uint32_t)k[6]<<16);
+ case 6 : b+=((uint32_t)k[5]<<8);
+ case 5 : b+=k[4];
+ case 4 : a+=((uint32_t)k[3]<<24);
+ case 3 : a+=((uint32_t)k[2]<<16);
+ case 2 : a+=((uint32_t)k[1]<<8);
+ case 1 : a+=k[0];
+ /* case 0: nothing left to add */
+ }
+ burtlemix(a,b,c);
+ /*-------------------------------------------- report the result */
+ return c;
+}
+
+uint32_t burtleCI(const unsigned char* k, uint32_t length, uint32_t initval)
+{
+ uint32_t a,b,c,len;
+
+ /* Set up the internal state */
+ len = length;
+ a = b = 0x9e3779b9; /* the golden ratio; an arbitrary value */
+ c = initval; /* the previous hash value */
+
+ /*---------------------------------------- handle most of the key */
+ while (len >= 12) {
+ a += (dns_tolower(k[0]) +((uint32_t)dns_tolower(k[1])<<8) +((uint32_t)dns_tolower(k[2])<<16) +((uint32_t)dns_tolower(k[3])<<24));
+ b += (dns_tolower(k[4]) +((uint32_t)dns_tolower(k[5])<<8) +((uint32_t)dns_tolower(k[6])<<16) +((uint32_t)dns_tolower(k[7])<<24));
+ c += (dns_tolower(k[8]) +((uint32_t)dns_tolower(k[9])<<8) +((uint32_t)dns_tolower(k[10])<<16)+((uint32_t)dns_tolower(k[11])<<24));
+ burtlemix(a,b,c);
+ k += 12; len -= 12;
+ }
+
+ /*------------------------------------- handle the last 11 bytes */
+ c += length;
+ switch(len) { /* all the case statements fall through */
+ case 11: c+=((uint32_t)dns_tolower(k[10])<<24);
+ case 10: c+=((uint32_t)dns_tolower(k[9])<<16);
+ case 9 : c+=((uint32_t)dns_tolower(k[8])<<8);
+ /* the first byte of c is reserved for the length */
+ case 8 : b+=((uint32_t)dns_tolower(k[7])<<24);
+ case 7 : b+=((uint32_t)dns_tolower(k[6])<<16);
+ case 6 : b+=((uint32_t)dns_tolower(k[5])<<8);
+ case 5 : b+=dns_tolower(k[4]);
+ case 4 : a+=((uint32_t)dns_tolower(k[3])<<24);
+ case 3 : a+=((uint32_t)dns_tolower(k[2])<<16);
+ case 2 : a+=((uint32_t)dns_tolower(k[1])<<8);
+ case 1 : a+=dns_tolower(k[0]);
+ /* case 0: nothing left to add */
+ }
+ burtlemix(a,b,c);
+ /*-------------------------------------------- report the result */
+ return c;
+}
+
+
+bool setSocketTimestamps(int fd)
+{
+#ifdef SO_TIMESTAMP
+ int on=1;
+ return setsockopt(fd, SOL_SOCKET, SO_TIMESTAMP, (char*)&on, sizeof(on)) == 0;
+#endif
+ return true; // we pretend this happened.
+}
+
+bool setTCPNoDelay(int sock)
+{
+ int flag = 1;
+ return setsockopt(sock, /* socket affected */
+ IPPROTO_TCP, /* set option at TCP level */
+ TCP_NODELAY, /* name of option */
+ (char *) &flag, /* the cast is historical cruft */
+ sizeof(flag)) == 0; /* length of option value */
+}
+
+
+bool setNonBlocking(int sock)
+{
+ int flags=fcntl(sock,F_GETFL,0);
+ if(flags<0 || fcntl(sock, F_SETFL,flags|O_NONBLOCK) <0)
+ return false;
+ return true;
+}
+
+bool setBlocking(int sock)
+{
+ int flags=fcntl(sock,F_GETFL,0);
+ if(flags<0 || fcntl(sock, F_SETFL,flags&(~O_NONBLOCK)) <0)
+ return false;
+ return true;
+}
+
+bool isNonBlocking(int sock)
+{
+ int flags=fcntl(sock,F_GETFL,0);
+ return flags & O_NONBLOCK;
+}
+
+// Closes a socket.
+int closesocket( int socket )
+{
+ int ret=::close(socket);
+ if(ret < 0 && errno == ECONNRESET) // see ticket 192, odd BSD behaviour
+ return 0;
+ if(ret < 0)
+ throw PDNSException("Error closing socket: "+stringerror());
+ return ret;
+}
+
+bool setCloseOnExec(int sock)
+{
+ int flags=fcntl(sock,F_GETFD,0);
+ if(flags<0 || fcntl(sock, F_SETFD,flags|FD_CLOEXEC) <0)
+ return false;
+ return true;
+}
+
+string getMACAddress(const ComboAddress& ca)
+{
+ string ret;
+#ifdef __linux__
+ ifstream ifs("/proc/net/arp");
+ if(!ifs)
+ return ret;
+ string line;
+ string match=ca.toString()+' ';
+ while(getline(ifs, line)) {
+ if(boost::starts_with(line, match)) {
+ vector<string> parts;
+ stringtok(parts, line, " \n\t\r");
+ if(parts.size() < 4)
+ return ret;
+ unsigned int tmp[6];
+ sscanf(parts[3].c_str(), "%02x:%02x:%02x:%02x:%02x:%02x", tmp, tmp+1, tmp+2, tmp+3, tmp+4, tmp+5);
+ for(int i = 0 ; i< 6 ; ++i)
+ ret.append(1, (char)tmp[i]);
+ return ret;
+ }
+ }
+#endif
+ return ret;
+}
+
+uint64_t udpErrorStats(const std::string& str)
+{
+#ifdef __linux__
+ ifstream ifs("/proc/net/snmp");
+ if(!ifs)
+ return 0;
+ string line;
+ vector<string> parts;
+ while(getline(ifs,line)) {
+ if(boost::starts_with(line, "Udp: ") && isdigit(line[5])) {
+ stringtok(parts, line, " \n\t\r");
+ if(parts.size() < 7)
+ break;
+ if(str=="udp-rcvbuf-errors")
+ return std::stoull(parts[5]);
+ else if(str=="udp-sndbuf-errors")
+ return std::stoull(parts[6]);
+ else if(str=="udp-noport-errors")
+ return std::stoull(parts[2]);
+ else if(str=="udp-in-errors")
+ return std::stoull(parts[3]);
+ else
+ return 0;
+ }
+ }
+#endif
+ return 0;
+}
+
+bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum)
+{
+ if (algoName == DNSName("hmac-md5.sig-alg.reg.int") || algoName == DNSName("hmac-md5"))
+ algoEnum = TSIG_MD5;
+ else if (algoName == DNSName("hmac-sha1"))
+ algoEnum = TSIG_SHA1;
+ else if (algoName == DNSName("hmac-sha224"))
+ algoEnum = TSIG_SHA224;
+ else if (algoName == DNSName("hmac-sha256"))
+ algoEnum = TSIG_SHA256;
+ else if (algoName == DNSName("hmac-sha384"))
+ algoEnum = TSIG_SHA384;
+ else if (algoName == DNSName("hmac-sha512"))
+ algoEnum = TSIG_SHA512;
+ else if (algoName == DNSName("gss-tsig"))
+ algoEnum = TSIG_GSS;
+ else {
+ return false;
+ }
+ return true;
+}
+
+DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum)
+{
+ switch(algoEnum) {
+ case TSIG_MD5: return DNSName("hmac-md5.sig-alg.reg.int.");
+ case TSIG_SHA1: return DNSName("hmac-sha1.");
+ case TSIG_SHA224: return DNSName("hmac-sha224.");
+ case TSIG_SHA256: return DNSName("hmac-sha256.");
+ case TSIG_SHA384: return DNSName("hmac-sha384.");
+ case TSIG_SHA512: return DNSName("hmac-sha512.");
+ case TSIG_GSS: return DNSName("gss-tsig.");
+ }
+ throw PDNSException("getTSIGAlgoName does not understand given algorithm, please fix!");
+}
+
+uint64_t getOpenFileDescriptors(const std::string&)
+{
+#ifdef __linux__
+ DIR* dirhdl=opendir(("/proc/"+std::to_string(getpid())+"/fd/").c_str());
+ if(!dirhdl)
+ return 0;
+
+ struct dirent *entry;
+ int ret=0;
+ while((entry = readdir(dirhdl))) {
+ uint32_t num;
+ try {
+ num = pdns_stou(entry->d_name);
+ } catch (...) {
+ continue; // was not a number.
+ }
+ if(std::to_string(num) == entry->d_name)
+ ret++;
+ }
+ closedir(dirhdl);
+ return ret;
+
+#else
+ return 0;
+#endif
+}
+
+uint64_t getRealMemoryUsage(const std::string&)
+{
+#ifdef __linux__
+ ifstream ifs("/proc/"+std::to_string(getpid())+"/smaps");
+ if(!ifs)
+ return 0;
+ string line;
+ uint64_t bytes=0;
+ string header("Private_Dirty:");
+ while(getline(ifs, line)) {
+ if(boost::starts_with(line, header)) {
+ bytes += std::stoull(line.substr(header.length() + 1))*1024;
+ }
+ }
+ return bytes;
+#else
+ return 0;
+#endif
+}
+
+uint64_t getCPUTimeUser(const std::string&)
+{
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ return (ru.ru_utime.tv_sec*1000ULL + ru.ru_utime.tv_usec/1000);
+}
+
+uint64_t getCPUTimeSystem(const std::string&)
+{
+ struct rusage ru;
+ getrusage(RUSAGE_SELF, &ru);
+ return (ru.ru_stime.tv_sec*1000ULL + ru.ru_stime.tv_usec/1000);
+}
+
+double DiffTime(const struct timespec& first, const struct timespec& second)
+{
+ int seconds=second.tv_sec - first.tv_sec;
+ int nseconds=second.tv_nsec - first.tv_nsec;
+
+ if(nseconds < 0) {
+ seconds-=1;
+ nseconds+=1000000000;
+ }
+ return seconds + nseconds/1000000000.0;
+}
+
+double DiffTime(const struct timeval& first, const struct timeval& second)
+{
+ int seconds=second.tv_sec - first.tv_sec;
+ int useconds=second.tv_usec - first.tv_usec;
+
+ if(useconds < 0) {
+ seconds-=1;
+ useconds+=1000000;
+ }
+ return seconds + useconds/1000000.0;
+}
+
+uid_t strToUID(const string &str)
+{
+ uid_t result = 0;
+ const char * cstr = str.c_str();
+ struct passwd * pwd = getpwnam(cstr);
+
+ if (pwd == NULL) {
+ long long val;
+
+ try {
+ val = stoll(str);
+ }
+ catch(std::exception& e) {
+ throw runtime_error((boost::format("Error: Unable to parse user ID %s") % cstr).str() );
+ }
+
+ if (val < std::numeric_limits<uid_t>::min() || val > std::numeric_limits<uid_t>::max()) {
+ throw runtime_error((boost::format("Error: Unable to parse user ID %s") % cstr).str() );
+ }
+
+ result = static_cast<uid_t>(val);
+ }
+ else {
+ result = pwd->pw_uid;
+ }
+
+ return result;
+}
+
+gid_t strToGID(const string &str)
+{
+ gid_t result = 0;
+ const char * cstr = str.c_str();
+ struct group * grp = getgrnam(cstr);
+
+ if (grp == NULL) {
+ long long val;
+
+ try {
+ val = stoll(str);
+ }
+ catch(std::exception& e) {
+ throw runtime_error((boost::format("Error: Unable to parse group ID %s") % cstr).str() );
+ }
+
+ if (val < std::numeric_limits<gid_t>::min() || val > std::numeric_limits<gid_t>::max()) {
+ throw runtime_error((boost::format("Error: Unable to parse group ID %s") % cstr).str() );
+ }
+
+ result = static_cast<gid_t>(val);
+ }
+ else {
+ result = grp->gr_gid;
+ }
+
+ return result;
+}
+
+unsigned int pdns_stou(const std::string& str, size_t * idx, int base)
+{
+ if (str.empty()) return 0; // compability
+ unsigned long result = std::stoul(str, idx, base);
+ if (result > std::numeric_limits<unsigned int>::max()) {
+ throw std::out_of_range("stou");
+ }
+ return static_cast<unsigned int>(result);
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include <errno.h>
+#include <inttypes.h>
+#include <cstring>
+#include <cstdio>
+#include <regex.h>
+#include <limits.h>
+#include <type_traits>
+#include <boost/algorithm/string.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+using namespace ::boost::multi_index;
+
+#include "dns.hh"
+#include <atomic>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <time.h>
+#include <syslog.h>
+#include <deque>
+#include <stdexcept>
+#include <string>
+#include <ctype.h>
+#include <vector>
+
+#include "namespaces.hh"
+#include "dnsname.hh"
+
+typedef enum { TSIG_MD5, TSIG_SHA1, TSIG_SHA224, TSIG_SHA256, TSIG_SHA384, TSIG_SHA512, TSIG_GSS } TSIGHashEnum;
+
+string nowTime();
+const string unquotify(const string &item);
+string humanDuration(time_t passed);
+bool stripDomainSuffix(string *qname, const string &domain);
+void stripLine(string &line);
+string getHostname();
+string urlEncode(const string &text);
+int waitForData(int fd, int seconds, int useconds=0);
+int waitFor2Data(int fd1, int fd2, int seconds, int useconds, int* fd);
+int waitForRWData(int fd, bool waitForRead, int seconds, int useconds, bool* error=nullptr, bool* disconnected=nullptr);
+uint16_t getShort(const unsigned char *p);
+uint16_t getShort(const char *p);
+uint32_t getLong(const unsigned char *p);
+uint32_t getLong(const char *p);
+bool getTSIGHashEnum(const DNSName& algoName, TSIGHashEnum& algoEnum);
+DNSName getTSIGAlgoName(TSIGHashEnum& algoEnum);
+
+int logFacilityToLOG(unsigned int facility);
+
+struct ServiceTuple
+{
+ string host;
+ uint16_t port;
+};
+void parseService(const string &descr, ServiceTuple &st);
+
+template <typename Container>
+void
+stringtok (Container &container, string const &in,
+ const char * const delimiters = " \t\n")
+{
+ const string::size_type len = in.length();
+ string::size_type i = 0;
+
+ while (i<len) {
+ // eat leading whitespace
+ i = in.find_first_not_of (delimiters, i);
+ if (i == string::npos)
+ return; // nothing left but white space
+
+ // find the end of the token
+ string::size_type j = in.find_first_of (delimiters, i);
+
+ // push token
+ if (j == string::npos) {
+ container.push_back (in.substr(i));
+ return;
+ } else
+ container.push_back (in.substr(i, j-i));
+
+ // set up for next loop
+ i = j + 1;
+ }
+}
+
+template<typename T> bool rfc1982LessThan(T a, T b)
+{
+ return ((signed)(a - b)) < 0;
+}
+
+// fills container with ranges, so {posbegin,posend}
+template <typename Container>
+void
+vstringtok (Container &container, string const &in,
+ const char * const delimiters = " \t\n")
+{
+ const string::size_type len = in.length();
+ string::size_type i = 0;
+
+ while (i<len) {
+ // eat leading whitespace
+ i = in.find_first_not_of (delimiters, i);
+ if (i == string::npos)
+ return; // nothing left but white space
+
+ // find the end of the token
+ string::size_type j = in.find_first_of (delimiters, i);
+
+ // push token
+ if (j == string::npos) {
+ container.push_back (make_pair(i, len));
+ return;
+ } else
+ container.push_back (make_pair(i, j));
+
+ // set up for next loop
+ i = j + 1;
+ }
+}
+
+size_t writen2(int fd, const void *buf, size_t count);
+inline size_t writen2(int fd, const std::string &s) { return writen2(fd, s.data(), s.size()); }
+size_t readn2(int fd, void* buffer, size_t len);
+size_t readn2WithTimeout(int fd, void* buffer, size_t len, int timeout);
+size_t writen2WithTimeout(int fd, const void * buffer, size_t len, int timeout);
+
+const string toLower(const string &upper);
+const string toLowerCanonic(const string &upper);
+bool IpToU32(const string &str, uint32_t *ip);
+string U32ToIP(uint32_t);
+string stringerror();
+string netstringerror();
+string itoa(int i);
+string uitoa(unsigned int i);
+string bitFlip(const string &str);
+
+void dropPrivs(int uid, int gid);
+int makeGidNumeric(const string &group);
+int makeUidNumeric(const string &user);
+void cleanSlashes(string &str);
+
+#if defined(_POSIX_THREAD_CPUTIME) && defined(CLOCK_THREAD_CPUTIME_ID)
+/** CPUTime measurements */
+class CPUTime
+{
+public:
+ void start()
+ {
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &d_start);
+ }
+ uint64_t ndiff()
+ {
+ struct timespec now;
+ clock_gettime(CLOCK_THREAD_CPUTIME_ID, &now);
+ return 1000000000ULL*(now.tv_sec - d_start.tv_sec) + (now.tv_nsec - d_start.tv_nsec);
+ }
+private:
+ struct timespec d_start;
+};
+#endif
+
+/** The DTime class can be used for timing statistics with microsecond resolution.
+On 32 bits systems this means that 2147 seconds is the longest time that can be measured. */
+class DTime
+{
+public:
+ DTime(); //!< Does not set the timer for you! Saves lots of gettimeofday() calls
+ DTime(const DTime &dt);
+ time_t time();
+ inline void set(); //!< Reset the timer
+ inline int udiff(); //!< Return the number of microseconds since the timer was last set.
+ inline int udiffNoReset(); //!< Return the number of microseconds since the timer was last set.
+ void setTimeval(const struct timeval& tv)
+ {
+ d_set=tv;
+ }
+ struct timeval getTimeval()
+ {
+ return d_set;
+ }
+private:
+ struct timeval d_set;
+};
+
+inline void DTime::set()
+{
+ gettimeofday(&d_set,0);
+}
+
+inline int DTime::udiff()
+{
+ int res=udiffNoReset();
+ gettimeofday(&d_set,0);
+ return res;
+}
+
+inline int DTime::udiffNoReset()
+{
+ struct timeval now;
+
+ gettimeofday(&now,0);
+ int ret=1000000*(now.tv_sec-d_set.tv_sec)+(now.tv_usec-d_set.tv_usec);
+ return ret;
+}
+
+
+inline bool dns_isspace(char c)
+{
+ return c==' ' || c=='\t' || c=='\r' || c=='\n';
+}
+
+inline char dns_tolower(char c)
+{
+ if(c>='A' && c<='Z')
+ c+='a'-'A';
+ return c;
+}
+
+inline char dns_toupper(char c)
+{
+ if(c>='a' && c<='z')
+ c+='A'-'a';
+ return c;
+}
+
+inline const string toLower(const string &upper)
+{
+ string reply(upper);
+ char c;
+ for(unsigned int i = 0; i < reply.length(); i++) {
+ c = dns_tolower(upper[i]);
+ if( c != upper[i])
+ reply[i] = c;
+ }
+ return reply;
+}
+
+inline const string toLowerCanonic(const string &upper)
+{
+ string reply(upper);
+ if(!upper.empty()) {
+ unsigned int i, limit= ( unsigned int ) reply.length();
+ char c;
+ for(i = 0; i < limit ; i++) {
+ c = dns_tolower(upper[i]);
+ if(c != upper[i])
+ reply[i] = c;
+ }
+ if(upper[i-1]=='.')
+ reply.resize(i-1);
+ }
+
+ return reply;
+}
+
+
+
+// Make s uppercase:
+inline string toUpper( const string& s )
+{
+ string r(s);
+ for( unsigned int i = 0; i < s.length(); i++ ) {
+ r[i] = dns_toupper(r[i]);
+ }
+ return r;
+}
+
+inline double getTime()
+{
+ struct timeval now;
+ gettimeofday(&now,0);
+
+ return now.tv_sec+now.tv_usec/1000000.0;
+}
+
+inline void unixDie(const string &why)
+{
+ throw runtime_error(why+": "+strerror(errno));
+}
+
+string makeHexDump(const string& str);
+void shuffle(vector<DNSRecord>& rrs);
+void shuffle(vector<DNSResourceRecord>& rrs);
+void orderAndShuffle(vector<DNSRecord>& rrs);
+
+void normalizeTV(struct timeval& tv);
+const struct timeval operator+(const struct timeval& lhs, const struct timeval& rhs);
+const struct timeval operator-(const struct timeval& lhs, const struct timeval& rhs);
+inline float makeFloat(const struct timeval& tv)
+{
+ return tv.tv_sec + tv.tv_usec/1000000.0f;
+}
+
+inline bool operator<(const struct timeval& lhs, const struct timeval& rhs)
+{
+ return make_pair(lhs.tv_sec, lhs.tv_usec) < make_pair(rhs.tv_sec, rhs.tv_usec);
+}
+
+inline bool operator<(const struct timespec& lhs, const struct timespec& rhs)
+{
+ return tie(lhs.tv_sec, lhs.tv_nsec) < tie(rhs.tv_sec, rhs.tv_nsec);
+}
+
+
+inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b) __attribute__((pure));
+inline bool pdns_ilexicographical_compare(const std::string& a, const std::string& b)
+{
+ const unsigned char *aPtr = (const unsigned char*)a.c_str(), *bPtr = (const unsigned char*)b.c_str();
+ const unsigned char *aEptr = aPtr + a.length(), *bEptr = bPtr + b.length();
+ while(aPtr != aEptr && bPtr != bEptr) {
+ if ((*aPtr != *bPtr) && (dns_tolower(*aPtr) - dns_tolower(*bPtr)))
+ return (dns_tolower(*aPtr) - dns_tolower(*bPtr)) < 0;
+ aPtr++;
+ bPtr++;
+ }
+ if(aPtr == aEptr && bPtr == bEptr) // strings are equal (in length)
+ return false;
+ return aPtr == aEptr; // true if first string was shorter
+}
+
+inline bool pdns_iequals(const std::string& a, const std::string& b) __attribute__((pure));
+inline bool pdns_iequals(const std::string& a, const std::string& b)
+{
+ if (a.length() != b.length())
+ return false;
+
+ const char *aPtr = a.c_str(), *bPtr = b.c_str();
+ const char *aEptr = aPtr + a.length();
+ while(aPtr != aEptr) {
+ if((*aPtr != *bPtr) && (dns_tolower(*aPtr) != dns_tolower(*bPtr)))
+ return false;
+ aPtr++;
+ bPtr++;
+ }
+ return true;
+}
+
+inline bool pdns_iequals_ch(const char a, const char b) __attribute__((pure));
+inline bool pdns_iequals_ch(const char a, const char b)
+{
+ if ((a != b) && (dns_tolower(a) != dns_tolower(b)))
+ return false;
+
+ return true;
+}
+
+
+typedef unsigned long AtomicCounterInner;
+typedef std::atomic<AtomicCounterInner> AtomicCounter ;
+
+// FIXME400 this should probably go?
+struct CIStringCompare: public std::binary_function<string, string, bool>
+{
+ bool operator()(const string& a, const string& b) const
+ {
+ return pdns_ilexicographical_compare(a, b);
+ }
+};
+
+struct CIStringComparePOSIX
+{
+ bool operator() (const std::string& lhs, const std::string& rhs)
+ {
+ std::string::const_iterator a,b;
+ const std::locale &loc = std::locale("POSIX");
+ a=lhs.begin();b=rhs.begin();
+ while(a!=lhs.end()) {
+ if (b==rhs.end() || std::tolower(*b,loc)<std::tolower(*a,loc)) return false;
+ else if (std::tolower(*a,loc)<std::tolower(*b,loc)) return true;
+ a++;b++;
+ }
+ return (b!=rhs.end());
+ }
+};
+
+struct CIStringPairCompare: public std::binary_function<pair<string, uint16_t>, pair<string,uint16_t>, bool>
+{
+ bool operator()(const pair<string, uint16_t>& a, const pair<string, uint16_t>& b) const
+ {
+ if(pdns_ilexicographical_compare(a.first, b.first))
+ return true;
+ if(pdns_ilexicographical_compare(b.first, a.first))
+ return false;
+ return a.second < b.second;
+ }
+};
+
+inline size_t pdns_ci_find(const string& haystack, const string& needle)
+{
+ string::const_iterator it = std::search(haystack.begin(), haystack.end(),
+ needle.begin(), needle.end(), pdns_iequals_ch);
+ if (it == haystack.end()) {
+ // not found
+ return string::npos;
+ } else {
+ return it - haystack.begin();
+ }
+}
+
+pair<string, string> splitField(const string& inp, char sepa);
+
+inline bool isCanonical(const string& qname)
+{
+ if(qname.empty())
+ return false;
+ return qname[qname.size()-1]=='.';
+}
+
+inline DNSName toCanonic(const DNSName& zone, const string& qname)
+{
+ if(qname.size()==1 && qname[0]=='@')
+ return zone;
+ if(isCanonical(qname))
+ return DNSName(qname);
+ return DNSName(qname) += zone;
+}
+
+string stripDot(const string& dom);
+
+void seedRandom(const string& source);
+string makeRelative(const std::string& fqdn, const std::string& zone);
+string labelReverse(const std::string& qname);
+std::string dotConcat(const std::string& a, const std::string &b);
+int makeIPv6sockaddr(const std::string& addr, struct sockaddr_in6* ret);
+int makeIPv4sockaddr(const std::string& str, struct sockaddr_in* ret);
+int makeUNsockaddr(const std::string& path, struct sockaddr_un* ret);
+bool stringfgets(FILE* fp, std::string& line);
+
+template<typename Index>
+std::pair<typename Index::iterator,bool>
+replacing_insert(Index& i,const typename Index::value_type& x)
+{
+ std::pair<typename Index::iterator,bool> res=i.insert(x);
+ if(!res.second)res.second=i.replace(res.first,x);
+ return res;
+}
+
+/** very small regex wrapper */
+class Regex
+{
+public:
+ /** constructor that accepts the expression to regex */
+ Regex(const string &expr);
+
+ ~Regex()
+ {
+ regfree(&d_preg);
+ }
+ /** call this to find out if 'line' matches your expression */
+ bool match(const string &line) const
+ {
+ return regexec(&d_preg,line.c_str(),0,0,0)==0;
+ }
+ bool match(const DNSName& name) const
+ {
+ return match(name.toStringNoDot());
+ }
+
+private:
+ regex_t d_preg;
+};
+
+class SimpleMatch
+{
+public:
+ SimpleMatch(const string &mask, bool caseFold = false)
+ {
+ this->d_mask = mask;
+ this->d_fold = caseFold;
+ }
+
+ bool match(string::const_iterator mi, string::const_iterator mend, string::const_iterator vi, string::const_iterator vend)
+ {
+ for(;;mi++) {
+ if (mi == mend) {
+ return vi == vend;
+ } else if (*mi == '?') {
+ if (vi == vend) return false;
+ vi++;
+ } else if (*mi == '*') {
+ while(*mi == '*') mi++;
+ if (mi == d_mask.end()) return true;
+ while(vi != vend) {
+ if (match(mi,mend,vi,vend)) return true;
+ vi++;
+ }
+ return false;
+ } else {
+ if ((mi == mend && vi != vend)||
+ (mi != mend && vi == vend)) return false;
+ if (d_fold) {
+ if (dns_tolower(*mi) != dns_tolower(*vi)) return false;
+ } else {
+ if (*mi != *vi) return false;
+ }
+ vi++;
+ }
+ }
+ }
+
+ bool match(const string& value) {
+ return match(d_mask.begin(), d_mask.end(), value.begin(), value.end());
+ }
+
+ bool match(const DNSName& name) {
+ return match(name.toStringNoDot());
+ }
+
+private:
+ string d_mask;
+ bool d_fold;
+};
+
+union ComboAddress;
+/* itfIndex is an interface index, as returned by if_nametoindex(). 0 means default. */
+void addCMsgSrcAddr(struct msghdr* msgh, void* cmsgbuf, const ComboAddress* source, int itfIndex);
+
+unsigned int getFilenumLimit(bool hardOrSoft=0);
+void setFilenumLimit(unsigned int lim);
+bool readFileIfThere(const char* fname, std::string* line);
+uint32_t burtle(const unsigned char* k, uint32_t lengh, uint32_t init);
+bool setSocketTimestamps(int fd);
+
+//! Sets the socket into blocking mode.
+bool setBlocking( int sock );
+
+//! Sets the socket into non-blocking mode.
+bool setNonBlocking( int sock );
+bool setTCPNoDelay(int sock);
+bool isNonBlocking(int sock);
+int closesocket(int fd);
+bool setCloseOnExec(int sock);
+uint64_t udpErrorStats(const std::string& str);
+
+uint64_t getRealMemoryUsage(const std::string&);
+uint64_t getOpenFileDescriptors(const std::string&);
+uint64_t getCPUTimeUser(const std::string&);
+uint64_t getCPUTimeSystem(const std::string&);
+std::string getMACAddress(const ComboAddress& ca);
+template<typename T, typename... Args>
+std::unique_ptr<T> make_unique(Args&&... args)
+{
+ return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
+}
+
+
+template<typename T>
+const T& defTer(const T& a, const T& b)
+{
+ return a ? a : b;
+}
+
+template<typename P, typename T>
+T valueOrEmpty(const P val) {
+ if (!val) return T{};
+ return T(val);
+}
+
+
+// I'm not very OCD, but I appreciate loglines like "processing 1 delta", "processing 2 deltas" :-)
+template <typename Integer>
+const char* addS(Integer siz, typename std::enable_if<std::is_integral<Integer>::value>::type*P=0)
+{
+ if(!siz || siz > 1)
+ return "s";
+ else return "";
+}
+
+template<typename C>
+const char* addS(const C& c, typename std::enable_if<std::is_class<C>::value>::type*P=0)
+{
+ return addS(c.size());
+}
+
+template<typename C>
+const typename C::value_type::second_type* rplookup(const C& c, const typename C::value_type::first_type& key)
+{
+ auto fnd = c.find(key);
+ if(fnd == c.end())
+ return 0;
+ return &fnd->second;
+}
+
+double DiffTime(const struct timespec& first, const struct timespec& second);
+double DiffTime(const struct timeval& first, const struct timeval& second);
+uid_t strToUID(const string &str);
+gid_t strToGID(const string &str);
+
+unsigned int pdns_stou(const std::string& str, size_t * idx = 0, int base = 10);
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_MPLEXER_HH
+#define PDNS_MPLEXER_HH
+#include <boost/function.hpp>
+#include <boost/any.hpp>
+#include <boost/shared_array.hpp>
+#include <boost/tuple/tuple.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <vector>
+#include <map>
+#include <stdexcept>
+#include <string>
+#include "utility.hh"
+
+class FDMultiplexerException : public std::runtime_error
+{
+public:
+ FDMultiplexerException(const std::string& str) : std::runtime_error(str)
+ {}
+};
+
+
+/** Very simple FD multiplexer, based on callbacks and boost::any parameters
+ As a special service, this parameter is kept around and can be modified,
+ allowing for state to be stored inside the multiplexer.
+
+ It has some "interesting" semantics
+*/
+
+class FDMultiplexer
+{
+public:
+ // typedef boost::variant<PacketID, TCPConnection> funcparam_t;
+ typedef boost::any funcparam_t;
+protected:
+
+ typedef boost::function< void(int, funcparam_t&) > callbackfunc_t;
+ struct Callback
+ {
+ callbackfunc_t d_callback;
+ funcparam_t d_parameter;
+ struct timeval d_ttd;
+ };
+
+public:
+ FDMultiplexer() : d_inrun(false)
+ {}
+ virtual ~FDMultiplexer()
+ {}
+
+ virtual int run(struct timeval* tv) = 0;
+
+ //! Add an fd to the read watch list - currently an fd can only be on one list at a time!
+ virtual void addReadFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
+ {
+ this->addFD(d_readCallbacks, fd, toDo, parameter);
+ }
+
+ //! Add an fd to the write watch list - currently an fd can only be on one list at a time!
+ virtual void addWriteFD(int fd, callbackfunc_t toDo, const funcparam_t& parameter=funcparam_t())
+ {
+ this->addFD(d_writeCallbacks, fd, toDo, parameter);
+ }
+
+ //! Remove an fd from the read watch list. You can't call this function on an fd that is closed already!
+ /** WARNING: references to 'parameter' become invalid after this function! */
+ virtual void removeReadFD(int fd)
+ {
+ this->removeFD(d_readCallbacks, fd);
+ }
+
+ //! Remove an fd from the write watch list. You can't call this function on an fd that is closed already!
+ /** WARNING: references to 'parameter' become invalid after this function! */
+ virtual void removeWriteFD(int fd)
+ {
+ this->removeFD(d_writeCallbacks, fd);
+ }
+
+ virtual void setReadTTD(int fd, struct timeval tv, int timeout)
+ {
+ if(!d_readCallbacks.count(fd))
+ throw FDMultiplexerException("attempt to timestamp fd not in the multiplexer");
+ tv.tv_sec += timeout;
+ d_readCallbacks[fd].d_ttd=tv;
+ }
+
+ virtual funcparam_t& getReadParameter(int fd)
+ {
+ if(!d_readCallbacks.count(fd))
+ throw FDMultiplexerException("attempt to look up data in multiplexer for unlisted fd "+std::to_string(fd));
+ return d_readCallbacks[fd].d_parameter;
+ }
+
+ virtual std::vector<std::pair<int, funcparam_t> > getTimeouts(const struct timeval& tv)
+ {
+ std::vector<std::pair<int, funcparam_t> > ret;
+ for(callbackmap_t::iterator i=d_readCallbacks.begin(); i!=d_readCallbacks.end(); ++i)
+ if(i->second.d_ttd.tv_sec && boost::tie(tv.tv_sec, tv.tv_usec) > boost::tie(i->second.d_ttd.tv_sec, i->second.d_ttd.tv_usec))
+ ret.push_back(std::make_pair(i->first, i->second.d_parameter));
+ return ret;
+ }
+
+ typedef FDMultiplexer* getMultiplexer_t();
+ typedef std::multimap<int, getMultiplexer_t*> FDMultiplexermap_t;
+
+ static FDMultiplexermap_t& getMultiplexerMap()
+ {
+ static FDMultiplexermap_t theMap;
+ return theMap;
+ }
+
+ virtual std::string getName() = 0;
+
+
+protected:
+ typedef std::map<int, Callback> callbackmap_t;
+ callbackmap_t d_readCallbacks, d_writeCallbacks;
+
+ virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)=0;
+ virtual void removeFD(callbackmap_t& cbmap, int fd)=0;
+ bool d_inrun;
+ callbackmap_t::iterator d_iter;
+
+ void accountingAddFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter)
+ {
+ Callback cb;
+ cb.d_callback=toDo;
+ cb.d_parameter=parameter;
+ memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
+
+ if(cbmap.count(fd))
+ throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice");
+ cbmap[fd]=cb;
+ }
+
+ void accountingRemoveFD(callbackmap_t& cbmap, int fd)
+ {
+ if(!cbmap.erase(fd))
+ throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
+ }
+};
+
+class SelectFDMultiplexer : public FDMultiplexer
+{
+public:
+ SelectFDMultiplexer()
+ {}
+ virtual ~SelectFDMultiplexer()
+ {}
+
+ virtual int run(struct timeval* tv);
+
+ virtual void addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const funcparam_t& parameter);
+ virtual void removeFD(callbackmap_t& cbmap, int fd);
+ std::string getName()
+ {
+ return "select";
+ }
+};
+
+#endif
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "mtasker.hh"
+#include "misc.hh"
+#include <stdio.h>
+#include <iostream>
+
+
+/** \page MTasker
+ Simple system for implementing cooperative multitasking of functions, with
+ support for waiting on events which can return values.
+
+ \section copyright Copyright and License
+ MTasker is (c) 2002 - 2009 by bert hubert. It is licensed to you under the terms of the GPL version 2.
+
+ \section overview High level overview
+ MTasker is designed to support very simple cooperative multitasking to facilitate writing
+ code that would ordinarily require a statemachine, for which the author does not consider
+ himself smart enough.
+
+ This class does not perform any magic it only makes calls to makecontext() and swapcontext().
+ Getting the details right however is complicated and MTasker does that for you.
+
+ If preemptive multitasking or more advanced concepts such as semaphores, locks or mutexes
+ are required, the use of POSIX threads is advised.
+
+ MTasker is designed to offer the performance of statemachines while maintaining simple thread semantics. It is not
+ a replacement for a full threading system.
+
+ \section compatibility Compatibility
+ MTasker is only guaranteed to work on Linux with glibc 2.2.5 and higher. It does not work on FreeBSD and notably,
+ not on Red Hat 6.0. It may work on Solaris, please test.
+
+ \section concepts Concepts
+
+ There are two important concepts, the 'kernel' and the 'thread'. Each thread starts out as a function,
+ which is passed to MTasker::makeThread(), together with a possible argument.
+
+ This function is now free to do whatever it wants, but realise that MTasker implements cooperative
+ multitasking, which means that the coder has the responsiblilty of not taking the CPU overly long.
+ Other threads can only get the CPU if MTasker::yield() is called or if a thread sleeps to wait for an event,
+ using the MTasker::waitEvent() method.
+
+ \section kernel The Kernel
+ The Kernel consists of functions that do housekeeping, but also of code that the client coder
+ can call to report events. A minimal kernel loop looks like this:
+ \code
+ for(;;) {
+ MT.schedule();
+ if(MT.noProcesses()) // exit if no processes are left
+ break;
+ }
+ \endcode
+
+ The kernel typically starts from the main() function of your program. New threads are also
+ created from the kernel. This can also happen before entering the main loop. To start a thread,
+ the method MTasker::makeThread is provided.
+
+ \section events Events
+ By default, Events are recognized by an int and their value is also an int.
+ This can be overridden by specifying the EventKey and EventVal template parameters.
+
+ An event can be a keypress, but also a UDP packet, or a bit of data from a TCP socket. The
+ sample code provided works with keypresses, but that is just a not very useful example.
+
+ A thread can also wait for an event only for a limited time, and receive a timeout of that
+ event did not occur within the specified timeframe.
+
+ \section example A simple menu system
+ \code
+MTasker<> MT;
+
+void menuHandler(void *p)
+{
+ int num=(int)p;
+ cout<<"Key handler for key "<<num<<" launched"<<endl;
+
+ MT.waitEvent(num);
+ cout<<"Key "<<num<<" was pressed!"<<endl;
+}
+
+
+int main()
+{
+ char line[10];
+
+ for(int i=0;i<10;++i)
+ MT.makeThread(menuHandler,(void *)i);
+
+ for(;;) {
+ while(MT.schedule()); // do everything we can do
+ if(MT.noProcesses()) // exit if no processes are left
+ break;
+
+ if(!fgets(line,sizeof(line),stdin))
+ break;
+
+ MT.sendEvent(*line-'0');
+ }
+}
+\endcode
+
+\section example2 Canonical multitasking example
+This implements the canonical multitasking example, alternately printing an 'A' and a 'B'. The Linux kernel
+ started this way too.
+\code
+void printer(void *p)
+{
+ char c=(char)p;
+ for(;;) {
+ cout<<c<<endl;
+ MT.yield();
+ }
+
+}
+
+int main()
+{
+ MT.makeThread(printer,(void*)'a');
+ MT.makeThread(printer,(void*)'b');
+
+ for(;;) {
+ while(MT.schedule()); // do everything we can do
+ if(MT.noProcesses()) // exit if no processes are left
+ break;
+ }
+}
+\endcode
+
+*/
+
+//! puts a thread to sleep waiting until a specified event arrives
+/** Threads can call waitEvent to register that they are waiting on an event with a certain key.
+ If so desired, the event can carry data which is returned in val in case that is non-zero.
+
+ Furthermore, a timeout can be specified in seconds.
+
+ Only one thread can be waiting on a key, results of trying to have more threads
+ waiting on the same key are undefined.
+
+ \param key Event key to wait for. Needs to match up to a key reported to sendEvent
+ \param val If non-zero, the value of the event will be stored in *val
+ \param timeout If non-zero, number of seconds to wait for an event.
+
+ \return returns -1 in case of error, 0 in case of timeout, 1 in case of an answer
+*/
+
+template<class EventKey, class EventVal>int MTasker<EventKey,EventVal>::waitEvent(EventKey &key, EventVal *val, unsigned int timeoutMsec, struct timeval* now)
+{
+ if(d_waiters.count(key)) { // there was already an exact same waiter
+ return -1;
+ }
+
+ Waiter w;
+ w.context=std::make_shared<pdns_ucontext_t>();
+ w.ttd.tv_sec = 0; w.ttd.tv_usec = 0;
+ if(timeoutMsec) {
+ struct timeval increment;
+ increment.tv_sec = timeoutMsec / 1000;
+ increment.tv_usec = 1000 * (timeoutMsec % 1000);
+ if(now)
+ w.ttd = increment + *now;
+ else {
+ struct timeval realnow;
+ gettimeofday(&realnow, 0);
+ w.ttd = increment + realnow;
+ }
+ }
+
+ w.tid=d_tid;
+ w.key=key;
+
+ d_waiters.insert(w);
+#ifdef MTASKERTIMING
+ unsigned int diff=d_threads[d_tid].dt.ndiff()/1000;
+ d_threads[d_tid].totTime+=diff;
+#endif
+ pdns_swapcontext(*d_waiters.find(key)->context,d_kernel); // 'A' will return here when 'key' has arrived, hands over control to kernel first
+#ifdef MTASKERTIMING
+ d_threads[d_tid].dt.start();
+#endif
+ if(val && d_waitstatus==Answer)
+ *val=d_waitval;
+ d_tid=w.tid;
+ if((char*)&w < d_threads[d_tid].highestStackSeen) {
+ d_threads[d_tid].highestStackSeen = (char*)&w;
+ }
+ key=d_eventkey;
+ return d_waitstatus;
+}
+
+//! yields control to the kernel or other threads
+/** Hands over control to the kernel, allowing other processes to run, or events to arrive */
+
+template<class Key, class Val>void MTasker<Key,Val>::yield()
+{
+ d_runQueue.push(d_tid);
+ pdns_swapcontext(*d_threads[d_tid].context ,d_kernel); // give control to the kernel
+}
+
+//! reports that an event took place for which threads may be waiting
+/** From the kernel loop, sendEvent can be called to report that something occurred for which there may be waiters.
+ \param key Key of the event for which threads may be waiting
+ \param val If non-zero, pointer to the content of the event
+ \return Returns -1 in case of error, 0 if there were no waiters, 1 if a thread was woken up.
+
+ WARNING: when passing val as zero, d_waitval is undefined, and hence waitEvent will return undefined!
+*/
+template<class EventKey, class EventVal>int MTasker<EventKey,EventVal>::sendEvent(const EventKey& key, const EventVal* val)
+{
+ typename waiters_t::iterator waiter=d_waiters.find(key);
+
+ if(waiter == d_waiters.end()) {
+ // cout<<"Event sent nobody was waiting for!"<<endl;
+ return 0;
+ }
+
+ d_waitstatus=Answer;
+ if(val)
+ d_waitval=*val;
+
+ d_tid=waiter->tid; // set tid
+ d_eventkey=waiter->key; // pass waitEvent the exact key it was woken for
+ auto userspace=std::move(waiter->context);
+ d_waiters.erase(waiter); // removes the waitpoint
+ pdns_swapcontext(d_kernel,*userspace); // swaps back to the above point 'A'
+ return 1;
+}
+
+//! launches a new thread
+/** The kernel can call this to make a new thread, which starts at the function start and gets passed the val void pointer.
+ \param start Pointer to the function which will form the start of the thread
+ \param val A void pointer that can be used to pass data to the thread
+*/
+template<class Key, class Val>void MTasker<Key,Val>::makeThread(tfunc_t *start, void* val)
+{
+ auto uc=std::make_shared<pdns_ucontext_t>();
+
+ uc->uc_link = &d_kernel; // come back to kernel after dying
+ uc->uc_stack.resize (d_stacksize);
+
+ auto& thread = d_threads[d_maxtid];
+ auto mt = this;
+ thread.start = [start, val, mt]() {
+ char dummy;
+ mt->d_threads[mt->d_tid].startOfStack = mt->d_threads[mt->d_tid].highestStackSeen = &dummy;
+ auto const tid = mt->d_tid;
+ start (val);
+ mt->d_zombiesQueue.push(tid);
+ };
+ pdns_makecontext (*uc, thread.start);
+
+ thread.context = std::move(uc);
+ d_runQueue.push(d_maxtid++); // will run at next schedule invocation
+}
+
+
+//! needs to be called periodically so threads can run and housekeeping can be performed
+/** The kernel should call this function every once in a while. It makes sense
+ to call this function if you:
+ - reported an event
+ - called makeThread
+ - want to have threads running waitEvent() to get a timeout if enough time passed
+
+ \return Returns if there is more work scheduled and recalling schedule now would be useful
+
+*/
+template<class Key, class Val>bool MTasker<Key,Val>::schedule(struct timeval* now)
+{
+ if(!d_runQueue.empty()) {
+ d_tid=d_runQueue.front();
+#ifdef MTASKERTIMING
+ d_threads[d_tid].dt.start();
+#endif
+ pdns_swapcontext(d_kernel, *d_threads[d_tid].context);
+
+ d_runQueue.pop();
+ return true;
+ }
+ if(!d_zombiesQueue.empty()) {
+ d_threads.erase(d_zombiesQueue.front());
+ d_zombiesQueue.pop();
+ return true;
+ }
+ if(!d_waiters.empty()) {
+ struct timeval rnow;
+ if(!now)
+ gettimeofday(&rnow, 0);
+ else
+ rnow = *now;
+
+ typedef typename waiters_t::template index<KeyTag>::type waiters_by_ttd_index_t;
+ // waiters_by_ttd_index_t& ttdindex=d_waiters.template get<KeyTag>();
+ waiters_by_ttd_index_t& ttdindex=boost::multi_index::get<KeyTag>(d_waiters);
+
+ for(typename waiters_by_ttd_index_t::iterator i=ttdindex.begin(); i != ttdindex.end(); ) {
+ if(i->ttd.tv_sec && i->ttd < rnow) {
+ d_waitstatus=TimeOut;
+ d_eventkey=i->key; // pass waitEvent the exact key it was woken for
+ auto uc = i->context;
+ d_tid = i->tid;
+ ttdindex.erase(i++); // removes the waitpoint
+
+ pdns_swapcontext(d_kernel, *uc); // swaps back to the above point 'A'
+ }
+ else if(i->ttd.tv_sec)
+ break;
+ }
+ }
+ return false;
+}
+
+//! returns true if there are no processes
+/** Call this to check if no processes are running anymore
+ \return true if no processes are left
+ */
+template<class Key, class Val>bool MTasker<Key,Val>::noProcesses()
+{
+ return d_threads.empty();
+}
+
+//! returns the number of processes running
+/** Call this to perhaps limit activities if too many threads are running
+ \return number of processes running
+ */
+template<class Key, class Val>unsigned int MTasker<Key,Val>::numProcesses()
+{
+ return d_threads.size();
+}
+
+//! gives access to the list of Events threads are waiting for
+/** The kernel can call this to get a list of Events threads are waiting for. This is very useful
+ to setup 'select' or 'poll' or 'aio' events needed to satisfy these requests.
+ getEvents clears the events parameter before filling it.
+
+ \param events Vector which is to be filled with keys threads are waiting for
+*/
+template<class Key, class Val>void MTasker<Key,Val>::getEvents(std::vector<Key>& events)
+{
+ events.clear();
+ for(typename waiters_t::const_iterator i=d_waiters.begin();i!=d_waiters.end();++i) {
+ events.push_back(i->first);
+ }
+}
+
+//! Returns the current Thread ID (tid)
+/** Processes can call this to get a numerical representation of their current thread ID.
+ This can be useful for logging purposes.
+*/
+template<class Key, class Val>int MTasker<Key,Val>::getTid()
+{
+ return d_tid;
+}
+
+//! Returns the maximum stack usage so far of this MThread
+template<class Key, class Val>unsigned int MTasker<Key,Val>::getMaxStackUsage()
+{
+ return d_threads[d_tid].startOfStack - d_threads[d_tid].highestStackSeen;
+}
+
+//! Returns the maximum stack usage so far of this MThread
+template<class Key, class Val>unsigned int MTasker<Key,Val>::getUsec()
+{
+#ifdef MTASKERTIMING
+ return d_threads[d_tid].totTime + d_threads[d_tid].dt.ndiff()/1000;
+#else
+ return 0;
+#endif
+}
--- /dev/null
+# this file is used by ../pdns/test-bindparser_cc.cc
+# if you change it, please make check!
+
+options {
+ directory "./zones/";
+ recursion no;
+ listen-on port 5300 {
+ 127.0.0.1;
+ };
+ version "Meow!Meow!";
+ minimal-responses yes;
+};
+zone "example.com"{
+ type master;
+ file "example.com";
+};
+
+zone "test.com"{
+ type slave;
+ file "test.com";
+ masters { 1.2.3.4:5678; };
+};
+
+zone "test.dyndns" {
+ type garblewarble;
+ file "test.dyndns";
+ allow-update {
+ 127.0.0.0/8;
+ };
+};
+
+zone "wtest.com"{
+ type master;
+ file "wtest.com";
+};
+
+zone "nztest.com"{
+ type master;
+ file "nztest.com";
+};
+
+zone "dnssec-parent.com"{
+ type master;
+ file "dnssec-parent.com";
+};
+
+zone "delegated.dnssec-parent.com"{
+ type master;
+ file "delegated.dnssec-parent.com";
+};
+
+zone "secure-delegated.dnssec-parent.com"{
+ type master;
+ file "secure-delegated.dnssec-parent.com";
+};
+
+zone "minimal.com"{
+ type master;
+ file "minimal.com";
+};
+
+zone "tsig.com"{
+ type master;
+ file "tsig.com";
+};
+
+zone "stest.com"{
+ type master;
+ file "stest.com";
+};
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include <cstdio>
+#include <cstring>
+#include <cstdlib>
+#include <cerrno>
+#include <iostream>
+#include <string>
+#include <sys/types.h>
+#include "responsestats.hh"
+
+#include "dns.hh"
+#include "dnsbackend.hh"
+#include "dnspacket.hh"
+#include "nameserver.hh"
+#include "distributor.hh"
+#include "logger.hh"
+#include "arguments.hh"
+#include "statbag.hh"
+
+#include "namespaces.hh"
+
+extern StatBag S;
+
+/** \mainpage
+ PowerDNS is a very versatile nameserver that can answer questions from different backends. To implement your
+ own backend, see the documentation for the DNSBackend class.
+
+ \section copyright Copyright and License
+ PowerDNS is (C) 2001-2008 PowerDNS.COM BV. It is distributed according to the terms of the General Public License version 2.
+
+ \section overview High level overview
+
+ The Distributor contains a configurable number of PacketHandler instances, each in its own thread, for connection pooling.
+ PacketHandler instances are recycled of they let escape an PDNSException.
+
+ The PacketHandler implements the RFC1034 algorithm and converts question packets into DNSBackend queries.
+
+ A DNSBackend is an entity that returns DNSResourceRecord objects in return to explicit questions for domains with a specified QType
+
+ PowerDNS uses the UeberBackend as its DNSBackend. The UeberBackend by default has no DNSBackends within itself, those are loaded
+ using the pdns_control tool. This way DNSBackend implementations can be kept completely separate (but they often aren't).s
+
+ If one or more DNSBackends are loaded, the UeberBackend fields the queries to all of them until one answers.
+
+ \section TCP TCP Operations
+
+ The TCP operation runs within a single thread called tcpreceiver(), that also queries the PacketHandler.
+
+ \section Cache Caching
+
+ On its own, this setup is not suitable for high performance operations. A single DNS query can turn into many DNSBackend questions,
+ each taking many milliseconds to complete. This is why the qthread() first checks the PacketCache to see if an answer is known to a packet
+ asking this question. If so, the entire Distributor is shunted, and the answer is sent back *directly*, within a few microseconds.
+
+ \section misc Miscellaneous
+ Configuration details are available via the ArgvMap instance arg. Statistics are created by making calls to the StatBag object called S.
+ These statistics are made available via the UeberBackend on the same socket that is used for dynamic module commands.
+
+ \section Main Main
+ The main() of PowerDNS can be found in receiver.cc - start reading there for further insights into the operation of the nameserver
+*/
+
+vector<ComboAddress> g_localaddresses; // not static, our unit tests need to poke this
+
+void UDPNameserver::bindIPv4()
+{
+ vector<string>locals;
+ stringtok(locals,::arg()["local-address"]," ,");
+ int one = 1;
+
+ if(locals.empty())
+ throw PDNSException("No local address specified");
+
+ int s;
+ for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
+ string localname(*i);
+ ComboAddress locala;
+
+ s=socket(AF_INET,SOCK_DGRAM,0);
+
+ if(s<0) {
+ L<<Logger::Error<<"Unable to acquire UDP socket: "+string(strerror(errno)) << endl;
+ throw PDNSException("Unable to acquire a UDP socket: "+string(strerror(errno)));
+ }
+
+ setCloseOnExec(s);
+
+ if(!setNonBlocking(s))
+ throw PDNSException("Unable to set UDP socket to non-blocking: "+stringerror());
+
+ memset(&locala,0,sizeof(locala));
+ locala.sin4.sin_family=AF_INET;
+
+ if(localname=="0.0.0.0")
+ setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one));
+
+ if (!setSocketTimestamps(s))
+ L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
+
+#ifdef SO_REUSEPORT
+ if( d_can_reuseport )
+ if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
+ d_can_reuseport = false;
+#endif
+
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET, s);
+
+ locala=ComboAddress(localname, ::arg().asNum("local-port"));
+ if(locala.sin4.sin_family != AF_INET)
+ throw PDNSException("Attempting to bind IPv4 socket to IPv6 address");
+
+ if( !d_additional_socket )
+ g_localaddresses.push_back(locala);
+
+ if(::bind(s, (sockaddr*)&locala, locala.getSocklen()) < 0) {
+ string binderror = strerror(errno);
+ close(s);
+ if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
+ L<<Logger::Error<<"IPv4 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
+ continue;
+ } else {
+ L<<Logger::Error<<"Unable to bind UDP socket to '"+locala.toStringWithPort()+"': "<<binderror<<endl;
+ throw PDNSException("Unable to bind to UDP socket");
+ }
+ }
+ d_sockets.push_back(s);
+ L<<Logger::Error<<"UDP server bound to "<<locala.toStringWithPort()<<endl;
+ struct pollfd pfd;
+ pfd.fd = s;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ d_rfds.push_back(pfd);
+ }
+}
+
+bool AddressIsUs(const ComboAddress& remote)
+{
+ for(const ComboAddress& us : g_localaddresses) {
+ if(remote == us)
+ return true;
+ if(IsAnyAddress(us)) {
+ int s = socket(remote.sin4.sin_family, SOCK_DGRAM, 0);
+ if(s < 0)
+ continue;
+
+ if(connect(s, (struct sockaddr*)&remote, remote.getSocklen()) < 0) {
+ close(s);
+ continue;
+ }
+
+ ComboAddress actualLocal;
+ actualLocal.sin4.sin_family = remote.sin4.sin_family;
+ socklen_t socklen = actualLocal.getSocklen();
+
+ if(getsockname(s, (struct sockaddr*) &actualLocal, &socklen) < 0) {
+ close(s);
+ continue;
+ }
+ close(s);
+ actualLocal.sin4.sin_port = us.sin4.sin_port;
+ if(actualLocal == remote)
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void UDPNameserver::bindIPv6()
+{
+ vector<string> locals;
+ stringtok(locals,::arg()["local-ipv6"]," ,");
+ int one=1;
+
+ if(locals.empty())
+ return;
+
+ int s;
+ for(vector<string>::const_iterator i=locals.begin();i!=locals.end();++i) {
+ string localname(*i);
+
+ s=socket(AF_INET6,SOCK_DGRAM,0);
+ if(s<0) {
+ if( errno == EAFNOSUPPORT ) {
+ L<<Logger::Error<<"IPv6 Address Family is not supported - skipping UDPv6 bind" << endl;
+ return;
+ } else {
+ L<<Logger::Error<<"Unable to acquire a UDPv6 socket: "+string(strerror(errno)) << endl;
+ throw PDNSException("Unable to acquire a UDPv6 socket: "+string(strerror(errno)));
+ }
+ }
+
+ setCloseOnExec(s);
+ if(!setNonBlocking(s))
+ throw PDNSException("Unable to set UDPv6 socket to non-blocking: "+stringerror());
+
+ ComboAddress locala(localname, ::arg().asNum("local-port"));
+
+ if(IsAnyAddress(locala)) {
+ setsockopt(s, IPPROTO_IP, GEN_IP_PKTINFO, &one, sizeof(one)); // linux supports this, so why not - might fail on other systems
+#ifdef IPV6_RECVPKTINFO
+ setsockopt(s, IPPROTO_IPV6, IPV6_RECVPKTINFO, &one, sizeof(one));
+#endif
+ setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &one, sizeof(one)); // if this fails, we report an error in tcpreceiver too
+ }
+
+ if (!setSocketTimestamps(s))
+ L<<Logger::Warning<<"Unable to enable timestamp reporting for socket"<<endl;
+
+#ifdef SO_REUSEPORT
+ if( d_can_reuseport )
+ if( setsockopt(s, SOL_SOCKET, SO_REUSEPORT, &one, sizeof(one)) )
+ d_can_reuseport = false;
+#endif
+
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET6, s);
+
+ if( !d_additional_socket )
+ g_localaddresses.push_back(locala);
+ if(::bind(s, (sockaddr*)&locala, sizeof(locala))<0) {
+ close(s);
+ if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
+ L<<Logger::Error<<"IPv6 Address " << localname << " does not exist on this server - skipping UDP bind" << endl;
+ continue;
+ } else {
+ L<<Logger::Error<<"Unable to bind to UDPv6 socket "<< localname <<": "<<strerror(errno)<<endl;
+ throw PDNSException("Unable to bind to UDPv6 socket");
+ }
+ }
+ d_sockets.push_back(s);
+ struct pollfd pfd;
+ pfd.fd = s;
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ d_rfds.push_back(pfd);
+ L<<Logger::Error<<"UDPv6 server bound to "<<locala.toStringWithPort()<<endl;
+ }
+}
+
+UDPNameserver::UDPNameserver( bool additional_socket )
+{
+#ifdef SO_REUSEPORT
+ d_can_reuseport = ::arg().mustDo("reuseport");
+#endif
+ // Are we the main socket (false) or a rebinding using SO_REUSEPORT ?
+ d_additional_socket = additional_socket;
+
+ if(!::arg()["local-address"].empty())
+ bindIPv4();
+ if(!::arg()["local-ipv6"].empty())
+ bindIPv6();
+
+ if(::arg()["local-address"].empty() && ::arg()["local-ipv6"].empty())
+ L<<Logger::Critical<<"PDNS is deaf and mute! Not listening on any interfaces"<<endl;
+}
+
+void UDPNameserver::send(DNSPacket *p)
+{
+ string buffer=p->getString();
+ g_rs.submitResponse(*p, true);
+
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+
+ fillMSGHdr(&msgh, &iov, cbuf, 0, (char*)buffer.c_str(), buffer.length(), &p->d_remote);
+
+ msgh.msg_control=NULL;
+ if(p->d_anyLocal) {
+ addCMsgSrcAddr(&msgh, cbuf, p->d_anyLocal.get_ptr(), 0);
+ }
+ DLOG(L<<Logger::Notice<<"Sending a packet to "<< p->getRemote() <<" ("<< buffer.length()<<" octets)"<<endl);
+ if(buffer.length() > p->getMaxReplyLen()) {
+ L<<Logger::Error<<"Weird, trying to send a message that needs truncation, "<< buffer.length()<<" > "<<p->getMaxReplyLen()<<endl;
+ }
+ if(sendmsg(p->getSocket(), &msgh, 0) < 0)
+ L<<Logger::Error<<"Error sending reply with sendmsg (socket="<<p->getSocket()<<", dest="<<p->d_remote.toStringWithPort()<<"): "<<strerror(errno)<<endl;
+}
+
+DNSPacket *UDPNameserver::receive(DNSPacket *prefilled)
+{
+ ComboAddress remote;
+ extern StatBag S;
+ ssize_t len=-1;
+ char mesg[DNSPacket::s_udpTruncationThreshold];
+ Utility::sock_t sock=-1;
+
+ struct msghdr msgh;
+ struct iovec iov;
+ char cbuf[256];
+
+ remote.sin6.sin6_family=AF_INET6; // make sure it is big enough
+ fillMSGHdr(&msgh, &iov, cbuf, sizeof(cbuf), mesg, sizeof(mesg), &remote);
+
+ int err;
+ vector<struct pollfd> rfds= d_rfds;
+
+ for(auto &pfd : rfds) {
+ pfd.events = POLLIN;
+ pfd.revents = 0;
+ }
+
+ retry:;
+
+ err = poll(&rfds[0], rfds.size(), -1);
+ if(err < 0) {
+ if(errno==EINTR)
+ goto retry;
+ unixDie("Unable to poll for new UDP events");
+ }
+
+ for(auto &pfd : rfds) {
+ if(pfd.revents & POLLIN) {
+ sock=pfd.fd;
+ if((len=recvmsg(sock, &msgh, 0)) < 0 ) {
+ if(errno != EAGAIN)
+ L<<Logger::Error<<"recvfrom gave error, ignoring: "<<strerror(errno)<<endl;
+ return 0;
+ }
+ break;
+ }
+ }
+ if(sock==-1)
+ throw PDNSException("poll betrayed us! (should not happen)");
+
+ DLOG(L<<"Received a packet " << len <<" bytes long from "<< remote.toString()<<endl);
+
+ BOOST_STATIC_ASSERT(offsetof(sockaddr_in, sin_port) == offsetof(sockaddr_in6, sin6_port));
+
+ if(remote.sin4.sin_port == 0) // would generate error on responding. sin4 also works for ipv6
+ return 0;
+
+ DNSPacket *packet;
+ if(prefilled) // they gave us a preallocated packet
+ packet=prefilled;
+ else
+ packet=new DNSPacket(true); // don't forget to free it!
+
+ packet->setSocket(sock);
+ packet->setRemote(&remote);
+
+ ComboAddress dest;
+ if(HarvestDestinationAddress(&msgh, &dest)) {
+// cerr<<"Setting d_anyLocal to '"<<dest.toString()<<"'"<<endl;
+ packet->d_anyLocal = dest;
+ }
+
+ struct timeval recvtv;
+ if(HarvestTimestamp(&msgh, &recvtv)) {
+ packet->d_dt.setTimeval(recvtv);
+ }
+ else
+ packet->d_dt.set(); // timing
+
+ if(packet->parse(mesg, (size_t) len)<0) {
+ S.inc("corrupt-packets");
+ S.ringAccount("remotes-corrupt", packet->d_remote);
+
+ if(!prefilled)
+ delete packet;
+ return 0; // unable to parse
+ }
+
+ return packet;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef NAMESERVER_HH
+#define NAMESERVER_HH
+
+#include <poll.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/time.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <vector>
+
+#include "statbag.hh"
+#include "namespaces.hh"
+#include "dnspacket.hh"
+#include "responsestats.hh"
+
+/** This is the main class. It opens a socket on udp port 53 and waits for packets. Those packets can
+ be retrieved with the receive() member function, which returns a DNSPacket.
+
+ Some sample code in main():
+ \code
+ typedef Distributor<DNSPacket,DNSPacket,PacketHandler> DNSDistributor;
+ DNSDistributor D(6); // the big dispatcher!
+
+ pthread_t qtid, atid;
+ N=new UDPNameserver;
+
+ pthread_create(&qtid,0,qthread,static_cast<void *>(&D)); // receives packets
+ pthread_create(&atid,0,athread,static_cast<void *>(&D)); // sends packets
+ \endcode
+
+ Code for qthread:
+ \code
+ void *qthread(void *p)
+ {
+ DNSDistributor *D=static_cast<DNSDistributor *>(p);
+
+ DNSPacket *P;
+
+ while((P=N->receive())) // receive a packet
+ {
+ D->question(P); // and give to the distributor, they will delete it
+ }
+ return 0;
+ }
+
+ \endcode
+
+*/
+
+#ifdef __linux__
+#ifndef SO_REUSEPORT
+#define SO_REUSEPORT 15
+#endif
+#endif
+
+class UDPNameserver
+{
+public:
+ UDPNameserver( bool additional_socket = false ); //!< Opens the socket
+ DNSPacket *receive(DNSPacket *prefilled=0); //!< call this in a while or for(;;) loop to get packets
+ void send(DNSPacket *); //!< send a DNSPacket. Will call DNSPacket::truncate() if over 512 bytes
+ inline bool canReusePort() {
+#ifdef SO_REUSEPORT
+ return d_can_reuseport;
+#else
+ return false;
+#endif
+ };
+
+private:
+ bool d_additional_socket;
+#ifdef SO_REUSEPORT
+ bool d_can_reuseport;
+#endif
+ vector<int> d_sockets;
+ void bindIPv4();
+ void bindIPv6();
+ vector<pollfd> d_rfds;
+};
+
+bool AddressIsUs(const ComboAddress& remote);
+
+extern ResponseStats g_rs;
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_NAMESPACES_HH
+#define PDNS_NAMESPACES_HH
+#include <boost/tuple/tuple.hpp>
+
+#include <boost/shared_array.hpp>
+#include <boost/scoped_array.hpp>
+#include <boost/optional.hpp>
+#include <boost/any.hpp>
+#include <boost/function.hpp>
+#include <boost/format.hpp>
+#include <boost/algorithm/string.hpp>
+#include <memory>
+#include <vector>
+#include <map>
+#include <set>
+#include <deque>
+#include <string>
+#include <iostream>
+
+using std::vector;
+using std::map;
+using std::pair;
+using std::make_pair;
+using std::runtime_error;
+using std::ostringstream;
+using std::set;
+using std::deque;
+using std::cerr;
+using std::cout;
+using std::clog;
+using std::endl;
+using std::ifstream;
+using std::ofstream;
+using std::ostream;
+using std::min; // these are a bit scary, everybody uses 'min'
+using std::max;
+using std::string;
+
+using boost::tie;
+using std::shared_ptr;
+using std::unique_ptr;
+using boost::shared_array;
+using boost::scoped_array;
+using boost::tuple;
+using boost::format;
+using boost::make_tuple;
+using boost::optional;
+using boost::any_cast;
+using boost::any;
+using boost::function;
+using boost::trim;
+using boost::trim_copy;
+using boost::trim_left;
+using boost::trim_right;
+using boost::is_any_of;
+using boost::trim_right_copy_if;
+using boost::equals;
+using boost::ends_with;
+using boost::iends_with;
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <bitset>
+#include "dnsparser.hh"
+#include "iputils.hh"
+#undef L
+#include <boost/program_options.hpp>
+
+#include <boost/format.hpp>
+#include <boost/utility.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+
+#include "mplexer.hh"
+#include "statbag.hh"
+#include "arguments.hh"
+
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+#include "namespaces.hh"
+
+namespace po = boost::program_options;
+po::variables_map g_vm;
+
+StatBag S;
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+}
+
+void usage() {
+ cerr<<"Syntax: pdns_notify IP_ADDRESS[:PORT] DOMAIN"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+
+ for(int n=1 ; n < argc; ++n) {
+ if ((string) argv[n] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[n] == "--version") {
+ cerr<<"notify "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(argc!=3) {
+ usage();
+ exit(1);
+ }
+
+ int sock = socket(AF_INET, SOCK_DGRAM, 0);
+ if(sock < 0)
+ throw runtime_error("Creating socket for incoming packets: "+stringerror());
+
+
+ // ComboAddress local("127.0.0.1", (int)0);
+// if(::bind(sock, (struct sockaddr*) &local, local.getSocklen()) < 0)
+// throw runtime_error("Failed to bind local socket to address "+local.toString()+": "+stringerror());
+
+ ComboAddress pdns(argv[1], 53);
+ if(connect(sock, (struct sockaddr*) &pdns, pdns.getSocklen()) < 0)
+ throw runtime_error("Failed to connect PowerDNS socket to address "+pdns.toString()+": "+stringerror());
+
+ vector<uint8_t> outpacket;
+ DNSPacketWriter pw(outpacket, DNSName(argv[2]), QType::SOA, 1, Opcode::Notify);
+ pw.getHeader()->id = random();
+
+
+ if(send(sock, &outpacket[0], outpacket.size(), 0) < 0) {
+ throw runtime_error("Unable to send notify to PowerDNS: "+stringerror());
+ }
+
+ char buffer[1500];
+
+ int len=recv(sock, buffer, sizeof(buffer),0);
+ if(len < 0)
+ throw runtime_error("Unable to receive notification response from PowerDNS: "+stringerror());
+
+ string packet(buffer, len);
+ MOADNSParser mdp(false, packet);
+
+ cerr<<"Received notification response with error: "<<RCode::to_s(mdp.d_header.rcode)<<endl;
+ cerr<<"For: '"<<mdp.d_qname<<"'"<<endl;
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <bitset>
+#include "dnsparser.hh"
+#include "iputils.hh"
+#undef L
+#include <boost/program_options.hpp>
+
+#include <boost/format.hpp>
+#include <boost/utility.hpp>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/algorithm/string.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <grp.h>
+#include "dnsrecords.hh"
+#include "mplexer.hh"
+#include "statbag.hh"
+
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+#include "namespaces.hh"
+
+namespace po = boost::program_options;
+po::variables_map g_vm;
+
+StatBag S;
+
+SelectFDMultiplexer g_fdm;
+int g_pdnssocket;
+bool g_verbose;
+
+struct NotificationInFlight
+{
+ ComboAddress source;
+ time_t resentTime;
+ DNSName domain;
+ uint16_t origID, resentID;
+ int origSocket;
+};
+
+typedef map<uint16_t, NotificationInFlight> nifs_t;
+nifs_t g_nifs;
+
+void syslogFmt(const boost::format& fmt)
+{
+ cerr<<"nproxy: "<<fmt<<endl;
+ syslog(LOG_WARNING, "%s", str(fmt).c_str());
+}
+
+void handleOutsideUDPPacket(int fd, boost::any&)
+try
+{
+ char buffer[1500];
+ struct NotificationInFlight nif;
+ /* make sure we report enough room for IPv6 */
+ nif.source.sin4.sin_family = AF_INET6;
+ nif.origSocket = fd;
+
+ socklen_t socklen=nif.source.getSocklen();
+
+ int res=recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&nif.source, &socklen);
+ if(!res)
+ return;
+
+ if(res < 0)
+ throw runtime_error("reading packet from remote: "+stringerror());
+
+ string packet(buffer, res);
+ MOADNSParser mdp(true, packet);
+ nif.domain = mdp.d_qname;
+ nif.origID = mdp.d_header.id;
+
+
+ if(mdp.d_header.opcode == Opcode::Query && !mdp.d_header.qr && mdp.d_answers.empty() && mdp.d_qname.toString() == "pdns.nproxy." &&
+ (mdp.d_qtype == QType::TXT || mdp.d_qtype ==QType::A)) {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, mdp.d_qname, mdp.d_qtype);
+ pw.getHeader()->id = mdp.d_header.id;
+ pw.getHeader()->rd = mdp.d_header.rd;
+ pw.getHeader()->qr = 1;
+
+ pw.startRecord(mdp.d_qname, mdp.d_qtype);
+ if(mdp.d_qtype == QType::TXT) {
+ TXTRecordContent trc("\"OK\"");
+ trc.toPacket(pw);
+ }
+ else if(mdp.d_qtype == QType::A) {
+ ARecordContent arc("1.2.3.4");
+ arc.toPacket(pw);
+ }
+ pw.commit();
+
+ if(sendto(fd, &packet[0], packet.size(), 0, (struct sockaddr*)&nif.source, socklen) < 0) {
+ syslogFmt(boost::format("Unable to send health check response to external nameserver %s - %s") % nif.source.toStringWithPort() % stringerror());
+ }
+ return;
+ }
+
+ if(mdp.d_header.opcode != Opcode::Notify || mdp.d_qtype != QType::SOA) {
+ syslogFmt(boost::format("Received non-notification packet for domain '%s' from external nameserver %s") % nif.domain.toString() % nif.source.toStringWithPort());
+ return;
+ }
+ syslogFmt(boost::format("External notification received for domain '%s' from %s") % nif.domain.toString() % nif.source.toStringWithPort());
+ vector<uint8_t> outpacket;
+ DNSPacketWriter pw(outpacket, mdp.d_qname, mdp.d_qtype, 1, Opcode::Notify);
+
+ static uint16_t s_idpool;
+ pw.getHeader()->id = nif.resentID = s_idpool++;
+
+ if(send(g_pdnssocket, &outpacket[0], outpacket.size(), 0) < 0) {
+ throw runtime_error("Unable to send notify to PowerDNS: "+stringerror());
+ }
+ nif.resentTime=time(0);
+ g_nifs[nif.resentID] = nif;
+
+}
+catch(std::exception &e)
+{
+ syslogFmt(boost::format("Error parsing packet from external nameserver: %s") % e.what());
+}
+
+
+void handleInsideUDPPacket(int fd, boost::any&)
+try
+{
+ char buffer[1500];
+ struct NotificationInFlight nif;
+ /* make sure we report enough room for IPv6 */
+ nif.source.sin4.sin_family = AF_INET6;
+
+ socklen_t socklen=nif.source.getSocklen();
+
+ int len=recvfrom(fd, buffer, sizeof(buffer), 0, (struct sockaddr*)&nif.source, &socklen);
+ if(!len)
+ return;
+
+ if(len < 0)
+ throw runtime_error("reading packet from remote: "+stringerror());
+
+ string packet(buffer, len);
+ MOADNSParser mdp(false, packet);
+
+ // cerr<<"Inside notification response for: "<<mdp.d_qname<<endl;
+
+ if(!g_nifs.count(mdp.d_header.id)) {
+ syslogFmt(boost::format("Response from inner PowerDNS with unknown ID %1%") % (uint16_t)mdp.d_header.id);
+ return;
+ }
+
+ nif=g_nifs[mdp.d_header.id];
+
+ if(nif.domain != mdp.d_qname) {
+ syslogFmt(boost::format("Response from inner nameserver for different domain '%s' than original notification '%s'") % mdp.d_qname.toString() % nif.domain.toString());
+ } else {
+ if(sendto(nif.origSocket, buffer, len, 0, (sockaddr*) &nif.source, nif.source.getSocklen()) < 0) {
+ syslogFmt(boost::format("Unable to send notification response to external nameserver %s - %s") % nif.source.toStringWithPort() % stringerror());
+ }
+ else
+ syslogFmt(boost::format("Sent notification response to external nameserver %s for domain '%s'") % nif.source.toStringWithPort() % nif.domain.toString());
+ }
+ g_nifs.erase(mdp.d_header.id);
+
+}
+catch(std::exception &e)
+{
+ syslogFmt(boost::format("Error parsing packet from internal nameserver: %s") % e.what());
+}
+
+void expireOldNotifications()
+{
+ time_t limit = time(0) - 10;
+ for(nifs_t::iterator iter = g_nifs.begin(); iter != g_nifs.end(); ) {
+ if(iter->second.resentTime < limit) {
+ syslogFmt(boost::format("Notification for domain '%s' was sent to inner nameserver, but no response within 10 seconds") % iter->second.domain.toString());
+ g_nifs.erase(iter++);
+ }
+ else
+ ++iter;
+ }
+}
+
+void daemonize(int null_fd);
+
+void usage(po::options_description &desc) {
+ cerr<<"nproxy"<<endl;
+ cerr<<desc<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ reportAllTypes();
+ openlog("nproxy", LOG_NDELAY | LOG_PID, LOG_DAEMON);
+
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("version", "print the version")
+ ("powerdns-address", po::value<string>(), "IP address of PowerDNS server")
+ ("chroot", po::value<string>(), "chroot to this directory for additional security")
+ ("setuid", po::value<int>(), "setuid to this numerical user id")
+ ("setgid", po::value<int>(), "setgid to this numerical user id")
+ ("origin-address", po::value<string>()->default_value("::"), "Source address for notifications to PowerDNS")
+ ("listen-address", po::value<vector<string> >(), "IP addresses to listen on")
+ ("listen-port", po::value<int>()->default_value(53), "Source port to listen on")
+ ("daemon,d", po::value<bool>()->default_value(true), "operate in the background")
+ ("verbose,v", "be verbose");
+
+ po::store(po::command_line_parser(argc, argv).options(desc).run(), g_vm);
+ po::notify(g_vm);
+
+ if (g_vm.count("help")) {
+ usage(desc);
+ return EXIT_SUCCESS;
+ }
+
+ if (g_vm.count("version")) {
+ cerr << "nproxy " << VERSION << endl;
+ return EXIT_SUCCESS;
+ }
+
+ if(!g_vm.count("powerdns-address")) {
+ cerr<<"Mandatory setting 'powerdns-address' unset:\n"<<endl;
+ usage(desc);
+ return EXIT_FAILURE;
+ }
+
+ if(!g_vm.count("verbose")) {
+ g_verbose=true;
+ }
+
+ vector<string> addresses;
+ if(g_vm.count("listen-address"))
+ addresses=g_vm["listen-address"].as<vector<string> >();
+ else
+ addresses.push_back("::");
+
+ // create sockets to listen on
+
+ syslogFmt(boost::format("Starting up"));
+ for(vector<string>::const_iterator address = addresses.begin(); address != addresses.end(); ++address) {
+ ComboAddress local(*address, g_vm["listen-port"].as<int>());
+ int sock = socket(local.sin4.sin_family, SOCK_DGRAM, 0);
+ if(sock < 0)
+ throw runtime_error("Creating socket for incoming packets: "+stringerror());
+
+ if(::bind(sock,(sockaddr*) &local, local.getSocklen()) < 0)
+ throw runtime_error("Binding socket for incoming packets to '"+ local.toStringWithPort()+"': "+stringerror());
+
+ g_fdm.addReadFD(sock, handleOutsideUDPPacket); // add to fdmultiplexer for each socket
+ syslogFmt(boost::format("Listening for external notifications on address %s") % local.toStringWithPort());
+ }
+
+ // create socket that talks to inner PowerDNS
+ ComboAddress originAddress(g_vm["origin-address"].as<string>(), 0);
+ g_pdnssocket=socket(originAddress.sin4.sin_family, SOCK_DGRAM, 0);
+ if(g_pdnssocket < 0)
+ throw runtime_error("Creating socket for packets to PowerDNS: "+stringerror());
+
+
+ if(::bind(g_pdnssocket,(sockaddr*) &originAddress, originAddress.getSocklen()) < 0)
+ throw runtime_error("Binding local address of inward socket to '"+ originAddress.toStringWithPort()+"': "+stringerror());
+
+
+ ComboAddress pdns(g_vm["powerdns-address"].as<string>(), 53);
+ if(connect(g_pdnssocket, (struct sockaddr*) &pdns, pdns.getSocklen()) < 0)
+ throw runtime_error("Failed to connect PowerDNS socket to address "+pdns.toStringWithPort()+": "+stringerror());
+
+ syslogFmt(boost::format("Sending notifications from %s to internal address %s") % originAddress.toString() % pdns.toStringWithPort());
+
+ g_fdm.addReadFD(g_pdnssocket, handleInsideUDPPacket);
+
+ int null_fd=open("/dev/null",O_RDWR); /* open stdin */
+ if(null_fd < 0)
+ throw runtime_error("Unable to open /dev/null: "+stringerror());
+
+ if(g_vm.count("chroot")) {
+ if(chroot(g_vm["chroot"].as<string>().c_str()) < 0 || chdir("/") < 0)
+ throw runtime_error("while chrooting to "+g_vm["chroot"].as<string>());
+ syslogFmt(boost::format("Changed root to directory '%s'") % g_vm["chroot"].as<string>());
+ }
+
+ if(g_vm.count("setgid")) {
+ if(setgid(g_vm["setgid"].as<int>()) < 0)
+ throw runtime_error("while changing gid to "+std::to_string(g_vm["setgid"].as<int>()));
+ syslogFmt(boost::format("Changed gid to %d") % g_vm["setgid"].as<int>());
+ if(setgroups(0, NULL) < 0)
+ throw runtime_error("while dropping supplementary groups");
+ }
+
+ if(g_vm.count("setuid")) {
+ if(setuid(g_vm["setuid"].as<int>()) < 0)
+ throw runtime_error("while changing uid to "+std::to_string(g_vm["setuid"].as<int>()));
+ syslogFmt(boost::format("Changed uid to %d") % g_vm["setuid"].as<int>());
+ }
+
+ if(g_vm["daemon"].as<bool>()) {
+ syslogFmt(boost::format("Daemonizing"));
+ daemonize(null_fd);
+ }
+ close(null_fd);
+ syslogFmt(boost::format("Program operational"));
+
+
+ // start loop
+ struct timeval now;
+ for(;;) {
+ gettimeofday(&now, 0);
+ g_fdm.run(&now);
+ // check for notifications that have been outstanding for more than 10 seconds
+ expireOldNotifications();
+ }
+}
+catch(boost::program_options::error& e)
+{
+ syslogFmt(boost::format("Error parsing command line options: %s") % e.what());
+}
+catch(std::exception& e)
+{
+ syslogFmt(boost::format("Fatal: %s") % e.what());
+}
+catch(PDNSException& e)
+{
+ syslogFmt(boost::format("Fatal: %s") % e.reason);
+}
+
+void daemonize(int null_fd)
+{
+ if(fork())
+ exit(0); // bye bye
+
+ setsid();
+
+ dup2(null_fd,0); /* stdin */
+ dup2(null_fd,1); /* stderr */
+ dup2(null_fd,2); /* stderr */
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "base32.hh"
+#include "dnssecinfra.hh"
+
+
+StatBag S;
+
+typedef std::pair<string,string> nsec3;
+typedef set<nsec3> nsec3set;
+
+string nsec3Hash(const DNSName &qname, const string &salt, unsigned int iters)
+{
+ NSEC3PARAMRecordContent ns3prc;
+ ns3prc.d_iterations = iters;
+ ns3prc.d_salt = salt;
+ return toBase32Hex(hashQNameWithSalt(ns3prc, qname));
+}
+
+void proveOrDeny(const nsec3set &nsec3s, const DNSName &qname, const string &salt, unsigned int iters, set<DNSName> &proven, set<DNSName> &denied)
+{
+ string hashed = nsec3Hash(qname, salt, iters);
+
+ // cerr<<"proveOrDeny(.., '"<<qname<<"', ..)"<<endl;
+ // cerr<<"hashed: "<<hashed<<endl;
+ for(nsec3set::const_iterator pos=nsec3s.begin(); pos != nsec3s.end(); ++pos) {
+ string base=(*pos).first;
+ string next=(*pos).second;
+
+ if(hashed == base)
+ {
+ proven.insert(qname);
+ cout<<qname.toString()<<" ("<<hashed<<") proven by base of "<<base<<".."<<next<<endl;
+ }
+ if(hashed == next)
+ {
+ proven.insert(qname);
+ cout<<qname.toString()<<" ("<<hashed<<") proven by next of "<<base<<".."<<next<<endl;
+ }
+ if((hashed > base && hashed < next) ||
+ (next < base && (hashed < next || hashed > base)))
+ {
+ denied.insert(qname);
+ cout<<qname.toString()<<" ("<<hashed<<") denied by "<<base<<".."<<next<<endl;
+ }
+ if (base == next && base != hashed)
+ {
+ denied.insert(qname);
+ cout<<qname.toString()<<" ("<<hashed<<") denied by "<<base<<".."<<next<<endl;
+ }
+ }
+}
+
+void usage() {
+ cerr<<"nsec3dig"<<endl;
+ cerr<<"Syntax: nsec3dig IP-ADDRESS PORT QUESTION QUESTION-TYPE [recurse]\n";
+}
+
+int main(int argc, char** argv)
+try
+{
+ bool recurse=false;
+
+ reportAllTypes();
+
+ for (int i = 1; i < argc; i++) {
+ if ((string) argv[i] == "--help") {
+ usage();
+ return EXIT_SUCCESS;
+ }
+
+ if ((string) argv[i] == "--version") {
+ cerr<<"nsec3dig "<<VERSION<<endl;
+ return EXIT_SUCCESS;
+ }
+ }
+
+ if(argc < 5) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+ // FIXME: turn recurse and dnssec into proper flags or something
+ if(argc > 5 && strcmp(argv[5], "recurse")==0)
+ {
+ recurse=true;
+ }
+
+ vector<uint8_t> packet;
+ DNSName qname(argv[3]);
+ DNSPacketWriter pw(packet, qname, DNSRecordContent::TypeToNumber(argv[4]));
+
+ if(recurse)
+ {
+ pw.getHeader()->rd=true;
+ pw.getHeader()->cd=true;
+ }
+
+ pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
+ pw.commit();
+
+
+ ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
+ Socket sock(dest.sin4.sin_family, SOCK_STREAM);
+ sock.connect(dest);
+ uint16_t len;
+ len = htons(packet.size());
+ if(sock.write((char *) &len, 2) != 2)
+ throw PDNSException("tcp write failed");
+
+ sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+
+ if(sock.read((char *) &len, 2) != 2)
+ throw PDNSException("tcp read failed");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=sock.read(creply+n, len-n);
+ if(numread<0)
+ throw PDNSException("tcp read failed");
+ n+=numread;
+ }
+
+ string reply(creply, len);
+ delete[] creply;
+
+ MOADNSParser mdp(false, reply);
+ cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+
+ set<DNSName> names;
+ set<DNSName> namesseen;
+ set<DNSName> namestocheck;
+ nsec3set nsec3s;
+ string nsec3salt;
+ int nsec3iters = 0;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if(i->first.d_type == QType::NSEC3)
+ {
+ // cerr<<"got nsec3 ["<<i->first.d_name<<"]"<<endl;
+ // cerr<<i->first.d_content->getZoneRepresentation()<<endl;
+ NSEC3RecordContent r = dynamic_cast<NSEC3RecordContent&> (*(i->first.d_content));
+ // nsec3.insert(new nsec3()
+ // cerr<<toBase32Hex(r.d_nexthash)<<endl;
+ vector<string> parts;
+ string sname=i->first.d_name.toString();
+ boost::split(parts, sname /* FIXME400 */, boost::is_any_of("."));
+ nsec3s.insert(make_pair(toLower(parts[0]), toBase32Hex(r.d_nexthash)));
+ nsec3salt = r.d_salt;
+ nsec3iters = r.d_iterations;
+ }
+ else
+ {
+ // cerr<<"namesseen.insert('"<<i->first.d_name<<"')"<<endl;
+ names.insert(i->first.d_name);
+ namesseen.insert(i->first.d_name);
+ }
+
+ if(i->first.d_type == QType::CNAME)
+ {
+ namesseen.insert(DNSName(i->first.d_content->getZoneRepresentation()));
+ }
+
+ cout<<i->first.d_place-1<<"\t"<<i->first.d_name.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+ cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
+ }
+
+#if 0
+ cerr<<"got "<<names.size()<<" names"<<endl;
+ for(set<string>::const_iterator pos=names.begin(); pos != names.end(); ++pos) {
+ cerr<<"name: "<<*pos<<endl;
+ }
+ cerr<<"got "<<nsec3s.size()<<" names"<<endl;
+ for(nsec3set::const_iterator pos=nsec3s.begin(); pos != nsec3s.end(); ++pos) {
+ cerr<<"nsec3: "<<(*pos).first<<".."<<(*pos).second<<endl;
+ }
+#endif
+
+ cout<<"== nsec3 prove/deny report follows =="<<endl;
+ set<DNSName> proven;
+ set<DNSName> denied;
+ namesseen.insert(qname);
+ for(const auto &n: namesseen)
+ {
+ DNSName shorter(n);
+ do {
+ namestocheck.insert(shorter);
+ } while(shorter.chopOff());
+ }
+ for(const auto &n: namestocheck)
+ {
+ proveOrDeny(nsec3s, n, nsec3salt, nsec3iters, proven, denied);
+ proveOrDeny(nsec3s, DNSName("*")+n, nsec3salt, nsec3iters, proven, denied);
+ }
+
+ if(names.count(qname))
+ {
+ cout<<"== qname found in names, investigating NSEC3s in case it's a wildcard"<<endl;
+ // exit(EXIT_SUCCESS);
+ }
+ // cout<<"== qname not found in names, investigating denial"<<endl;
+ if(proven.count(qname))
+ {
+ cout<<"qname found proven, NODATA response?"<<endl;
+ exit(EXIT_SUCCESS);
+ }
+ DNSName shorter=qname;
+ DNSName encloser;
+ DNSName nextcloser;
+ DNSName prev(qname);
+ while(shorter.chopOff())
+ {
+ if(proven.count(shorter))
+ {
+ encloser=shorter;
+ nextcloser=prev;
+ cout<<"found closest encloser at "<<encloser.toString()<<endl;
+ cout<<"next closer is "<<nextcloser.toString()<<endl;
+ break;
+ }
+ prev=shorter;
+ }
+ if(encloser.countLabels() && nextcloser.countLabels())
+ {
+ if(denied.count(nextcloser))
+ {
+ cout<<"next closer ("<<nextcloser.toString()<<") is denied correctly"<<endl;
+ }
+ else
+ {
+ cout<<"next closer ("<<nextcloser.toString()<<") NOT denied"<<endl;
+ }
+ DNSName wcplusencloser=DNSName("*")+encloser;
+ if(denied.count(wcplusencloser))
+ {
+ cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is denied correctly"<<endl;
+ }
+ else if(proven.count(wcplusencloser))
+ {
+ cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is proven"<<endl;
+ }
+ else
+ {
+ cout<<"wildcard at encloser ("<<wcplusencloser.toString()<<") is NOT denied or proven"<<endl;
+ }
+ }
+ exit(EXIT_SUCCESS);
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+catch(PDNSException &e)
+{
+ cerr<<"Fatal: "<<e.reason<<endl;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsrecords.hh"
+
+void NSECRecordContent::report(void)
+{
+ regist(1, 47, &make, &make, "NSEC");
+}
+
+DNSRecordContent* NSECRecordContent::make(const string& content)
+{
+ return new NSECRecordContent(content);
+}
+
+NSECRecordContent::NSECRecordContent(const string& content, const string& zone)
+{
+ RecordTextReader rtr(content, zone);
+ rtr.xfrName(d_next);
+
+ while(!rtr.eof()) {
+ uint16_t type;
+ rtr.xfrType(type);
+ d_set.insert(type);
+ }
+}
+
+void NSECRecordContent::toPacket(DNSPacketWriter& pw)
+{
+ pw.xfrName(d_next);
+
+ uint8_t res[34];
+ set<uint16_t>::const_iterator i;
+ int oldWindow = -1;
+ int window = 0;
+ int len = 0;
+ string tmp;
+
+ for(i=d_set.begin(); i != d_set.end(); ++i){
+ uint16_t bit = (*i)%256;
+ window = static_cast<int>((*i) / 256);
+
+ if (window != oldWindow) {
+ if (oldWindow > -1) {
+ res[0] = static_cast<unsigned char>(oldWindow);
+ res[1] = static_cast<unsigned char>(len);
+ tmp.assign(res, res+len+2);
+ pw.xfrBlob(tmp);
+ }
+ memset(res, 0, 34);
+ oldWindow = window;
+ }
+ res[2+bit/8] |= 1 << (7-(bit%8));
+ len=1+bit/8;
+ }
+
+ res[0] = static_cast<unsigned char>(window);
+ res[1] = static_cast<unsigned char>(len);
+ tmp.assign(res, res+len+2);
+ pw.xfrBlob(tmp);
+}
+
+NSECRecordContent::DNSRecordContent* NSECRecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ NSECRecordContent* ret=new NSECRecordContent();
+ pr.xfrName(ret->d_next);
+ string bitmap;
+ pr.xfrBlob(bitmap);
+
+ // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left
+ if(bitmap.empty())
+ return ret;
+
+ if(bitmap.size() < 2)
+ throw MOADNSException("NSEC record with impossibly small bitmap");
+
+ for(unsigned int n = 0; n+1 < bitmap.size();) {
+ unsigned int window=static_cast<unsigned char>(bitmap[n++]);
+ unsigned int len=static_cast<unsigned char>(bitmap[n++]);
+
+ // end if zero padding and ensure packet length
+ if(window == 0&&len == 0) break;
+ if(n+len>bitmap.size())
+ throw MOADNSException("NSEC record with bitmap length > packet length");
+
+ for(unsigned int k=0; k < len; k++) {
+ uint8_t val=bitmap[n++];
+ for(int bit = 0; bit < 8 ; ++bit , val>>=1)
+ if(val & 1) {
+ ret->d_set.insert((7-bit) + 8*(k) + 256*window);
+ }
+ }
+ }
+ return ret;
+}
+
+string NSECRecordContent::getZoneRepresentation(bool noDot) const
+{
+ string ret;
+ RecordTextWriter rtw(ret);
+ rtw.xfrName(d_next);
+
+ for(set<uint16_t>::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) {
+ ret+=" ";
+ ret+=NumberToType(*i);
+ }
+
+ return ret;
+}
+
+////// begin of NSEC3
+
+void NSEC3RecordContent::report(void)
+{
+ regist(1, 50, &make, &make, "NSEC3");
+}
+
+DNSRecordContent* NSEC3RecordContent::make(const string& content)
+{
+ return new NSEC3RecordContent(content);
+}
+
+NSEC3RecordContent::NSEC3RecordContent(const string& content, const string& zone)
+{
+ RecordTextReader rtr(content, zone);
+ rtr.xfr8BitInt(d_algorithm);
+ rtr.xfr8BitInt(d_flags);
+ rtr.xfr16BitInt(d_iterations);
+
+ rtr.xfrHexBlob(d_salt);
+ rtr.xfrBase32HexBlob(d_nexthash);
+
+ while(!rtr.eof()) {
+ uint16_t type;
+ rtr.xfrType(type);
+ d_set.insert(type);
+ }
+}
+
+void NSEC3RecordContent::toPacket(DNSPacketWriter& pw)
+{
+ pw.xfr8BitInt(d_algorithm);
+ pw.xfr8BitInt(d_flags);
+ pw.xfr16BitInt(d_iterations);
+ pw.xfr8BitInt(d_salt.length());
+ pw.xfrBlob(d_salt);
+
+ pw.xfr8BitInt(d_nexthash.length());
+ pw.xfrBlob(d_nexthash);
+
+ uint8_t res[34];
+ set<uint16_t>::const_iterator i;
+ int oldWindow = -1;
+ int window = 0;
+ int len = 0;
+ string tmp;
+
+ for(i=d_set.begin(); i != d_set.end(); ++i){
+ uint16_t bit = (*i)%256;
+ window = static_cast<int>((*i) / 256);
+
+ if (window != oldWindow) {
+ if (oldWindow > -1) {
+ res[0] = static_cast<unsigned char>(oldWindow);
+ res[1] = static_cast<unsigned char>(len);
+ tmp.assign(res, res+len+2);
+ pw.xfrBlob(tmp);
+ }
+ memset(res, 0, 34);
+ oldWindow = window;
+ }
+ res[2+bit/8] |= 1 << (7-(bit%8));
+ len=1+bit/8;
+ }
+
+ res[0] = static_cast<unsigned char>(window);
+ res[1] = static_cast<unsigned char>(len);
+
+ if (len) {
+ tmp.assign(res, res+len+2);
+ pw.xfrBlob(tmp);
+ }
+}
+
+NSEC3RecordContent::DNSRecordContent* NSEC3RecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ NSEC3RecordContent* ret=new NSEC3RecordContent();
+ pr.xfr8BitInt(ret->d_algorithm);
+ pr.xfr8BitInt(ret->d_flags);
+ pr.xfr16BitInt(ret->d_iterations);
+ uint8_t len;
+ pr.xfr8BitInt(len);
+ pr.xfrBlob(ret->d_salt, len);
+
+ pr.xfr8BitInt(len);
+
+ pr.xfrBlob(ret->d_nexthash, len);
+
+ string bitmap;
+ pr.xfrBlob(bitmap);
+
+ // 00 06 20 00 00 00 00 03 -> NS RRSIG NSEC ( 2, 46, 47 ) counts from left
+
+ if(bitmap.empty())
+ return ret;
+
+ if(bitmap.size() < 2)
+ throw MOADNSException("NSEC3 record with impossibly small bitmap");
+
+ for(unsigned int n = 0; n+1 < bitmap.size();) {
+ unsigned int window=static_cast<unsigned char>(bitmap[n++]);
+ unsigned int len=static_cast<unsigned char>(bitmap[n++]);
+
+ // end if zero padding and ensure packet length
+ if(window == 0&&len == 0) break;
+ if(n+len>bitmap.size())
+ throw MOADNSException("NSEC record with bitmap length > packet length");
+
+ for(unsigned int k=0; k < len; k++) {
+ uint8_t val=bitmap[n++];
+ for(int bit = 0; bit < 8 ; ++bit , val>>=1)
+ if(val & 1) {
+ ret->d_set.insert((7-bit) + 8*(k) + 256*window);
+ }
+ }
+ }
+ return ret;
+}
+
+string NSEC3RecordContent::getZoneRepresentation(bool noDot) const
+{
+ string ret;
+ RecordTextWriter rtw(ret);
+ rtw.xfr8BitInt(d_algorithm);
+ rtw.xfr8BitInt(d_flags);
+ rtw.xfr16BitInt(d_iterations);
+
+ rtw.xfrHexBlob(d_salt);
+ rtw.xfrBase32HexBlob(d_nexthash);
+ for(set<uint16_t>::const_iterator i=d_set.begin(); i!=d_set.end(); ++i) {
+ ret+=" ";
+ ret+=NumberToType(*i);
+ }
+
+ return ret;
+}
+
+
+void NSEC3PARAMRecordContent::report(void)
+{
+ regist(1, 51, &make, &make, "NSEC3PARAM");
+ regist(254, 51, &make, &make, "NSEC3PARAM");
+}
+
+DNSRecordContent* NSEC3PARAMRecordContent::make(const string& content)
+{
+ return new NSEC3PARAMRecordContent(content);
+}
+
+NSEC3PARAMRecordContent::NSEC3PARAMRecordContent(const string& content, const string& zone)
+{
+ RecordTextReader rtr(content, zone);
+ rtr.xfr8BitInt(d_algorithm);
+ rtr.xfr8BitInt(d_flags);
+ rtr.xfr16BitInt(d_iterations);
+ rtr.xfrHexBlob(d_salt);
+}
+
+void NSEC3PARAMRecordContent::toPacket(DNSPacketWriter& pw)
+{
+ pw.xfr8BitInt(d_algorithm);
+ pw.xfr8BitInt(d_flags);
+ pw.xfr16BitInt(d_iterations);
+ pw.xfr8BitInt(d_salt.length());
+ // cerr<<"salt: '"<<makeHexDump(d_salt)<<"', "<<d_salt.length()<<endl;
+ pw.xfrBlob(d_salt);
+}
+
+NSEC3PARAMRecordContent::DNSRecordContent* NSEC3PARAMRecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ NSEC3PARAMRecordContent* ret=new NSEC3PARAMRecordContent();
+ pr.xfr8BitInt(ret->d_algorithm);
+ pr.xfr8BitInt(ret->d_flags);
+ pr.xfr16BitInt(ret->d_iterations);
+ uint8_t len;
+ pr.xfr8BitInt(len);
+ pr.xfrHexBlob(ret->d_salt, len);
+ return ret;
+}
+
+string NSEC3PARAMRecordContent::getZoneRepresentation(bool noDot) const
+{
+ string ret;
+ RecordTextWriter rtw(ret);
+ rtw.xfr8BitInt(d_algorithm);
+ rtw.xfr8BitInt(d_flags);
+ rtw.xfr16BitInt(d_iterations);
+ rtw.xfrHexBlob(d_salt);
+ return ret;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <openssl/obj_mac.h>
+#ifdef HAVE_LIBCRYPTO_ECDSA
+#include <openssl/ecdsa.h>
+#endif
+#include <openssl/sha.h>
+#include <openssl/rand.h>
+#include <openssl/rsa.h>
+#include <openssl/opensslv.h>
+#include "opensslsigners.hh"
+#include "dnssecinfra.hh"
+
+#if (OPENSSL_VERSION_NUMBER < 0x1010000fL || defined LIBRESSL_VERSION_NUMBER)
+/* OpenSSL < 1.1.0 needs support for threading/locking in the calling application. */
+static pthread_mutex_t *openssllocks;
+
+extern "C" {
+void openssl_pthreads_locking_callback(int mode, int type, const char *file, int line)
+{
+ if (mode & CRYPTO_LOCK) {
+ pthread_mutex_lock(&(openssllocks[type]));
+
+ }else {
+ pthread_mutex_unlock(&(openssllocks[type]));
+ }
+}
+
+unsigned long openssl_pthreads_id_callback()
+{
+ return (unsigned long)pthread_self();
+}
+}
+
+void openssl_thread_setup()
+{
+ openssllocks = (pthread_mutex_t*)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+
+ for (int i = 0; i < CRYPTO_num_locks(); i++)
+ pthread_mutex_init(&(openssllocks[i]), NULL);
+
+ CRYPTO_set_id_callback(openssl_pthreads_id_callback);
+ CRYPTO_set_locking_callback(openssl_pthreads_locking_callback);
+}
+
+void openssl_thread_cleanup()
+{
+ CRYPTO_set_locking_callback(NULL);
+
+ for (int i=0; i<CRYPTO_num_locks(); i++) {
+ pthread_mutex_destroy(&(openssllocks[i]));
+ }
+
+ OPENSSL_free(openssllocks);
+}
+
+/* compat helpers. These DO NOT do any of the checking that the libssl 1.1 functions do. */
+static inline void RSA_get0_key(const RSA* rsakey, const BIGNUM** n, const BIGNUM** e, const BIGNUM** d) {
+ *n = rsakey->n;
+ *e = rsakey->e;
+ *d = rsakey->d;
+}
+
+static inline int RSA_set0_key(RSA* rsakey, BIGNUM* n, BIGNUM* e, BIGNUM* d) {
+ if (n) {
+ BN_clear_free(rsakey->n);
+ rsakey->n = n;
+ }
+ if (e) {
+ BN_clear_free(rsakey->e);
+ rsakey->e = e;
+ }
+ if (d) {
+ BN_clear_free(rsakey->d);
+ rsakey->d = d;
+ }
+ return 1;
+}
+
+static inline void RSA_get0_factors(const RSA* rsakey, const BIGNUM** p, const BIGNUM** q) {
+ *p = rsakey->p;
+ *q = rsakey->q;
+}
+
+static inline int RSA_set0_factors(RSA* rsakey, BIGNUM* p, BIGNUM* q) {
+ BN_clear_free(rsakey->p);
+ rsakey->p = p;
+ BN_clear_free(rsakey->q);
+ rsakey->q = q;
+ return 1;
+}
+
+static inline void RSA_get0_crt_params(const RSA* rsakey, const BIGNUM** dmp1, const BIGNUM** dmq1, const BIGNUM** iqmp) {
+ *dmp1 = rsakey->dmp1;
+ *dmq1 = rsakey->dmq1;
+ *iqmp = rsakey->iqmp;
+}
+
+static inline int RSA_set0_crt_params(RSA* rsakey, BIGNUM* dmp1, BIGNUM* dmq1, BIGNUM* iqmp) {
+ BN_clear_free(rsakey->dmp1);
+ rsakey->dmp1 = dmp1;
+ BN_clear_free(rsakey->dmq1);
+ rsakey->dmq1 = dmq1;
+ BN_clear_free(rsakey->iqmp);
+ rsakey->iqmp = iqmp;
+ return 1;
+}
+
+#ifdef HAVE_LIBCRYPTO_ECDSA
+static inline void ECDSA_SIG_get0(const ECDSA_SIG* signature, const BIGNUM** pr, const BIGNUM** ps) {
+ *pr = signature->r;
+ *ps = signature->s;
+}
+
+static inline int ECDSA_SIG_set0(ECDSA_SIG* signature, BIGNUM* pr, BIGNUM* ps) {
+ BN_clear_free(signature->r);
+ BN_clear_free(signature->s);
+ signature->r = pr;
+ signature->s = ps;
+ return 1;
+}
+#endif /* HAVE_LIBCRYPTO_ECDSA */
+
+#else
+void openssl_thread_setup() {}
+void openssl_thread_cleanup() {}
+#endif
+
+
+/* seeding PRNG */
+
+void openssl_seed()
+{
+ std::string entropy;
+ entropy.reserve(1024);
+
+ unsigned int r;
+ for(int i=0; i<1024; i+=4) {
+ r=dns_random(0xffffffff);
+ entropy.append((const char*)&r, 4);
+ }
+
+ RAND_seed((const unsigned char*)entropy.c_str(), 1024);
+}
+
+
+class OpenSSLRSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit OpenSSLRSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+ int ret = RAND_status();
+ if (ret != 1) {
+ throw runtime_error(getName()+" insufficient entropy");
+ }
+ }
+
+ ~OpenSSLRSADNSCryptoKeyEngine()
+ {
+ if (d_key)
+ RSA_free(d_key);
+ }
+
+ string getName() const override { return "OpenSSL RSA"; }
+ int getBits() const override { return RSA_size(d_key) << 3; }
+
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string hash(const std::string& hash) const override;
+ std::string sign(const std::string& hash) const override;
+ bool verify(const std::string& hash, const std::string& signature) const override;
+ std::string getPubKeyHash() const override;
+ std::string getPublicKeyString() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ bool checkKey() const override;
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<OpenSSLRSADNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ static int hashSizeToKind(size_t hashSize);
+
+ RSA* d_key{NULL};
+};
+
+
+void OpenSSLRSADNSCryptoKeyEngine::create(unsigned int bits)
+{
+ BIGNUM *e = BN_new();
+ if (!e) {
+ throw runtime_error(getName()+" key generation failed, unable to allocate e");
+ }
+
+ /* RSA_F4 is a public exponent value of 65537 */
+ int res = BN_set_word(e, RSA_F4);
+
+ if (res == 0) {
+ BN_free(e);
+ throw runtime_error(getName()+" key generation failed while setting e");
+ }
+
+ RSA* key = RSA_new();
+ if (key == NULL) {
+ BN_free(e);
+ throw runtime_error(getName()+" allocation of key structure failed");
+ }
+
+ res = RSA_generate_key_ex(key, bits, e, NULL);
+ BN_free(e);
+ if (res == 0) {
+ RSA_free(key);
+ throw runtime_error(getName()+" key generation failed");
+ }
+
+ if (d_key)
+ RSA_free(d_key);
+
+ d_key = key;
+}
+
+
+DNSCryptoKeyEngine::storvector_t OpenSSLRSADNSCryptoKeyEngine::convertToISCVector() const
+{
+ storvector_t storvect;
+ typedef vector<pair<string, const BIGNUM*> > outputs_t;
+ outputs_t outputs;
+ const BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
+ RSA_get0_key(d_key, &n, &e, &d);
+ RSA_get0_factors(d_key, &p, &q);
+ RSA_get0_crt_params(d_key, &dmp1, &dmq1, &iqmp);
+ outputs.push_back(make_pair("Modulus", n));
+ outputs.push_back(make_pair("PublicExponent", e));
+ outputs.push_back(make_pair("PrivateExponent", d));
+ outputs.push_back(make_pair("Prime1", p));
+ outputs.push_back(make_pair("Prime2", q));
+ outputs.push_back(make_pair("Exponent1", dmp1));
+ outputs.push_back(make_pair("Exponent2", dmq1));
+ outputs.push_back(make_pair("Coefficient", iqmp));
+
+ string algorithm=std::to_string(d_algorithm);
+ switch(d_algorithm) {
+ case 5:
+ case 7:
+ algorithm += " (RSASHA1)";
+ break;
+ case 8:
+ algorithm += " (RSASHA256)";
+ break;
+ case 10:
+ algorithm += " (RSASHA512)";
+ break;
+ default:
+ algorithm += " (?)";
+ }
+ storvect.push_back(make_pair("Algorithm", algorithm));
+
+ for(outputs_t::value_type value : outputs) {
+ unsigned char tmp[BN_num_bytes(value.second)];
+ int len = BN_bn2bin(value.second, tmp);
+ storvect.push_back(make_pair(value.first, string((char*) tmp, len)));
+ }
+
+ return storvect;
+}
+
+
+std::string OpenSSLRSADNSCryptoKeyEngine::hash(const std::string& orig) const
+{
+ if (d_algorithm == 5 || d_algorithm == 7) {
+ /* RSA SHA1 */
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ SHA1((unsigned char*) orig.c_str(), orig.length(), hash);
+ return string((char*) hash, sizeof(hash));
+ }
+ else if (d_algorithm == 8) {
+ /* RSA SHA256 */
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
+ return string((char*) hash, sizeof(hash));
+ }
+ else if (d_algorithm == 10) {
+ /* RSA SHA512 */
+ unsigned char hash[SHA512_DIGEST_LENGTH];
+ SHA512((unsigned char*) orig.c_str(), orig.length(), hash);
+ return string((char*) hash, sizeof(hash));
+ }
+
+ throw runtime_error(getName()+" does not support hash operation for algorithm "+std::to_string(d_algorithm));
+}
+
+int OpenSSLRSADNSCryptoKeyEngine::hashSizeToKind(const size_t hashSize)
+{
+ switch(hashSize) {
+ case SHA_DIGEST_LENGTH:
+ return NID_sha1;
+ case SHA256_DIGEST_LENGTH:
+ return NID_sha256;
+ case SHA384_DIGEST_LENGTH:
+ return NID_sha384;
+ case SHA512_DIGEST_LENGTH:
+ return NID_sha512;
+ default:
+ throw runtime_error("OpenSSL RSA does not handle hash of size " + std::to_string(hashSize));
+ }
+}
+
+std::string OpenSSLRSADNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ string hash = this->hash(msg);
+ int hashKind = hashSizeToKind(hash.size());
+ unsigned char signature[RSA_size(d_key)];
+ unsigned int signatureLen = 0;
+
+ int res = RSA_sign(hashKind, (unsigned char*) hash.c_str(), hash.length(), signature, &signatureLen, d_key);
+ if (res != 1) {
+ throw runtime_error(getName()+" failed to generate signature");
+ }
+
+ return string((char*) signature, signatureLen);
+}
+
+
+bool OpenSSLRSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ string hash = this->hash(msg);
+ int hashKind = hashSizeToKind(hash.size());
+
+ int ret = RSA_verify(hashKind, (const unsigned char*) hash.c_str(), hash.length(), (unsigned char*) signature.c_str(), signature.length(), d_key);
+
+ return (ret == 1);
+}
+
+
+std::string OpenSSLRSADNSCryptoKeyEngine::getPubKeyHash() const
+{
+ const BIGNUM *n, *e, *d;
+ RSA_get0_key(d_key, &n, &e, &d);
+ unsigned char tmp[std::max(BN_num_bytes(e), BN_num_bytes(n))];
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ SHA_CTX ctx;
+
+ int res = SHA1_Init(&ctx);
+
+ if (res != 1) {
+ throw runtime_error(getName()+" failed to init hash context for generating the public key hash");
+ }
+
+ int len = BN_bn2bin(e, tmp);
+ res = SHA1_Update(&ctx, tmp, len);
+ if (res != 1) {
+ throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
+ }
+
+ len = BN_bn2bin(n, tmp);
+ res = SHA1_Update(&ctx, tmp, len);
+ if (res != 1) {
+ throw runtime_error(getName()+" failed to update hash context for generating the public key hash");
+ }
+
+ res = SHA1_Final(hash, &ctx);
+ if (res != 1) {
+ throw runtime_error(getName()+" failed to finish hash context for generating the public key hash");
+ }
+
+ return string((char*) hash, sizeof(hash));
+}
+
+
+std::string OpenSSLRSADNSCryptoKeyEngine::getPublicKeyString() const
+{
+ const BIGNUM *n, *e, *d;
+ RSA_get0_key(d_key, &n, &e, &d);
+ string keystring;
+ unsigned char tmp[std::max(BN_num_bytes(e), BN_num_bytes(n))];
+
+ int len = BN_bn2bin(e, tmp);
+ if (len < 255) {
+ keystring.assign(1, (char) (unsigned int) len);
+ } else {
+ keystring.assign(1, 0);
+ uint16_t tempLen = len;
+ tempLen = htons(tempLen);
+ keystring.append((char*)&tempLen, 2);
+ }
+ keystring.append((char *) tmp, len);
+
+ len = BN_bn2bin(n, tmp);
+ keystring.append((char *) tmp, len);
+
+ return keystring;
+}
+
+
+void OpenSSLRSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
+{
+ typedef map<string, BIGNUM**> places_t;
+ places_t places;
+ RSA* key = RSA_new();
+ if (key == NULL) {
+ throw runtime_error(getName()+" allocation of key structure failed");
+ }
+
+ BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp;
+ n = BN_new();
+ if (n == NULL) {
+ RSA_free(key);
+ throw runtime_error(getName()+" allocation of BIGNUM n failed");
+ }
+ e = BN_new();
+ if (e == NULL) {
+ RSA_free(key);
+ BN_clear_free(n);
+ throw runtime_error(getName()+" allocation of BIGNUM e failed");
+ }
+ d = BN_new();
+ if (d == NULL) {
+ RSA_free(key);
+ BN_clear_free(n);
+ BN_clear_free(e);
+ throw runtime_error(getName()+" allocation of BIGNUM d failed");
+ }
+ RSA_set0_key(key, n, e, d);
+
+ p = BN_new();
+ if (p == NULL) {
+ RSA_free(key);
+ throw runtime_error(getName()+" allocation of BIGNUM p failed");
+ }
+ q = BN_new();
+ if (q == NULL) {
+ RSA_free(key);
+ BN_clear_free(p);
+ throw runtime_error(getName()+" allocation of BIGNUM q failed");
+ }
+ RSA_set0_factors(key, p, q);
+
+ dmp1 = BN_new();
+ if (dmp1 == NULL) {
+ RSA_free(key);
+ throw runtime_error(getName()+" allocation of BIGNUM dmp1 failed");
+ }
+ dmq1 = BN_new();
+ if (dmq1 == NULL) {
+ RSA_free(key);
+ BN_clear_free(dmp1);
+ throw runtime_error(getName()+" allocation of BIGNUM dmq1 failed");
+ }
+ iqmp = BN_new();
+ if (iqmp == NULL) {
+ RSA_free(key);
+ BN_clear_free(dmq1);
+ BN_clear_free(iqmp);
+ throw runtime_error(getName()+" allocation of BIGNUM iqmp failed");
+ }
+ RSA_set0_crt_params(key, dmp1, dmq1, iqmp);
+
+ places["Modulus"]=&n;
+ places["PublicExponent"]=&e;
+ places["PrivateExponent"]=&d;
+ places["Prime1"]=&p;
+ places["Prime2"]=&q;
+ places["Exponent1"]=&dmp1;
+ places["Exponent2"]=&dmq1;
+ places["Coefficient"]=&iqmp;
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+
+ string raw;
+ for(const places_t::value_type& val : places) {
+ raw=stormap[toLower(val.first)];
+
+ if (!val.second)
+ continue;
+
+ *val.second = BN_bin2bn((unsigned char*) raw.c_str(), raw.length(), *val.second);
+ if (!*val.second) {
+ RSA_free(key);
+ throw runtime_error(getName()+" error loading " + val.first);
+ }
+ }
+
+ if (drc.d_algorithm != d_algorithm) {
+ RSA_free(key);
+ throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
+ }
+
+ if (d_key)
+ RSA_free(d_key);
+
+ d_key = key;
+}
+
+bool OpenSSLRSADNSCryptoKeyEngine::checkKey() const
+{
+ return (RSA_check_key(d_key) == 1);
+}
+
+void OpenSSLRSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ string exponent, modulus;
+ const size_t inputLen = input.length();
+ const unsigned char* raw = (const unsigned char*)input.c_str();
+
+ if (inputLen < 1) {
+ throw runtime_error(getName()+" invalid input size for the public key");
+ }
+
+ if (raw[0] != 0) {
+ const size_t exponentSize = raw[0];
+ if (inputLen < (exponentSize + 2)) {
+ throw runtime_error(getName()+" invalid input size for the public key");
+ }
+ exponent = input.substr(1, exponentSize);
+ modulus = input.substr(exponentSize + 1);
+ } else {
+ if (inputLen < 3) {
+ throw runtime_error(getName()+" invalid input size for the public key");
+ }
+ const size_t exponentSize = raw[1]*0xff + raw[2];
+ if (inputLen < (exponentSize + 4)) {
+ throw runtime_error(getName()+" invalid input size for the public key");
+ }
+ exponent = input.substr(3, exponentSize);
+ modulus = input.substr(exponentSize + 3);
+ }
+
+ RSA* key = RSA_new();
+ if (key == NULL) {
+ throw runtime_error(getName()+" allocation of key structure failed");
+ }
+
+ BIGNUM *e = BN_bin2bn((unsigned char*)exponent.c_str(), exponent.length(), NULL);
+ if (!e) {
+ RSA_free(key);
+ throw runtime_error(getName()+" error loading e value of public key");
+ }
+ BIGNUM *n = BN_bin2bn((unsigned char*)modulus.c_str(), modulus.length(), NULL);
+ if (!n) {
+ RSA_free(key);
+ throw runtime_error(getName()+" error loading n value of public key");
+ }
+
+ if (d_key)
+ RSA_free(d_key);
+
+ RSA_set0_key(key, n, e, NULL);
+ d_key = key;
+}
+
+#ifdef HAVE_LIBCRYPTO_ECDSA
+class OpenSSLECDSADNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit OpenSSLECDSADNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {
+
+ int ret = RAND_status();
+ if (ret != 1) {
+ throw runtime_error(getName()+" insufficient entropy");
+ }
+
+ d_eckey = EC_KEY_new();
+ if (d_eckey == NULL) {
+ throw runtime_error(getName()+" allocation of key structure failed");
+ }
+
+ if(d_algorithm == 13) {
+ d_ecgroup = EC_GROUP_new_by_curve_name(NID_X9_62_prime256v1);
+ d_len = 32;
+ } else if (d_algorithm == 14) {
+ d_ecgroup = EC_GROUP_new_by_curve_name(NID_secp384r1);
+ d_len = 48;
+ } else {
+ throw runtime_error(getName()+" unknown algorithm "+std::to_string(d_algorithm));
+ }
+ if (d_ecgroup == NULL) {
+ throw runtime_error(getName()+" allocation of group structure failed");
+ }
+
+ ret = EC_KEY_set_group(d_eckey,d_ecgroup);
+ if (ret != 1) {
+ throw runtime_error(getName()+" setting key group failed");
+ }
+
+ }
+
+ ~OpenSSLECDSADNSCryptoKeyEngine()
+ {
+ EC_KEY_free(d_eckey);
+ EC_GROUP_free(d_ecgroup);
+ BN_CTX_free(d_ctx);
+ }
+
+ string getName() const override { return "OpenSSL ECDSA"; }
+ int getBits() const override { return d_len << 3; }
+
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string hash(const std::string& hash) const override;
+ std::string sign(const std::string& hash) const override;
+ bool verify(const std::string& hash, const std::string& signature) const override;
+ std::string getPubKeyHash() const override;
+ std::string getPublicKeyString() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ bool checkKey() const override;
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<OpenSSLECDSADNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned int d_len;
+
+ EC_KEY *d_eckey = NULL;
+ EC_GROUP *d_ecgroup = NULL;
+ BN_CTX *d_ctx = NULL;
+};
+
+
+void OpenSSLECDSADNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if (bits >> 3 != d_len) {
+ throw runtime_error(getName()+" unknown key length of "+std::to_string(bits)+" bits requested");
+ }
+
+ int res = EC_KEY_generate_key(d_eckey);
+ if (res == 0) {
+ throw runtime_error(getName()+" key generation failed");
+ }
+}
+
+
+DNSCryptoKeyEngine::storvector_t OpenSSLECDSADNSCryptoKeyEngine::convertToISCVector() const
+{
+ storvector_t storvect;
+ string algorithm;
+
+ if(d_algorithm == 13)
+ algorithm = "13 (ECDSAP256SHA256)";
+ else if(d_algorithm == 14)
+ algorithm = "14 (ECDSAP384SHA384)";
+ else
+ algorithm = " ? (?)";
+
+ storvect.push_back(make_pair("Algorithm", algorithm));
+
+ const BIGNUM *key = EC_KEY_get0_private_key(d_eckey);
+ if (key == NULL) {
+ throw runtime_error(getName()+" private key not set");
+ }
+
+ unsigned char tmp[BN_num_bytes(key)];
+ int len = BN_bn2bin(key, tmp);
+
+ string prefix;
+ if (d_len - len)
+ prefix.append(d_len - len, 0x00);
+
+ storvect.push_back(make_pair("PrivateKey", prefix + string((char*) tmp, sizeof(tmp))));
+
+ return storvect;
+}
+
+
+std::string OpenSSLECDSADNSCryptoKeyEngine::hash(const std::string& orig) const
+{
+ if(getBits() == 256) {
+ unsigned char hash[SHA256_DIGEST_LENGTH];
+ SHA256((unsigned char*) orig.c_str(), orig.length(), hash);
+ return string((char*) hash, sizeof(hash));
+ }
+ else if(getBits() == 384) {
+ unsigned char hash[SHA384_DIGEST_LENGTH];
+ SHA384((unsigned char*) orig.c_str(), orig.length(), hash);
+ return string((char*) hash, sizeof(hash));
+ }
+
+ throw runtime_error(getName()+" does not support a hash size of "+std::to_string(getBits())+" bits");
+}
+
+
+std::string OpenSSLECDSADNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ string hash = this->hash(msg);
+
+ ECDSA_SIG *signature = ECDSA_do_sign((unsigned char*) hash.c_str(), hash.length(), d_eckey);
+ if (NULL == signature) {
+ throw runtime_error(getName()+" failed to generate signature");
+ }
+
+ string ret;
+ unsigned char tmp[d_len];
+
+ const BIGNUM *pr, *ps;
+ ECDSA_SIG_get0(signature, &pr, &ps);
+ int len = BN_bn2bin(pr, tmp);
+ if (d_len - len)
+ ret.append(d_len - len, 0x00);
+ ret.append(string((char*) tmp, len));
+
+ len = BN_bn2bin(ps, tmp);
+ if (d_len - len)
+ ret.append(d_len - len, 0x00);
+ ret.append(string((char*) tmp, len));
+
+ ECDSA_SIG_free(signature);
+
+ return ret;
+}
+
+
+bool OpenSSLECDSADNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != (d_len * 2)) {
+ throw runtime_error(getName()+" invalid signature size "+std::to_string(signature.length()));
+ }
+
+ string hash = this->hash(msg);
+
+ ECDSA_SIG *sig;
+ sig = ECDSA_SIG_new();
+ if (sig == NULL) {
+ throw runtime_error(getName()+" allocation of signature structure failed");
+ }
+
+ BIGNUM *r, *s;
+ r = BN_bin2bn((unsigned char*) signature.c_str(), d_len, NULL);
+ s = BN_bin2bn((unsigned char*) signature.c_str() + d_len, d_len, NULL);
+ if (!r || !s) {
+ if (r) {
+ BN_clear_free(r);
+ }
+ if (s) {
+ BN_clear_free(s);
+ }
+ ECDSA_SIG_free(sig);
+ throw runtime_error(getName()+" invalid signature");
+ }
+
+ ECDSA_SIG_set0(sig, r, s);
+ int ret = ECDSA_do_verify((unsigned char*) hash.c_str(), hash.length(), sig, d_eckey);
+
+ ECDSA_SIG_free(sig);
+
+ if (ret == -1){
+ throw runtime_error(getName()+" verify error");
+ }
+
+ return (ret == 1);
+}
+
+
+std::string OpenSSLECDSADNSCryptoKeyEngine::getPubKeyHash() const
+{
+ string pubKey = getPublicKeyString();
+ unsigned char hash[SHA_DIGEST_LENGTH];
+ SHA1((unsigned char*) pubKey.c_str(), pubKey.length(), hash);
+ return string((char*) hash, sizeof(hash));
+}
+
+
+std::string OpenSSLECDSADNSCryptoKeyEngine::getPublicKeyString() const
+{
+ unsigned char binaryPoint[(d_len * 2) + 1];
+
+ int ret = EC_POINT_point2oct(d_ecgroup, EC_KEY_get0_public_key(d_eckey), POINT_CONVERSION_UNCOMPRESSED, binaryPoint, sizeof(binaryPoint), d_ctx);
+ if (ret == 0) {
+ throw runtime_error(getName()+" exporting point to binary failed");
+ }
+
+ /* we skip the first byte as the other backends use
+ raw field elements, as opposed to the format described in
+ SEC1: "2.3.3 Elliptic-Curve-Point-to-Octet-String Conversion" */
+ return string((const char *)(binaryPoint + 1), sizeof(binaryPoint) - 1);
+}
+
+
+void OpenSSLECDSADNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap)
+{
+ drc.d_algorithm = atoi(stormap["algorithm"].c_str());
+
+ if (drc.d_algorithm != d_algorithm) {
+ throw runtime_error(getName()+" tried to feed an algorithm "+std::to_string(drc.d_algorithm)+" to a "+std::to_string(d_algorithm)+" key");
+ }
+
+ string privateKey = stormap["privatekey"];
+
+ BIGNUM *prv_key = BN_bin2bn((unsigned char*) privateKey.c_str(), privateKey.length(), NULL);
+ if (prv_key == NULL) {
+ throw runtime_error(getName()+" reading private key from binary failed");
+ }
+
+ int ret = EC_KEY_set_private_key(d_eckey, prv_key);
+ if (ret != 1) {
+ BN_clear_free(prv_key);
+ throw runtime_error(getName()+" setting private key failed");
+ }
+
+ EC_POINT *pub_key = EC_POINT_new(d_ecgroup);
+ if (pub_key == NULL) {
+ BN_clear_free(prv_key);
+ throw runtime_error(getName()+" allocation of public key point failed");
+ }
+
+ ret = EC_POINT_mul(d_ecgroup, pub_key, prv_key, NULL, NULL, d_ctx);
+ if (ret != 1) {
+ EC_POINT_free(pub_key);
+ BN_clear_free(prv_key);
+ throw runtime_error(getName()+" computing public key from private failed");
+ }
+
+ BN_clear_free(prv_key);
+
+ ret = EC_KEY_set_public_key(d_eckey, pub_key);
+ if (ret != 1) {
+ EC_POINT_free(pub_key);
+ throw runtime_error(getName()+" setting public key failed");
+ }
+
+ EC_POINT_free(pub_key);
+}
+
+bool OpenSSLECDSADNSCryptoKeyEngine::checkKey() const
+{
+ return (EC_KEY_check_key(d_eckey) == 1);
+}
+
+void OpenSSLECDSADNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ /* uncompressed point, from SEC1:
+ "2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion" */
+ string ecdsaPoint= "\x04";
+ ecdsaPoint.append(input);
+
+ EC_POINT *pub_key = EC_POINT_new(d_ecgroup);
+ if (pub_key == NULL) {
+ throw runtime_error(getName()+" allocation of point structure failed");
+ }
+
+ int ret = EC_POINT_oct2point(d_ecgroup, pub_key, (unsigned char*) ecdsaPoint.c_str(), ecdsaPoint.length(), d_ctx);
+ if (ret != 1) {
+ throw runtime_error(getName()+" reading ECP point from binary failed");
+ }
+
+ ret = EC_KEY_set_private_key(d_eckey, NULL);
+ if (ret == 1) {
+ EC_POINT_free(pub_key);
+ throw runtime_error(getName()+" setting private key failed");
+ }
+
+ ret = EC_KEY_set_public_key(d_eckey, pub_key);
+ if (ret != 1) {
+ EC_POINT_free(pub_key);
+ throw runtime_error(getName()+" setting public key failed");
+ }
+
+ EC_POINT_free(pub_key);
+}
+#endif
+
+
+namespace {
+ struct LoaderStruct
+ {
+ LoaderStruct()
+ {
+ DNSCryptoKeyEngine::report(5, &OpenSSLRSADNSCryptoKeyEngine::maker);
+ DNSCryptoKeyEngine::report(7, &OpenSSLRSADNSCryptoKeyEngine::maker);
+ DNSCryptoKeyEngine::report(8, &OpenSSLRSADNSCryptoKeyEngine::maker);
+ DNSCryptoKeyEngine::report(10, &OpenSSLRSADNSCryptoKeyEngine::maker);
+#ifdef HAVE_LIBCRYPTO_ECDSA
+ DNSCryptoKeyEngine::report(13, &OpenSSLECDSADNSCryptoKeyEngine::maker);
+ DNSCryptoKeyEngine::report(14, &OpenSSLECDSADNSCryptoKeyEngine::maker);
+#endif
+ }
+ } loaderOpenSSL;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <string>
+#include <pthread.h>
+#include <openssl/crypto.h>
+#include <openssl/rand.h>
+
+#include "dns_random.hh"
+
+/* pthread locking */
+void openssl_thread_setup();
+void openssl_thread_cleanup();
+
+/* seeding PRNG */
+void openssl_seed();
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "packetcache.hh"
+#include "logger.hh"
+#include "arguments.hh"
+#include "statbag.hh"
+#include <map>
+#include <boost/algorithm/string.hpp>
+
+const unsigned int PacketCache::s_mincleaninterval, PacketCache::s_maxcleaninterval;
+
+extern StatBag S;
+
+PacketCache::PacketCache()
+{
+ d_ops=0;
+ d_maps.resize(1024);
+ for(auto& mc : d_maps) {
+ pthread_rwlock_init(&mc.d_mut, 0);
+ }
+
+ d_ttl=-1;
+ d_recursivettl=-1;
+
+ d_lastclean=time(0);
+ d_cleanskipped=false;
+ d_nextclean=d_cleaninterval=4096;
+
+ S.declare("packetcache-hit");
+ S.declare("packetcache-miss");
+ S.declare("packetcache-size");
+
+ d_statnumhit=S.getPointer("packetcache-hit");
+ d_statnummiss=S.getPointer("packetcache-miss");
+ d_statnumentries=S.getPointer("packetcache-size");
+ d_doRecursion=false;
+}
+
+PacketCache::~PacketCache()
+{
+ try {
+ // WriteLock l(&d_mut);
+ vector<WriteLock*> locks;
+ for(auto& mc : d_maps) {
+ locks.push_back(new WriteLock(&mc.d_mut));
+ }
+ for(auto wl : locks) {
+ delete wl;
+ }
+ }
+ catch(...) {
+ }
+}
+
+
+
+int PacketCache::get(DNSPacket *p, DNSPacket *cached, bool recursive)
+{
+ extern StatBag S;
+
+ if(d_ttl<0)
+ getTTLS();
+
+ cleanupIfNeeded();
+
+ if(d_doRecursion && p->d.rd) { // wants recursion
+ if(!d_recursivettl) {
+ (*d_statnummiss)++;
+ return 0;
+ }
+ }
+ else { // does not
+ if(!d_ttl) {
+ (*d_statnummiss)++;
+ return 0;
+ }
+ }
+
+ if(ntohs(p->d.qdcount)!=1) // we get confused by packets with more than one question
+ return 0;
+
+ unsigned int age=0;
+ string value;
+ bool haveSomething;
+ {
+ auto& mc=getMap(p->qdomain);
+ TryReadLock l(&mc.d_mut); // take a readlock here
+ if(!l.gotIt()) {
+ S.inc("deferred-cache-lookup");
+ return 0;
+ }
+
+ uint16_t maxReplyLen = p->d_tcp ? 0xffff : p->getMaxReplyLen();
+ haveSomething=getEntryLocked(p->qdomain, p->qtype, PacketCache::PACKETCACHE, value, -1, recursive, maxReplyLen, p->d_dnssecOk, p->hasEDNS(), &age);
+ }
+ if(haveSomething) {
+ (*d_statnumhit)++;
+ if (recursive)
+ ageDNSPacket(value, age);
+ if(cached->noparse(value.c_str(), value.size()) < 0)
+ return 0;
+ cached->spoofQuestion(p); // for correct case
+ cached->qdomain=p->qdomain;
+ cached->qtype=p->qtype;
+ return 1;
+ }
+
+ // cerr<<"Packet cache miss for '"<<p->qdomain<<"', merits: "<<packetMeritsRecursion<<endl;
+ (*d_statnummiss)++;
+ return 0; // bummer
+}
+
+void PacketCache::getTTLS()
+{
+ d_ttl=::arg().asNum("cache-ttl");
+ d_recursivettl=::arg().asNum("recursive-cache-ttl");
+
+ d_doRecursion=::arg().mustDo("recursor");
+}
+
+
+void PacketCache::insert(DNSPacket *q, DNSPacket *r, bool recursive, unsigned int maxttl)
+{
+ if(d_ttl < 0)
+ getTTLS();
+
+ if(ntohs(q->d.qdcount)!=1) {
+ return; // do not try to cache packets with multiple questions
+ }
+
+ if(q->qclass != QClass::IN) // we only cache the INternet
+ return;
+
+ uint16_t maxReplyLen = q->d_tcp ? 0xffff : q->getMaxReplyLen();
+ unsigned int ourttl = recursive ? d_recursivettl : d_ttl;
+ if(!recursive) {
+ if(maxttl<ourttl)
+ ourttl=maxttl;
+ } else {
+ unsigned int minttl = r->getMinTTL();
+ if(minttl<ourttl)
+ ourttl=minttl;
+ }
+ insert(q->qdomain, q->qtype, PacketCache::PACKETCACHE, r->getString(), ourttl, -1, recursive,
+ maxReplyLen, q->d_dnssecOk, q->hasEDNS());
+}
+
+// universal key appears to be: qname, qtype, kind (packet, query cache), optionally zoneid, meritsRecursion
+void PacketCache::insert(const DNSName &qname, const QType& qtype, CacheEntryType cet, const string& value, unsigned int ttl, int zoneID,
+ bool meritsRecursion, unsigned int maxReplyLen, bool dnssecOk, bool EDNS)
+{
+ cleanupIfNeeded();
+
+ if(!ttl)
+ return;
+
+ //cerr<<"Inserting qname '"<<qname<<"', cet: "<<(int)cet<<", qtype: "<<qtype.getName()<<", ttl: "<<ttl<<", maxreplylen: "<<maxReplyLen<<", hasEDNS: "<<EDNS<<endl;
+ CacheEntry val;
+ val.created=time(0);
+ val.ttd=val.created+ttl;
+ val.qname=qname;
+ val.qtype=qtype.getCode();
+ val.value=value;
+ val.ctype=cet;
+ val.meritsRecursion=meritsRecursion;
+ val.maxReplyLen = maxReplyLen;
+ val.dnssecOk = dnssecOk;
+ val.zoneID = zoneID;
+ val.hasEDNS = EDNS;
+
+ auto& mc = getMap(val.qname);
+
+ TryWriteLock l(&mc.d_mut);
+ if(l.gotIt()) {
+ bool success;
+ cmap_t::iterator place;
+ tie(place, success)=mc.d_map.insert(val);
+
+ if(!success)
+ mc.d_map.replace(place, val);
+ else
+ (*d_statnumentries)++;
+ }
+ else
+ S.inc("deferred-cache-inserts");
+}
+
+void PacketCache::insert(const DNSName &qname, const QType& qtype, CacheEntryType cet, const vector<DNSResourceRecord>& value, unsigned int ttl, int zoneID)
+{
+ cleanupIfNeeded();
+
+ if(!ttl)
+ return;
+
+ //cerr<<"Inserting qname '"<<qname<<"', cet: "<<(int)cet<<", qtype: "<<qtype.getName()<<", ttl: "<<ttl<<", maxreplylen: "<<maxReplyLen<<", hasEDNS: "<<EDNS<<endl;
+ CacheEntry val;
+ val.created=time(0);
+ val.ttd=val.created+ttl;
+ val.qname=qname;
+ val.qtype=qtype.getCode();
+ val.drs=value;
+ val.ctype=cet;
+ val.meritsRecursion=false;
+ val.maxReplyLen = 0;
+ val.dnssecOk = false;
+ val.zoneID = zoneID;
+ val.hasEDNS = false;
+
+ auto& mc = getMap(val.qname);
+
+ TryWriteLock l(&mc.d_mut);
+ if(l.gotIt()) {
+ bool success;
+ cmap_t::iterator place;
+ tie(place, success)=mc.d_map.insert(val);
+
+ if(!success)
+ mc.d_map.replace(place, val);
+ else
+ (*d_statnumentries)++;
+ }
+ else
+ S.inc("deferred-cache-inserts");
+}
+
+
+/* clears the entire packetcache. */
+int PacketCache::purge()
+{
+ int delcount=0;
+ for(auto& mc : d_maps) {
+ WriteLock l(&mc.d_mut);
+ delcount+=mc.d_map.size();
+ mc.d_map.clear();
+ }
+ d_statnumentries->store(0);
+ return delcount;
+}
+
+int PacketCache::purgeExact(const DNSName& qname)
+{
+ int delcount=0;
+ auto& mc = getMap(qname);
+
+ WriteLock l(&mc.d_mut);
+ auto range = mc.d_map.equal_range(tie(qname));
+ if(range.first != range.second) {
+ delcount+=distance(range.first, range.second);
+ mc.d_map.erase(range.first, range.second);
+ }
+ *d_statnumentries-=delcount;
+ return delcount;
+}
+
+/* purges entries from the packetcache. If match ends on a $, it is treated as a suffix */
+int PacketCache::purge(const string &match)
+{
+ if(ends_with(match, "$")) {
+ int delcount=0;
+ string prefix(match);
+ prefix.resize(prefix.size()-1);
+ DNSName dprefix(prefix);
+ for(auto& mc : d_maps) {
+ WriteLock l(&mc.d_mut);
+ cmap_t::const_iterator iter = mc.d_map.lower_bound(tie(dprefix));
+ auto start=iter;
+
+ for(; iter != mc.d_map.end(); ++iter) {
+ if(!iter->qname.isPartOf(dprefix)) {
+ break;
+ }
+ delcount++;
+ }
+ mc.d_map.erase(start, iter);
+ }
+ *d_statnumentries-=delcount;
+ return delcount;
+ }
+ else {
+ return purgeExact(DNSName(match));
+ }
+}
+// called from ueberbackend
+bool PacketCache::getEntry(const DNSName &qname, const QType& qtype, CacheEntryType cet, vector<DNSResourceRecord>& value, int zoneID)
+{
+ if(d_ttl<0)
+ getTTLS();
+
+ cleanupIfNeeded();
+
+ auto& mc=getMap(qname);
+
+ TryReadLock l(&mc.d_mut); // take a readlock here
+ if(!l.gotIt()) {
+ S.inc( "deferred-cache-lookup");
+ return false;
+ }
+
+ return getEntryLocked(qname, qtype, cet, value, zoneID);
+}
+
+
+bool PacketCache::getEntryLocked(const DNSName &qname, const QType& qtype, CacheEntryType cet, string& value, int zoneID, bool meritsRecursion,
+ unsigned int maxReplyLen, bool dnssecOK, bool hasEDNS, unsigned int *age)
+{
+ uint16_t qt = qtype.getCode();
+ //cerr<<"Lookup for maxReplyLen: "<<maxReplyLen<<endl;
+ auto& mc=getMap(qname);
+ cmap_t::const_iterator i=mc.d_map.find(tie(qname, qt, cet, zoneID, meritsRecursion, maxReplyLen, dnssecOK, hasEDNS, *age));
+ time_t now=time(0);
+ bool ret=(i!=mc.d_map.end() && i->ttd > now);
+ if(ret) {
+ if (age)
+ *age = now - i->created;
+ value = i->value;
+ }
+
+ return ret;
+}
+
+bool PacketCache::getEntryLocked(const DNSName &qname, const QType& qtype, CacheEntryType cet, vector<DNSResourceRecord>& value, int zoneID)
+{
+ uint16_t qt = qtype.getCode();
+ //cerr<<"Lookup for maxReplyLen: "<<maxReplyLen<<endl;
+ auto& mc=getMap(qname);
+ cmap_t::const_iterator i=mc.d_map.find(tie(qname, qt, cet, zoneID));
+ time_t now=time(0);
+ bool ret=(i!=mc.d_map.end() && i->ttd > now);
+ if(ret) {
+ value = i->drs;
+ }
+ return ret;
+}
+
+
+map<char,int> PacketCache::getCounts()
+{
+ int recursivePackets=0, nonRecursivePackets=0, queryCacheEntries=0, negQueryCacheEntries=0;
+
+ for(auto& mc : d_maps) {
+ ReadLock l(&mc.d_mut);
+
+ for(cmap_t::const_iterator iter = mc.d_map.begin() ; iter != mc.d_map.end(); ++iter) {
+ if(iter->ctype == PACKETCACHE)
+ if(iter->meritsRecursion)
+ recursivePackets++;
+ else
+ nonRecursivePackets++;
+ else if(iter->ctype == QUERYCACHE) {
+ if(iter->value.empty())
+ negQueryCacheEntries++;
+ else
+ queryCacheEntries++;
+ }
+ }
+ }
+ map<char,int> ret;
+
+ ret['!']=negQueryCacheEntries;
+ ret['Q']=queryCacheEntries;
+ ret['n']=nonRecursivePackets;
+ ret['r']=recursivePackets;
+ return ret;
+}
+
+
+void PacketCache::cleanup()
+{
+ unsigned int maxCached=::arg().asNum("max-cache-entries");
+ unsigned int toTrim=0;
+
+ unsigned long cacheSize=*d_statnumentries;
+
+ if(maxCached && cacheSize > maxCached) {
+ toTrim = cacheSize - maxCached;
+ }
+
+ unsigned int lookAt=0;
+ // two modes - if toTrim is 0, just look through 10% of the cache and nuke everything that is expired
+ // otherwise, scan first 5*toTrim records, and stop once we've nuked enough
+ if(toTrim)
+ lookAt=5*toTrim;
+ else
+ lookAt=cacheSize/10;
+
+ // cerr<<"cacheSize: "<<cacheSize<<", lookAt: "<<lookAt<<", toTrim: "<<toTrim<<endl;
+ time_t now=time(0);
+ DLOG(L<<"Starting cache clean"<<endl);
+ unsigned int totErased=0;
+ for(auto& mc : d_maps) {
+ WriteLock wl(&mc.d_mut);
+ typedef cmap_t::nth_index<1>::type sequence_t;
+ sequence_t& sidx=mc.d_map.get<1>();
+ unsigned int erased=0, lookedAt=0;
+ for(sequence_t::iterator i=sidx.begin(); i != sidx.end(); lookedAt++) {
+ if(i->ttd < now) {
+ sidx.erase(i++);
+ erased++;
+ }
+ else {
+ ++i;
+ }
+
+ if(toTrim && erased > toTrim / d_maps.size())
+ break;
+
+ if(lookedAt > lookAt / d_maps.size())
+ break;
+ }
+ totErased += erased;
+ }
+ // if(totErased)
+ // cerr<<"erased: "<<totErased<<endl;
+
+ *d_statnumentries-=totErased;
+
+ DLOG(L<<"Done with cache clean"<<endl);
+}
+
+/* the logic:
+ after d_nextclean operations, we clean. We also adjust the cleaninterval
+ a bit so we slowly move it to a value where we clean roughly every 30 seconds.
+
+ If d_nextclean has reached its maximum value, we also test if we were called
+ within 30 seconds, and if so, we skip cleaning. This means that under high load,
+ we will not clean more often than every 30 seconds anyhow.
+*/
+
+void PacketCache::cleanupIfNeeded()
+{
+ if (d_ops++ == d_nextclean) {
+ int timediff = max((int)(time(0) - d_lastclean), 1);
+
+ DLOG(L<<"cleaninterval: "<<d_cleaninterval<<", timediff: "<<timediff<<endl);
+
+ if (d_cleaninterval == s_maxcleaninterval && timediff < 30) {
+ d_cleanskipped = true;
+ d_nextclean += d_cleaninterval;
+
+ DLOG(L<<"cleaning skipped, timediff: "<<timediff<<endl);
+
+ return;
+ }
+
+ if(!d_cleanskipped) {
+ d_cleaninterval=(int)(0.6*d_cleaninterval)+(0.4*d_cleaninterval*(30.0/timediff));
+ d_cleaninterval=std::max(d_cleaninterval, s_mincleaninterval);
+ d_cleaninterval=std::min(d_cleaninterval, s_maxcleaninterval);
+
+ DLOG(L<<"new cleaninterval: "<<d_cleaninterval<<endl);
+ } else {
+ d_cleanskipped = false;
+ }
+
+ d_nextclean += d_cleaninterval;
+ d_lastclean=time(0);
+ cleanup();
+ }
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PACKETCACHE_HH
+#define PACKETCACHE_HH
+
+#include <string>
+#include <utility>
+#include <map>
+#include <map>
+#include "dns.hh"
+#include <boost/version.hpp>
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+
+#include "namespaces.hh"
+#include "dnspacket.hh"
+#include "lock.hh"
+#include "statbag.hh"
+
+/** This class performs 'whole packet caching'. Feed it a question packet and it will
+ try to find an answer. If you have an answer, insert it to have it cached for later use.
+ Take care not to replace existing cache entries. While this works, it is wasteful. Only
+ insert packets that where not found by get()
+
+ Locking!
+
+ The cache itself is protected by a read/write lock. Because deleting is a two step process, which
+ first marks and then sweeps, a second lock is present to prevent simultaneous inserts and deletes.
+*/
+
+class PacketCache : public boost::noncopyable
+{
+public:
+ PacketCache();
+ ~PacketCache();
+ enum CacheEntryType { PACKETCACHE, QUERYCACHE};
+
+ void insert(DNSPacket *q, DNSPacket *r, bool recursive, unsigned int maxttl=UINT_MAX); //!< We copy the contents of *p into our cache. Do not needlessly call this to insert questions already in the cache as it wastes resources
+
+ void insert(const DNSName &qname, const QType& qtype, CacheEntryType cet, const string& value, unsigned int ttl, int zoneID=-1, bool meritsRecursion=false,
+ unsigned int maxReplyLen=512, bool dnssecOk=false, bool EDNS=false);
+
+ void insert(const DNSName &qname, const QType& qtype, CacheEntryType cet, const vector<DNSResourceRecord>& content, unsigned int ttl, int zoneID=-1);
+
+ int get(DNSPacket *p, DNSPacket *q, bool recursive); //!< We return a dynamically allocated copy out of our cache. You need to delete it. You also need to spoof in the right ID with the DNSPacket.spoofID() method.
+ bool getEntry(const DNSName &qname, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1,
+ bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false, unsigned int *age=0);
+ bool getEntry(const DNSName &qname, const QType& qtype, CacheEntryType cet, vector<DNSResourceRecord>& entry, int zoneID=-1);
+
+
+ int size() { return *d_statnumentries; } //!< number of entries in the cache
+ void cleanupIfNeeded();
+ void cleanup(); //!< force the cache to preen itself from expired packets
+ int purge();
+ int purge(const std::string& match); // could be $ terminated. Is not a dnsname!
+ int purgeExact(const DNSName& qname); // no wildcard matching here
+
+ map<char,int> getCounts();
+private:
+ bool getEntryLocked(const DNSName &content, const QType& qtype, CacheEntryType cet, string& entry, int zoneID=-1,
+ bool meritsRecursion=false, unsigned int maxReplyLen=512, bool dnssecOk=false, bool hasEDNS=false, unsigned int *age=0);
+ bool getEntryLocked(const DNSName &content, const QType& qtype, CacheEntryType cet, vector<DNSResourceRecord>& entry, int zoneID=-1);
+
+
+ struct CacheEntry
+ {
+ CacheEntry() { qtype = ctype = 0; zoneID = -1; meritsRecursion=false; dnssecOk=false; hasEDNS=false; created=0; ttd=0; maxReplyLen=512;}
+
+ DNSName qname;
+ string value;
+ vector<DNSResourceRecord> drs;
+ time_t created;
+ time_t ttd;
+
+ uint16_t qtype;
+ uint16_t ctype;
+ int zoneID;
+ unsigned int maxReplyLen;
+
+ bool meritsRecursion;
+ bool dnssecOk;
+ bool hasEDNS;
+ };
+
+ void getTTLS();
+
+ typedef multi_index_container<
+ CacheEntry,
+ indexed_by <
+ ordered_unique<
+ composite_key<
+ CacheEntry,
+ member<CacheEntry,DNSName,&CacheEntry::qname>,
+ member<CacheEntry,uint16_t,&CacheEntry::qtype>,
+ member<CacheEntry,uint16_t, &CacheEntry::ctype>,
+ member<CacheEntry,int, &CacheEntry::zoneID>,
+ member<CacheEntry,bool, &CacheEntry::meritsRecursion>,
+ member<CacheEntry,unsigned int, &CacheEntry::maxReplyLen>,
+ member<CacheEntry,bool, &CacheEntry::dnssecOk>,
+ member<CacheEntry,bool, &CacheEntry::hasEDNS>
+ >,
+ composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<uint16_t>, std::less<int>, std::less<bool>,
+ std::less<unsigned int>, std::less<bool>, std::less<bool> >
+ >,
+ sequenced<>
+ >
+ > cmap_t;
+
+
+ struct MapCombo
+ {
+ pthread_rwlock_t d_mut;
+ cmap_t d_map;
+ };
+
+ vector<MapCombo> d_maps;
+ MapCombo& getMap(const DNSName& qname)
+ {
+ return d_maps[qname.hash() % d_maps.size()];
+ }
+
+ AtomicCounter d_ops;
+ time_t d_lastclean; // doesn't need to be atomic
+ unsigned long d_nextclean;
+ unsigned int d_cleaninterval;
+ bool d_cleanskipped;
+ AtomicCounter *d_statnumhit;
+ AtomicCounter *d_statnummiss;
+ AtomicCounter *d_statnumentries;
+
+ int d_ttl;
+ int d_recursivettl;
+ bool d_doRecursion;
+
+ static const unsigned int s_mincleaninterval=1000, s_maxcleaninterval=300000;
+};
+
+
+
+#endif /* PACKETCACHE_HH */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include "base32.hh"
+#include <string>
+#include <sys/types.h>
+#include <boost/algorithm/string.hpp>
+#include "dnssecinfra.hh"
+#include "dnsseckeeper.hh"
+#include "dns.hh"
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "dnspacket.hh"
+#include "nameserver.hh"
+#include "distributor.hh"
+#include "logger.hh"
+#include "arguments.hh"
+#include "packethandler.hh"
+#include "statbag.hh"
+#include "resolver.hh"
+#include "communicator.hh"
+#include "dnsproxy.hh"
+#include "version.hh"
+#include "common_startup.hh"
+
+#if 0
+#undef DLOG
+#define DLOG(x) x
+#endif
+
+AtomicCounter PacketHandler::s_count;
+NetmaskGroup PacketHandler::s_allowNotifyFrom;
+extern string s_programname;
+
+PacketHandler::PacketHandler():B(s_programname), d_dk(&B)
+{
+ ++s_count;
+ d_doDNAME=::arg().mustDo("dname-processing");
+ d_doRecursion= ::arg().mustDo("recursor");
+ d_logDNSDetails= ::arg().mustDo("log-dns-details");
+ d_doIPv6AdditionalProcessing = ::arg().mustDo("do-ipv6-additional-processing");
+ string fname= ::arg()["lua-prequery-script"];
+ if(fname.empty())
+ {
+ d_pdl = NULL;
+ }
+ else
+ {
+ d_pdl = new AuthLua(fname);
+ }
+
+}
+
+UeberBackend *PacketHandler::getBackend()
+{
+ return &B;
+}
+
+PacketHandler::~PacketHandler()
+{
+ --s_count;
+ DLOG(L<<Logger::Error<<"PacketHandler destructor called - "<<s_count<<" left"<<endl);
+}
+
+/**
+ * This adds CDNSKEY records to the answer packet. Returns true if one was added.
+ *
+ * @param p Pointer to the DNSPacket containing the original question
+ * @param r Pointer to the DNSPacket where the records should be inserted into
+ * @param sd SOAData of the zone for which CDNSKEY records sets should be added
+ * @return bool that shows if any records were added
+**/
+bool PacketHandler::addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
+{
+ string publishCDNSKEY;
+ d_dk.getFromMeta(p->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
+ if (publishCDNSKEY != "1")
+ return false;
+
+ DNSResourceRecord rr;
+ bool haveOne=false;
+ DNSSECPrivateKey dpk;
+
+ DNSSECKeeper::keyset_t entryPoints = d_dk.getEntryPoints(p->qdomain);
+ for(const auto& value: entryPoints) {
+ rr.qtype=QType::CDNSKEY;
+ rr.ttl=sd.default_ttl;
+ rr.qname=p->qdomain;
+ rr.content=value.first.getDNSKEY().getZoneRepresentation();
+ rr.auth=true;
+ r->addRecord(rr);
+ haveOne=true;
+ }
+
+ if(::arg().mustDo("direct-dnskey")) {
+ B.lookup(QType(QType::CDNSKEY), p->qdomain, p, sd.domain_id);
+
+ while(B.get(rr)) {
+ rr.ttl=sd.default_ttl;
+ r->addRecord(rr);
+ haveOne=true;
+ }
+ }
+ return haveOne;
+}
+
+/**
+ * This adds DNSKEY records to the answer packet. Returns true if one was added.
+ *
+ * @param p Pointer to the DNSPacket containing the original question
+ * @param r Pointer to the DNSPacket where the records should be inserted into
+ * @param sd SOAData of the zone for which DNSKEY records sets should be added
+ * @return bool that shows if any records were added
+**/
+bool PacketHandler::addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd)
+{
+ DNSResourceRecord rr;
+ bool haveOne=false;
+ DNSSECPrivateKey dpk;
+
+ DNSSECKeeper::keyset_t keyset = d_dk.getKeys(p->qdomain);
+ for(const auto& value: keyset) {
+ rr.qtype=QType::DNSKEY;
+ rr.ttl=sd.default_ttl;
+ rr.qname=p->qdomain;
+ rr.content=value.first.getDNSKEY().getZoneRepresentation();
+ rr.auth=true;
+ r->addRecord(rr);
+ haveOne=true;
+ }
+
+ if(::arg().mustDo("direct-dnskey")) {
+ B.lookup(QType(QType::DNSKEY), p->qdomain, p, sd.domain_id);
+
+ while(B.get(rr)) {
+ rr.ttl=sd.default_ttl;
+ r->addRecord(rr);
+ haveOne=true;
+ }
+ }
+
+ return haveOne;
+}
+
+/**
+ * This adds CDS records to the answer packet r.
+ *
+ * @param p Pointer to the DNSPacket containing the original question.
+ * @param r Pointer to the DNSPacket where the records should be inserted into.
+ * @param sd SOAData of the zone for which CDS records sets should be added,
+ * used to determine record TTL.
+ * @return bool that shows if any records were added.
+**/
+bool PacketHandler::addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd)
+{
+ string publishCDS;
+ d_dk.getFromMeta(p->qdomain, "PUBLISH-CDS", publishCDS);
+ if (publishCDS.empty())
+ return false;
+
+ vector<string> digestAlgos;
+ stringtok(digestAlgos, publishCDS, ", ");
+
+ DNSResourceRecord rr;
+ rr.qtype=QType::CDS;
+ rr.ttl=sd.default_ttl;
+ rr.qname=p->qdomain;
+ rr.auth=true;
+
+ bool haveOne=false;
+ DNSSECPrivateKey dpk;
+
+ DNSSECKeeper::keyset_t keyset = d_dk.getEntryPoints(p->qdomain);
+
+ for(auto const &value : keyset) {
+ for(auto const &digestAlgo : digestAlgos){
+ rr.content=makeDSFromDNSKey(p->qdomain, value.first.getDNSKEY(), std::stoi(digestAlgo)).getZoneRepresentation();
+ r->addRecord(rr);
+ haveOne=true;
+ }
+ }
+
+ if(::arg().mustDo("direct-dnskey")) {
+ B.lookup(QType(QType::CDS), p->qdomain, p, sd.domain_id);
+
+ while(B.get(rr)) {
+ rr.ttl=sd.default_ttl;
+ r->addRecord(rr);
+ haveOne=true;
+ }
+ }
+
+ return haveOne;
+}
+
+/** This adds NSEC3PARAM records. Returns true if one was added */
+bool PacketHandler::addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd)
+{
+ DNSResourceRecord rr;
+
+ NSEC3PARAMRecordContent ns3prc;
+ if(d_dk.getNSEC3PARAM(p->qdomain, &ns3prc)) {
+ rr.qtype=QType::NSEC3PARAM;
+ rr.ttl=sd.default_ttl;
+ rr.qname=p->qdomain;
+ ns3prc.d_flags = 0; // the NSEC3PARAM 'flag' is defined to always be zero in RFC5155.
+ rr.content=ns3prc.getZoneRepresentation();
+ rr.auth = true;
+ r->addRecord(rr);
+ return true;
+ }
+ return false;
+}
+
+
+// This is our chaos class requests handler. Return 1 if content was added, 0 if it wasn't
+int PacketHandler::doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target)
+{
+ DNSResourceRecord rr;
+
+ if(p->qtype.getCode()==QType::TXT) {
+ static const DNSName versionbind("version.bind."), versionpdns("version.pdns."), idserver("id.server.");
+ if (target==versionbind || target==versionpdns) {
+ // modes: full, powerdns only, anonymous or custom
+ const static string mode=::arg()["version-string"];
+
+ if(mode.empty() || mode=="full")
+ rr.content=fullVersionString();
+ else if(mode=="powerdns")
+ rr.content="Served by PowerDNS - https://www.powerdns.com/";
+ else if(mode=="anonymous") {
+ r->setRcode(RCode::ServFail);
+ return 0;
+ }
+ else
+ rr.content=mode;
+ }
+ else if (target==idserver) {
+ // modes: disabled, hostname or custom
+ const static string id=::arg()["server-id"];
+
+ if (id == "disabled") {
+ r->setRcode(RCode::Refused);
+ return 0;
+ }
+ rr.content=id;
+ }
+ else {
+ r->setRcode(RCode::Refused);
+ return 0;
+ }
+
+ rr.ttl=5;
+ rr.qname=target;
+ rr.qtype=QType::TXT;
+ rr.qclass=QClass::CHAOS;
+ r->addRecord(rr);
+ return 1;
+ }
+
+ r->setRcode(RCode::NotImp);
+ return 0;
+}
+
+vector<DNSResourceRecord> PacketHandler::getBestReferralNS(DNSPacket *p, SOAData& sd, const DNSName &target)
+{
+ vector<DNSResourceRecord> ret;
+ DNSResourceRecord rr;
+ DNSName subdomain(target);
+ do {
+ if(subdomain == sd.qname) // stop at SOA
+ break;
+ B.lookup(QType(QType::NS), subdomain, p, sd.domain_id);
+ while(B.get(rr)) {
+ ret.push_back(rr); // this used to exclude auth NS records for some reason
+ }
+ if(!ret.empty())
+ return ret;
+ } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
+ return ret;
+}
+
+vector<DNSResourceRecord> PacketHandler::getBestDNAMESynth(DNSPacket *p, SOAData& sd, DNSName &target)
+{
+ vector<DNSResourceRecord> ret;
+ DNSResourceRecord rr;
+ DNSName prefix;
+ DNSName subdomain(target);
+ do {
+ DLOG(L<<"Attempting DNAME lookup for "<<subdomain<<", sd.qname="<<sd.qname<<endl);
+
+ B.lookup(QType(QType::DNAME), subdomain, p, sd.domain_id);
+ while(B.get(rr)) {
+ ret.push_back(rr); // put in the original
+ rr.qtype = QType::CNAME;
+ rr.qname = prefix + rr.qname;
+ rr.content = (prefix + DNSName(rr.content)).toStringNoDot();
+ rr.auth = 0; // don't sign CNAME
+ target= DNSName(rr.content);
+ ret.push_back(rr);
+ }
+ if(!ret.empty())
+ return ret;
+ if(subdomain.countLabels())
+ prefix.appendRawLabel(subdomain.getRawLabels()[0]);
+ if(subdomain == sd.qname) // stop at SOA
+ break;
+
+ } while( subdomain.chopOff() ); // 'www.powerdns.org' -> 'powerdns.org' -> 'org' -> ''
+ return ret;
+}
+
+
+// Return best matching wildcard or next closer name
+bool PacketHandler::getBestWildcard(DNSPacket *p, SOAData& sd, const DNSName &target, DNSName &wildcard, vector<DNSResourceRecord>* ret)
+{
+ ret->clear();
+ DNSResourceRecord rr;
+ DNSName subdomain(target);
+ bool haveSomething=false;
+
+ wildcard=subdomain;
+ while( subdomain.chopOff() && !haveSomething ) {
+ if (subdomain.empty()) {
+ B.lookup(QType(QType::ANY), DNSName("*"), p, sd.domain_id);
+ } else {
+ B.lookup(QType(QType::ANY), DNSName("*")+subdomain, p, sd.domain_id);
+ }
+ while(B.get(rr)) {
+ if(rr.qtype == p->qtype || rr.qtype.getCode() == QType::CNAME || (p->qtype.getCode() == QType::ANY && rr.qtype.getCode() != QType::RRSIG))
+ ret->push_back(rr);
+ wildcard=DNSName("*")+subdomain;
+ haveSomething=true;
+ }
+
+ if ( subdomain == sd.qname || haveSomething ) // stop at SOA or result
+ break;
+
+ B.lookup(QType(QType::ANY), subdomain, p, sd.domain_id);
+ if (B.get(rr)) {
+ DLOG(L<<"No wildcard match, ancestor exists"<<endl);
+ while (B.get(rr)) ;
+ break;
+ }
+ wildcard=subdomain;
+ }
+
+ return haveSomething;
+}
+
+/** dangling is declared true if we were unable to resolve everything */
+int PacketHandler::doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& soadata, bool retargeted)
+{
+ DNSResourceRecord rr;
+ SOAData sd;
+ sd.db=0;
+
+ if(p->qtype.getCode()!=QType::AXFR) { // this packet needs additional processing
+ vector<DNSResourceRecord *> arrs=r->getAPRecords();
+ if(arrs.empty())
+ return 1;
+
+ DLOG(L<<Logger::Warning<<"This packet needs additional processing!"<<endl);
+
+ vector<DNSResourceRecord> crrs;
+
+ for(vector<DNSResourceRecord *>::const_iterator i=arrs.begin(); i!=arrs.end(); ++i)
+ crrs.push_back(**i);
+
+ // we now have a copy, push_back on packet might reallocate!
+ for(vector<DNSResourceRecord>::const_iterator i=crrs.begin(); i!=crrs.end(); ++i) {
+ if(r->d.aa && i->qname.countLabels() && i->qtype.getCode()==QType::NS && !B.getSOA(i->qname,sd,p) && !retargeted) { // drop AA in case of non-SOA-level NS answer, except for root referral
+ r->setA(false);
+ // i->d_place=DNSResourceRecord::AUTHORITY; // XXX FIXME
+ }
+
+ string content = stripDot(i->content);
+ if(i->qtype == QType::MX || i->qtype == QType::SRV) {
+ string::size_type pos = content.find_first_not_of("0123456789");
+ if(pos != string::npos)
+ boost::erase_head(content, pos);
+ trim_left(content);
+ }
+
+ if (i->qtype.getCode()==QType::SRV) {
+ vector<string>parts;
+ stringtok(parts, content);
+ if (parts.size() >= 3) {
+ B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), DNSName(parts[2]), p);
+ }
+ else
+ continue;
+ }
+ else {
+ B.lookup(QType(d_doIPv6AdditionalProcessing ? QType::ANY : QType::A), DNSName(content), p);
+ }
+ while(B.get(rr)) {
+ if(rr.qtype.getCode() != QType::A && rr.qtype.getCode()!=QType::AAAA)
+ continue;
+ if(rr.domain_id!=i->domain_id && ::arg()["out-of-zone-additional-processing"]=="no") {
+ DLOG(L<<Logger::Warning<<"Not including out-of-zone additional processing of "<<i->qname<<" ("<<rr.qname<<")"<<endl);
+ continue; // not adding out-of-zone additional data
+ }
+
+ if(rr.auth && !rr.qname.isPartOf(soadata.qname)) // don't sign out of zone data using the main key
+ rr.auth=false;
+ rr.d_place=DNSResourceRecord::ADDITIONAL;
+ r->addRecord(rr);
+ }
+ }
+ }
+ return 1;
+}
+
+
+void PacketHandler::emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode)
+{
+ NSECRecordContent nrc;
+ nrc.d_next = next;
+
+ nrc.d_set.insert(QType::NSEC);
+ nrc.d_set.insert(QType::RRSIG);
+ if(sd.qname == name) {
+ nrc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
+ nrc.d_set.insert(QType::DNSKEY);
+ string publishCDNSKEY;
+ d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
+ if (publishCDNSKEY == "1")
+ nrc.d_set.insert(QType::CDNSKEY);
+ string publishCDS;
+ d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
+ if (! publishCDS.empty())
+ nrc.d_set.insert(QType::CDS);
+ }
+
+ DNSResourceRecord rr;
+
+ B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
+ while(B.get(rr)) {
+ if(rr.qtype.getCode() == QType::NS || rr.auth)
+ nrc.d_set.insert(rr.qtype.getCode());
+ }
+
+ rr.qname = name;
+ rr.ttl = sd.default_ttl;
+ rr.qtype = QType::NSEC;
+ rr.content = nrc.getZoneRepresentation();
+ rr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
+ rr.auth = true;
+
+ r->addRecord(rr);
+}
+
+void PacketHandler::emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent& ns3prc, const DNSName& name, const string& namehash, const string& nexthash, int mode)
+{
+ NSEC3RecordContent n3rc;
+ n3rc.d_algorithm = ns3prc.d_algorithm;
+ n3rc.d_flags = ns3prc.d_flags;
+ n3rc.d_iterations = ns3prc.d_iterations;
+ n3rc.d_salt = ns3prc.d_salt;
+ n3rc.d_nexthash = nexthash;
+
+ DNSResourceRecord rr;
+
+ if(!name.empty()) {
+ if (sd.qname == name) {
+ n3rc.d_set.insert(QType::SOA); // 1dfd8ad SOA can live outside the records table
+ n3rc.d_set.insert(QType::NSEC3PARAM);
+ n3rc.d_set.insert(QType::DNSKEY);
+ string publishCDNSKEY;
+ d_dk.getFromMeta(name, "PUBLISH-CDNSKEY", publishCDNSKEY);
+ if (publishCDNSKEY == "1")
+ n3rc.d_set.insert(QType::CDNSKEY);
+ string publishCDS;
+ d_dk.getFromMeta(name, "PUBLISH-CDS", publishCDS);
+ if (! publishCDS.empty())
+ n3rc.d_set.insert(QType::CDS);
+ }
+
+ B.lookup(QType(QType::ANY), name, NULL, sd.domain_id);
+ while(B.get(rr)) {
+ if(rr.qtype.getCode() && (rr.qtype.getCode() == QType::NS || rr.auth)) // skip empty non-terminals
+ n3rc.d_set.insert(rr.qtype.getCode());
+ }
+ }
+
+ if (n3rc.d_set.size() && !(n3rc.d_set.size() == 1 && n3rc.d_set.count(QType::NS)))
+ n3rc.d_set.insert(QType::RRSIG);
+
+ rr.qname = DNSName(toBase32Hex(namehash))+sd.qname;
+ rr.ttl = sd.default_ttl;
+ rr.qtype=QType::NSEC3;
+ rr.content=n3rc.getZoneRepresentation();
+ rr.d_place = (mode == 5 ) ? DNSResourceRecord::ANSWER: DNSResourceRecord::AUTHORITY;
+ rr.auth = true;
+
+ r->addRecord(rr);
+}
+
+/*
+ mode 0 = No Data Responses, QTYPE is not DS
+ mode 1 = No Data Responses, QTYPE is DS
+ mode 2 = Wildcard No Data Responses
+ mode 3 = Wildcard Answer Responses
+ mode 4 = Name Error Responses
+ mode 5 = Direct NSEC request
+*/
+void PacketHandler::addNSECX(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
+{
+ if(!p->d_dnssecOk && mode != 5)
+ return;
+
+ NSEC3PARAMRecordContent ns3rc;
+ bool narrow;
+ if(d_dk.getNSEC3PARAM(auth, &ns3rc, &narrow)) {
+ if (mode != 5) // no direct NSEC3 queries, rfc5155 7.2.8
+ addNSEC3(p, r, target, wildcard, auth, ns3rc, narrow, mode);
+ }
+ else {
+ addNSEC(p, r, target, wildcard, auth, mode);
+ }
+}
+
+static void incrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
+{
+ if(raw.empty())
+ return;
+
+ for(string::size_type pos=raw.size(); pos; ) {
+ --pos;
+ unsigned char c = (unsigned char)raw[pos];
+ ++c;
+ raw[pos] = (char) c;
+ if(c)
+ break;
+ }
+}
+
+static void decrementHash(std::string& raw) // I wonder if this is correct, cmouse? ;-)
+{
+ if(raw.empty())
+ return;
+
+ for(string::size_type pos=raw.size(); pos; ) {
+ --pos;
+ unsigned char c = (unsigned char)raw[pos];
+ --c;
+ raw[pos] = (char) c;
+ if(c != 0xff)
+ break;
+ }
+}
+
+
+bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, DNSName& unhashed, string& before, string& after, int mode)
+{
+ bool ret;
+ if(narrow) { // nsec3-narrow
+ ret=true;
+ before=hashed;
+ if(decrement) {
+ decrementHash(before);
+ unhashed.clear();
+ }
+ after=hashed;
+ incrementHash(after);
+ }
+ else {
+ if (decrement || mode <= 1)
+ before.clear();
+ else
+ before=' ';
+ ret=db->getBeforeAndAfterNamesAbsolute(id, toBase32Hex(hashed), unhashed, before, after);
+ before=fromBase32Hex(before);
+ after=fromBase32Hex(after);
+ }
+ // cerr<<"rgetNSEC3Hashes: "<<hashed<<", "<<unhashed<<", "<<before<<", "<<after<<endl;
+ return ret;
+}
+
+void PacketHandler::addNSEC3(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& ns3rc, bool narrow, int mode)
+{
+ DLOG(L<<"addNSEC3() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
+
+ SOAData sd;
+ if(!B.getSOAUncached(auth, sd)) {
+ DLOG(L<<"Could not get SOA for domain");
+ return;
+ }
+
+ bool doNextcloser = false;
+ string before, after, hashed;
+ DNSName unhashed, closest;
+ DNSResourceRecord rr;
+
+ if (mode == 2 || mode == 3 || mode == 4) {
+ closest=wildcard;
+ closest.chopOff();
+ } else
+ closest=target;
+
+ // add matching NSEC3 RR
+ if (mode != 3) {
+ unhashed=(mode == 0 || mode == 1 || mode == 5) ? target : closest;
+ hashed=hashQNameWithSalt(ns3rc, unhashed);
+ DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
+
+ getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after, mode);
+
+ if (((mode == 0 && ns3rc.d_flags) || mode == 1) && (hashed != before)) {
+ DLOG(L<<"No matching NSEC3, do closest (provable) encloser"<<endl);
+
+ bool doBreak = false;
+ DNSResourceRecord rr;
+ while( closest.chopOff() && (closest != sd.qname)) { // stop at SOA
+ B.lookup(QType(QType::ANY), closest, p, sd.domain_id);
+ while(B.get(rr))
+ if (rr.auth)
+ doBreak = true;
+ if(doBreak)
+ break;
+ }
+ doNextcloser = true;
+ unhashed=closest;
+ hashed=hashQNameWithSalt(ns3rc, unhashed);
+ DLOG(L<<"1 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
+
+ getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, false, unhashed, before, after);
+ }
+
+ if (!after.empty()) {
+ DLOG(L<<"Done calling for matching, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
+ emitNSEC3(r, sd, ns3rc, unhashed, before, after, mode);
+ } else if(!before.empty())
+ r->addRecord(rr);
+ }
+
+ // add covering NSEC3 RR
+ if ((mode >= 2 && mode <= 4) || doNextcloser) {
+ DNSName next(target);
+ do {
+ unhashed=next;
+ }
+ while( next.chopOff() && !(next==closest));
+
+ hashed=hashQNameWithSalt(ns3rc, unhashed);
+ DLOG(L<<"2 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
+
+ getNSEC3Hashes(narrow, sd.db,sd.domain_id, hashed, true, unhashed, before, after);
+ DLOG(L<<"Done calling for covering, hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
+ emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
+ }
+
+ // wildcard denial
+ if (mode == 2 || mode == 4) {
+ unhashed=DNSName("*")+closest;
+
+ hashed=hashQNameWithSalt(ns3rc, unhashed);
+ DLOG(L<<"3 hash: "<<toBase32Hex(hashed)<<" "<<unhashed<<endl);
+
+ getNSEC3Hashes(narrow, sd.db, sd.domain_id, hashed, (mode != 2), unhashed, before, after);
+ DLOG(L<<"Done calling for '*', hashed: '"<<toBase32Hex(hashed)<<"' before='"<<toBase32Hex(before)<<"', after='"<<toBase32Hex(after)<<"'"<<endl);
+ emitNSEC3( r, sd, ns3rc, unhashed, before, after, mode);
+ }
+}
+
+void PacketHandler::addNSEC(DNSPacket *p, DNSPacket *r, const DNSName& target, const DNSName& wildcard, const DNSName& auth, int mode)
+{
+ DLOG(L<<"addNSEC() mode="<<mode<<" auth="<<auth<<" target="<<target<<" wildcard="<<wildcard<<endl);
+
+ SOAData sd;
+ if(!B.getSOAUncached(auth, sd)) {
+ DLOG(L<<"Could not get SOA for domain"<<endl);
+ return;
+ }
+
+ DNSName before,after;
+ sd.db->getBeforeAndAfterNames(sd.domain_id, auth, target, before, after);
+ if (mode != 5 || before == target)
+ emitNSEC(r, sd, before, after, mode);
+
+ if (mode == 2 || mode == 4) {
+ // wildcard NO-DATA or wildcard denial
+ before.clear();
+ DNSName closest(wildcard);
+ if (mode == 4) {
+ closest.chopOff();
+ closest.prependRawLabel("*");
+ }
+ sd.db->getBeforeAndAfterNames(sd.domain_id, auth, closest, before, after);
+ emitNSEC(r, sd, before, after, mode);
+ }
+ return;
+}
+
+/* Semantics:
+
+- only one backend owns the SOA of a zone
+- only one AXFR per zone at a time - double startTransaction should fail
+- backends need to implement transaction semantics
+
+
+How BindBackend would implement this:
+ startTransaction makes a file
+ feedRecord sends everything to that file
+ commitTransaction moves that file atomically over the regular file, and triggers a reload
+ rollbackTransaction removes the file
+
+
+How PostgreSQLBackend would implement this:
+ startTransaction starts a sql transaction, which also deletes all records
+ feedRecord is an insert statement
+ commitTransaction commits the transaction
+ rollbackTransaction aborts it
+
+How MySQLBackend would implement this:
+ (good question!)
+
+*/
+
+int PacketHandler::trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname)
+{
+ if(p->d_tcp)
+ {
+ // do it right now if the client is TCP
+ // rarely happens
+ return trySuperMasterSynchronous(p, tsigkeyname);
+ }
+ else
+ {
+ // queue it if the client is on UDP
+ Communicator.addTrySuperMasterRequest(p);
+ return 0;
+ }
+}
+
+int PacketHandler::trySuperMasterSynchronous(DNSPacket *p, const DNSName& tsigkeyname)
+{
+ string remote = p->getRemote().toString();
+ if(p->hasEDNSSubnet() && ::arg().contains("trusted-notification-proxy", remote)) {
+ remote = p->getRealRemote().toStringNoMask();
+ }
+
+ Resolver::res_t nsset;
+ try {
+ Resolver resolver;
+ uint32_t theirserial;
+ resolver.getSoaSerial(remote,p->qdomain, &theirserial);
+ resolver.resolve(remote, p->qdomain, QType::NS, &nsset);
+ }
+ catch(ResolverException &re) {
+ L<<Logger::Error<<"Error resolving SOA or NS for "<<p->qdomain<<" at: "<< remote <<": "<<re.reason<<endl;
+ return RCode::ServFail;
+ }
+
+ // check if the returned records are NS records
+ bool haveNS=false;
+ for(const auto& ns: nsset) {
+ if(ns.qtype.getCode()==QType::NS)
+ haveNS=true;
+ }
+
+ if(!haveNS) {
+ L<<Logger::Error<<"While checking for supermaster, did not find NS for "<<p->qdomain<<" at: "<< remote <<endl;
+ return RCode::ServFail;
+ }
+
+ string nameserver, account;
+ DNSBackend *db;
+
+ if (!::arg().mustDo("allow-unsigned-supermaster") && tsigkeyname.empty()) {
+ L<<Logger::Error<<"Received unsigned NOTIFY for "<<p->qdomain<<" from potential supermaster "<<remote<<". Refusing."<<endl;
+ return RCode::Refused;
+ }
+
+ if(!B.superMasterBackend(remote, p->qdomain, nsset, &nameserver, &account, &db)) {
+ L<<Logger::Error<<"Unable to find backend willing to host "<<p->qdomain<<" for potential supermaster "<<remote<<". Remote nameservers: "<<endl;
+ for(const auto& rr: nsset) {
+ if(rr.qtype.getCode()==QType::NS)
+ L<<Logger::Error<<rr.content<<endl;
+ }
+ return RCode::Refused;
+ }
+ try {
+ db->createSlaveDomain(p->getRemote().toString(), p->qdomain, nameserver, account);
+ if (tsigkeyname.empty() == false) {
+ vector<string> meta;
+ meta.push_back(tsigkeyname.toStringNoDot());
+ db->setDomainMetadata(p->qdomain, "AXFR-MASTER-TSIG", meta);
+ }
+ }
+ catch(PDNSException& ae) {
+ L<<Logger::Error<<"Database error trying to create "<<p->qdomain<<" for potential supermaster "<<remote<<": "<<ae.reason<<endl;
+ return RCode::ServFail;
+ }
+ L<<Logger::Warning<<"Created new slave zone '"<<p->qdomain<<"' from supermaster "<<remote<<endl;
+ return RCode::NoError;
+}
+
+int PacketHandler::processNotify(DNSPacket *p)
+{
+ /* now what?
+ was this notification from an approved address?
+ was this notification approved by TSIG?
+ We determine our internal SOA id (via UeberBackend)
+ We determine the SOA at our (known) master
+ if master is higher -> do stuff
+ */
+ vector<string> meta;
+
+ if(!::arg().mustDo("slave")) {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but slave support is disabled in the configuration"<<endl;
+ return RCode::NotImp;
+ }
+
+ if(!s_allowNotifyFrom.match((ComboAddress *) &p->d_remote ) || p->d_havetsig) {
+ if (p->d_havetsig && p->getTSIGKeyname().empty() == false) {
+ L<<Logger::Notice<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<", allowed by TSIG key '"<<p->getTSIGKeyname()<<"'"<<endl;
+ } else {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but remote is not permitted by TSIG or allow-notify-from"<<endl;
+ return RCode::Refused;
+ }
+ }
+
+ DNSBackend *db=0;
+ DomainInfo di;
+ di.serial = 0;
+ if(!B.getDomainInfo(p->qdomain, di) || !(db=di.backend)) {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" for which we are not authoritative"<<endl;
+ return trySuperMaster(p, p->getTSIGKeyname());
+ }
+
+ meta.clear();
+ if (B.getDomainMetadata(p->qdomain,"AXFR-MASTER-TSIG",meta) && meta.size() > 0) {
+ if (!p->d_havetsig) {
+ if (::arg().mustDo("allow-unsigned-notify")) {
+ L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": permitted because allow-unsigned-notify";
+ } else {
+ L<<Logger::Warning<<"Received unsigned NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": refused"<<endl;
+ return RCode::Refused;
+ }
+ } else if (meta[0] != p->getTSIGKeyname().toStringNoDot()) {
+ L<<Logger::Error<<"Received secure NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<": expected TSIG key '"<<meta[0]<<", got '"<<p->getTSIGKeyname()<<"'"<<endl;
+ return RCode::Refused;
+ }
+ }
+
+ if(::arg().contains("trusted-notification-proxy", p->getRemote().toString())) {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from trusted-notification-proxy "<< p->getRemote()<<endl;
+ if(di.masters.empty()) {
+ L<<Logger::Error<<"However, "<<p->qdomain<<" does not have any masters defined"<<endl;
+ return RCode::Refused;
+ }
+ }
+ else if(::arg().mustDo("master") && di.kind == DomainInfo::Master) {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" but we are master, rejecting"<<endl;
+ return RCode::Refused;
+ }
+ else if(!db->isMaster(p->qdomain, p->getRemote().toString())) {
+ L<<Logger::Error<<"Received NOTIFY for "<<p->qdomain<<" from "<<p->getRemote()<<" which is not a master"<<endl;
+ return RCode::Refused;
+ }
+
+ // ok, we've done our checks
+ di.backend = 0;
+ Communicator.addSlaveCheckRequest(di, p->d_remote);
+ return 0;
+}
+
+bool validDNSName(const DNSName &name)
+{
+ if (!g_8bitDNS) {
+ string::size_type pos, length;
+ char c;
+ for(const auto& s : name.getRawLabels()) {
+ length=s.length();
+ for(pos=0; pos < length; ++pos) {
+ c=s[pos];
+ if(!((c >= 'a' && c <= 'z') ||
+ (c >= 'A' && c <= 'Z') ||
+ (c >= '0' && c <= '9') ||
+ c =='-' || c == '_' || c=='*' || c=='.' || c=='/' || c=='@' || c==' ' || c=='\\' || c==':'))
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+DNSPacket *PacketHandler::question(DNSPacket *p)
+{
+ DNSPacket *ret;
+ int policyres = PolicyDecision::PASS;
+
+ if(d_pdl)
+ {
+ ret=d_pdl->prequery(p);
+ if(ret)
+ return ret;
+ }
+
+ if(p->d.rd) {
+ static AtomicCounter &rdqueries=*S.getPointer("rd-queries");
+ rdqueries++;
+ }
+
+ if(LPE)
+ {
+ policyres = LPE->police(p, NULL);
+ }
+
+ if (policyres == PolicyDecision::DROP)
+ return NULL;
+
+ if (policyres == PolicyDecision::TRUNCATE) {
+ ret=p->replyPacket(); // generate an empty reply packet
+ ret->d.tc = 1;
+ ret->commitD();
+ return ret;
+ }
+
+ bool shouldRecurse=false;
+ ret=questionOrRecurse(p, &shouldRecurse);
+ if(shouldRecurse) {
+ DP->sendPacket(p);
+ }
+ if(LPE) {
+ int policyres=LPE->police(p, ret);
+ if(policyres == PolicyDecision::DROP) {
+ delete ret;
+ return NULL;
+ }
+ if (policyres == PolicyDecision::TRUNCATE) {
+ delete ret;
+ ret=p->replyPacket(); // generate an empty reply packet
+ ret->d.tc = 1;
+ ret->commitD();
+ }
+
+ }
+ return ret;
+}
+
+void PacketHandler::makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd)
+{
+ DNSResourceRecord rr;
+ rr.qname=sd.qname;
+ rr.qtype=QType::SOA;
+ rr.content=serializeSOAData(sd);
+ rr.ttl=min(sd.ttl, sd.default_ttl);
+ rr.signttl=sd.ttl;
+ rr.domain_id=sd.domain_id;
+ rr.d_place=DNSResourceRecord::AUTHORITY;
+ rr.auth = 1;
+ rr.scopeMask = sd.scopeMask;
+ r->addRecord(rr);
+
+ if(d_dk.isSecuredZone(sd.qname))
+ addNSECX(p, r, target, wildcard, sd.qname, 4);
+
+ r->setRcode(RCode::NXDomain);
+}
+
+void PacketHandler::makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode)
+{
+ DNSResourceRecord rr;
+ rr.qname=sd.qname;
+ rr.qtype=QType::SOA;
+ rr.content=serializeSOAData(sd);
+ rr.ttl=sd.ttl;
+ rr.ttl=min(sd.ttl, sd.default_ttl);
+ rr.signttl=sd.ttl;
+ rr.domain_id=sd.domain_id;
+ rr.d_place=DNSResourceRecord::AUTHORITY;
+ rr.auth = 1;
+ r->addRecord(rr);
+
+ if(d_dk.isSecuredZone(sd.qname))
+ addNSECX(p, r, target, wildcard, sd.qname, mode);
+
+ S.ringAccount("noerror-queries",p->qdomain.toLogString()+"/"+p->qtype.getName());
+}
+
+
+bool PacketHandler::addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname)
+{
+ //cerr<<"Trying to find a DS for '"<<dsname<<"', domain_id = "<<sd.domain_id<<endl;
+ B.lookup(QType(QType::DS), dsname, p, sd.domain_id);
+ DNSResourceRecord rr;
+ bool gotOne=false;
+ while(B.get(rr)) {
+ gotOne=true;
+ rr.d_place = DNSResourceRecord::AUTHORITY;
+ r->addRecord(rr);
+ }
+ return gotOne;
+}
+
+bool PacketHandler::tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted)
+{
+ vector<DNSResourceRecord> rrset = getBestReferralNS(p, sd, target);
+ if(rrset.empty())
+ return false;
+
+ DLOG(L<<"The best NS is: "<<rrset.begin()->qname<<endl);
+ for(auto& rr: rrset) {
+ DLOG(L<<"\tadding '"<<rr.content<<"'"<<endl);
+ rr.d_place=DNSResourceRecord::AUTHORITY;
+ r->addRecord(rr);
+ }
+ if(!retargeted)
+ r->setA(false);
+
+ if(d_dk.isSecuredZone(sd.qname) && !addDSforNS(p, r, sd, rrset.begin()->qname))
+ addNSECX(p, r, rrset.begin()->qname, DNSName(), sd.qname, 1);
+
+ return true;
+}
+
+void PacketHandler::completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target)
+{
+ if(!p->d_dnssecOk)
+ return; // Don't send dnssec info to non validating resolvers.
+
+ if(!d_dk.isSecuredZone(sd.qname))
+ return;
+
+ addNSECX(p, r, target, DNSName(), sd.qname, 5);
+ if(sd.qname == p->qdomain) {
+ addDNSKEY(p, r, sd);
+ addCDNSKEY(p, r, sd);
+ addCDS(p, r, sd);
+ addNSEC3PARAM(p, r, sd);
+ }
+}
+
+bool PacketHandler::tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target)
+{
+ if(!d_doDNAME)
+ return false;
+ DLOG(L<<Logger::Warning<<"Let's try DNAME.."<<endl);
+ vector<DNSResourceRecord> rrset = getBestDNAMESynth(p, sd, target);
+ if(!rrset.empty()) {
+ for(auto& rr: rrset) {
+ rr.d_place = DNSResourceRecord::ANSWER;
+ r->addRecord(rr);
+ }
+ return true;
+ }
+ return false;
+}
+bool PacketHandler::tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata)
+{
+ retargeted = nodata = false;
+ DNSName bestmatch;
+
+ vector<DNSResourceRecord> rrset;
+ if(!getBestWildcard(p, sd, target, wildcard, &rrset))
+ return false;
+
+ if(rrset.empty()) {
+ DLOG(L<<"Wildcard matched something, but not of the correct type"<<endl);
+ nodata=true;
+ }
+ else {
+ DLOG(L<<"The best wildcard match: "<<rrset.begin()->qname<<endl);
+ for(auto& rr: rrset) {
+ rr.wildcardname = rr.qname;
+ rr.qname=bestmatch=target;
+
+ if(rr.qtype.getCode() == QType::CNAME) {
+ retargeted=true;
+ target=DNSName(rr.content);
+ }
+
+ DLOG(L<<"\tadding '"<<rr.content<<"'"<<endl);
+ rr.d_place=DNSResourceRecord::ANSWER;
+ r->addRecord(rr);
+ }
+ }
+ if(d_dk.isSecuredZone(sd.qname) && !nodata) {
+ addNSECX(p, r, bestmatch, wildcard, sd.qname, 3);
+ }
+ return true;
+}
+
+//! Called by the Distributor to ask a question. Returns 0 in case of an error
+DNSPacket *PacketHandler::questionOrRecurse(DNSPacket *p, bool *shouldRecurse)
+{
+ *shouldRecurse=false;
+ DNSResourceRecord rr;
+ SOAData sd;
+
+ // string subdomain="";
+ string soa;
+ int retargetcount=0;
+ set<DNSName> authSet;
+
+ vector<DNSResourceRecord> rrset;
+ bool weDone=0, weRedirected=0, weHaveUnauth=0;
+ DNSName haveAlias;
+
+ DNSPacket *r=0;
+ bool noCache=false;
+
+ if(p->d.qr) { // QR bit from dns packet (thanks RA from N)
+ if(d_logDNSDetails)
+ L<<Logger::Error<<"Received an answer (non-query) packet from "<<p->getRemote()<<", dropping"<<endl;
+ S.inc("corrupt-packets");
+ S.ringAccount("remotes-corrupt", p->d_remote);
+ return 0;
+ }
+
+ if(p->d.tc) { // truncated query. MOADNSParser would silently parse this packet in an incomplete way.
+ if(d_logDNSDetails)
+ L<<Logger::Error<<"Received truncated query packet from "<<p->getRemote()<<", dropping"<<endl;
+ S.inc("corrupt-packets");
+ S.ringAccount("remotes-corrupt", p->d_remote);
+ return 0;
+ }
+
+ if (p->hasEDNS() && p->getEDNSVersion() > 0) {
+ r = p->replyPacket();
+ r->setRcode(16 & 0xF);
+ r->setEDNSRcode((16 & 0xFFF0)>>4); // set rcode to BADVERS
+ return r;
+ }
+
+ if(p->d_havetsig) {
+ DNSName keyname;
+ string secret;
+ TSIGRecordContent trc;
+ if(!checkForCorrectTSIG(p, &B, &keyname, &secret, &trc)) {
+ r=p->replyPacket(); // generate an empty reply packet
+ if(d_logDNSDetails)
+ L<<Logger::Error<<"Received a TSIG signed message with a non-validating key"<<endl;
+ // RFC3007 describes that a non-secure message should be sending Refused for DNS Updates
+ if (p->d.opcode == Opcode::Update)
+ r->setRcode(RCode::Refused);
+ else
+ r->setRcode(RCode::NotAuth);
+ return r;
+ } else {
+ getTSIGHashEnum(trc.d_algoName, p->d_tsig_algo);
+ if (p->d_tsig_algo == TSIG_GSS) {
+ GssContext gssctx(keyname);
+ if (!gssctx.getPeerPrincipal(p->d_peer_principal)) {
+ L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
+ }
+ }
+ }
+ p->setTSIGDetails(trc, keyname, secret, trc.d_mac); // this will get copied by replyPacket()
+ noCache=true;
+ }
+
+ r=p->replyPacket(); // generate an empty reply packet, possibly with TSIG details inside
+
+ if (p->qtype == QType::TKEY) {
+ this->tkeyHandler(p, r);
+ return r;
+ }
+
+ try {
+
+ // XXX FIXME do this in DNSPacket::parse ?
+
+ if(!validDNSName(p->qdomain)) {
+ if(d_logDNSDetails)
+ L<<Logger::Error<<"Received a malformed qdomain from "<<p->getRemote()<<", '"<<p->qdomain<<"': sending servfail"<<endl;
+ S.inc("corrupt-packets");
+ S.ringAccount("remotes-corrupt", p->d_remote);
+ S.inc("servfail-packets");
+ r->setRcode(RCode::ServFail);
+ return r;
+ }
+ if(p->d.opcode) { // non-zero opcode (again thanks RA!)
+ if(p->d.opcode==Opcode::Update) {
+ S.inc("dnsupdate-queries");
+ int res=processUpdate(p);
+ if (res == RCode::Refused)
+ S.inc("dnsupdate-refused");
+ else if (res != RCode::ServFail)
+ S.inc("dnsupdate-answers");
+ r->setRcode(res);
+ r->setOpcode(Opcode::Update);
+ return r;
+ }
+ else if(p->d.opcode==Opcode::Notify) {
+ S.inc("incoming-notifications");
+ int res=processNotify(p);
+ if(res>=0) {
+ r->setRcode(res);
+ r->setOpcode(Opcode::Notify);
+ return r;
+ }
+ delete r;
+ return 0;
+ }
+
+ L<<Logger::Error<<"Received an unknown opcode "<<p->d.opcode<<" from "<<p->getRemote()<<" for "<<p->qdomain<<endl;
+
+ r->setRcode(RCode::NotImp);
+ return r;
+ }
+
+ // L<<Logger::Warning<<"Query for '"<<p->qdomain<<"' "<<p->qtype.getName()<<" from "<<p->getRemote()<< " (tcp="<<p->d_tcp<<")"<<endl;
+
+ r->d.ra = (p->d.rd && d_doRecursion && DP->recurseFor(p)); // make sure we set ra if rd was set, and we'll do it
+
+ if(p->qtype.getCode()==QType::IXFR) {
+ r->setRcode(RCode::NotImp);
+ return r;
+ }
+
+ DNSName target=p->qdomain;
+
+ // catch chaos qclass requests
+ if(p->qclass == QClass::CHAOS) {
+ if (doChaosRequest(p,r,target))
+ goto sendit;
+ else
+ return r;
+ }
+
+ // we only know about qclass IN (and ANY), send NotImp for everything else.
+ if(p->qclass != QClass::IN && p->qclass!=QClass::ANY) {
+ r->setRcode(RCode::NotImp);
+ return r;
+ }
+
+ // send TC for udp ANY query if any-to-tcp is enabled.
+ if(p->qtype.getCode() == QType::ANY && !p->d_tcp && g_anyToTcp) {
+ r->d.tc = 1;
+ r->commitD();
+ return r;
+ }
+
+ // for qclass ANY the response should never be authoritative unless the response covers all classes.
+ if(p->qclass==QClass::ANY)
+ r->setA(false);
+
+
+ retargeted:;
+ if(retargetcount > 10) { // XXX FIXME, retargetcount++?
+ L<<Logger::Warning<<"Abort CNAME chain resolution after "<<--retargetcount<<" redirects, sending out servfail. Initial query: '"<<p->qdomain<<"'"<<endl;
+ delete r;
+ r=p->replyPacket();
+ r->setRcode(RCode::ServFail);
+ return r;
+ }
+
+ if(!B.getAuth(p, &sd, target)) {
+ DLOG(L<<Logger::Error<<"We have no authority over zone '"<<target<<"'"<<endl);
+ if(r->d.ra) {
+ DLOG(L<<Logger::Error<<"Recursion is available for this remote, doing that"<<endl);
+ *shouldRecurse=true;
+ delete r;
+ return 0;
+ }
+
+ if(!retargetcount) {
+ r->setA(false); // drop AA if we never had a SOA in the first place
+ r->setRcode(RCode::Refused); // send REFUSED - but only on empty 'no idea'
+ }
+ goto sendit;
+ }
+ DLOG(L<<Logger::Error<<"We have authority, zone='"<<sd.qname<<"', id="<<sd.domain_id<<endl);
+ authSet.insert(sd.qname);
+
+ if(!retargetcount) r->qdomainzone=sd.qname;
+
+ if(sd.qname==p->qdomain) {
+ if(p->qtype.getCode() == QType::DNSKEY)
+ {
+ if(addDNSKEY(p, r, sd))
+ goto sendit;
+ }
+ else if(p->qtype.getCode() == QType::CDNSKEY)
+ {
+ if(addCDNSKEY(p,r, sd))
+ goto sendit;
+ }
+ else if(p->qtype.getCode() == QType::CDS)
+ {
+ if(addCDS(p,r, sd))
+ goto sendit;
+ }
+ else if(p->qtype.getCode() == QType::NSEC3PARAM && d_dk.isSecuredZone(sd.qname))
+ {
+ if(addNSEC3PARAM(p,r, sd))
+ goto sendit;
+ }
+ }
+
+ if(p->qtype.getCode() == QType::SOA && sd.qname==p->qdomain) {
+ rr.qname=sd.qname;
+ rr.qtype=QType::SOA;
+ rr.content=serializeSOAData(sd);
+ rr.ttl=sd.ttl;
+ rr.domain_id=sd.domain_id;
+ rr.d_place=DNSResourceRecord::ANSWER;
+ rr.auth = true;
+ r->addRecord(rr);
+ goto sendit;
+ }
+
+ // this TRUMPS a cname!
+ if(p->qtype.getCode() == QType::NSEC && d_dk.isSecuredZone(sd.qname) && !d_dk.getNSEC3PARAM(sd.qname, 0)) {
+ addNSEC(p, r, target, DNSName(), sd.qname, 5);
+ if (!r->isEmpty())
+ goto sendit;
+ }
+
+ // this TRUMPS a cname!
+ if(p->qtype.getCode() == QType::RRSIG) {
+ L<<Logger::Info<<"Direct RRSIG query for "<<target<<" from "<<p->getRemote()<<endl;
+ r->setRcode(RCode::NotImp);
+ goto sendit;
+ }
+
+ DLOG(L<<"Checking for referrals first, unless this is a DS query"<<endl);
+ if(p->qtype.getCode() != QType::DS && tryReferral(p, r, sd, target, retargetcount))
+ goto sendit;
+
+ DLOG(L<<"Got no referrals, trying ANY"<<endl);
+
+ // see what we get..
+ B.lookup(QType(QType::ANY), target, p, sd.domain_id);
+ rrset.clear();
+ haveAlias.trimToLabels(0);
+ weDone = weRedirected = weHaveUnauth = false;
+
+ while(B.get(rr)) {
+ //cerr<<"got content: ["<<rr.content<<"]"<<endl;
+ if (p->qtype.getCode() == QType::ANY && !p->d_dnssecOk && (rr.qtype.getCode() == QType:: DNSKEY || rr.qtype.getCode() == QType::NSEC3PARAM))
+ continue; // Don't send dnssec info to non validating resolvers.
+ if (rr.qtype.getCode() == QType::RRSIG) // RRSIGS are added later any way.
+ continue; // TODO: this actually means addRRSig should check if the RRSig is already there
+
+ // cerr<<"Auth: "<<rr.auth<<", "<<(rr.qtype == p->qtype)<<", "<<rr.qtype.getName()<<endl;
+ if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.auth)
+ weDone=1;
+ // the line below fakes 'unauth NS' for delegations for non-DNSSEC backends.
+ if((rr.qtype == p->qtype && !rr.auth) || (rr.qtype.getCode() == QType::NS && (!rr.auth || !(sd.qname==rr.qname))))
+ weHaveUnauth=1;
+
+ if(rr.qtype.getCode() == QType::CNAME && p->qtype.getCode() != QType::CNAME)
+ weRedirected=1;
+
+ if(DP && rr.qtype.getCode() == QType::ALIAS && (p->qtype.getCode() == QType::A || p->qtype.getCode() == QType::AAAA || p->qtype.getCode() == QType::ANY)) {
+ haveAlias=DNSName(rr.content);
+ }
+
+ // Filter out all SOA's and add them in later
+ if(rr.qtype.getCode() == QType::SOA)
+ continue;
+
+ rrset.push_back(rr);
+ }
+
+ /* Add in SOA if required */
+ if(target==sd.qname) {
+ rr.qtype = QType::SOA;
+ rr.content = serializeSOAData(sd);
+ rr.qname = sd.qname;
+ rr.ttl = sd.ttl;
+ rr.domain_id = sd.domain_id;
+ rr.auth = true;
+ rrset.push_back(rr);
+ }
+
+
+ DLOG(L<<"After first ANY query for '"<<target<<"', id="<<sd.domain_id<<": weDone="<<weDone<<", weHaveUnauth="<<weHaveUnauth<<", weRedirected="<<weRedirected<<", haveAlias='"<<haveAlias<<"'"<<endl);
+ if(p->qtype.getCode() == QType::DS && weHaveUnauth && !weDone && !weRedirected && d_dk.isSecuredZone(sd.qname)) {
+ DLOG(L<<"Q for DS of a name for which we do have NS, but for which we don't have on a zone with DNSSEC need to provide an AUTH answer that proves we don't"<<endl);
+ makeNOError(p, r, target, DNSName(), sd, 1);
+ goto sendit;
+ }
+
+ if(!haveAlias.empty() && (!weDone || p->qtype.getCode() == QType::ANY)) {
+ DLOG(L<<Logger::Warning<<"Found nothing that matched for '"<<target<<"', but did get alias to '"<<haveAlias<<"', referring"<<endl);
+ DP->completePacket(r, haveAlias, target);
+ return 0;
+ }
+
+ if(rrset.empty()) {
+ DLOG(L<<"checking qtype.getCode() ["<<(p->qtype.getCode())<<"] against QType::DS ["<<(QType::DS)<<"]"<<endl);
+ if(p->qtype.getCode() == QType::DS)
+ {
+ DLOG(L<<"DS query found no direct result, trying referral now"<<endl);
+ if(tryReferral(p, r, sd, target, retargetcount))
+ {
+ DLOG(L<<"got referral for DS query"<<endl);
+ goto sendit;
+ }
+ }
+
+
+ DLOG(L<<Logger::Warning<<"Found nothing in the by-name ANY, but let's try wildcards.."<<endl);
+ bool wereRetargeted(false), nodata(false);
+ DNSName wildcard;
+ if(tryWildcard(p, r, sd, target, wildcard, wereRetargeted, nodata)) {
+ if(wereRetargeted) {
+ if(!retargetcount) r->qdomainwild=wildcard;
+ retargetcount++;
+ goto retargeted;
+ }
+ if(nodata)
+ makeNOError(p, r, target, wildcard, sd, 2);
+
+ goto sendit;
+ }
+ else if(tryDNAME(p, r, sd, target)) {
+ retargetcount++;
+ goto retargeted;
+ }
+ else
+ {
+ if (!(((p->qtype.getCode() == QType::CNAME) || (p->qtype.getCode() == QType::ANY)) && retargetcount > 0))
+ makeNXDomain(p, r, target, wildcard, sd);
+ }
+
+ goto sendit;
+ }
+
+ if(weRedirected) {
+ for(auto& rr: rrset) {
+ if(rr.qtype.getCode() == QType::CNAME) {
+ r->addRecord(rr);
+ target = DNSName(rr.content);
+ retargetcount++;
+ goto retargeted;
+ }
+ }
+ }
+ else if(weDone) {
+ bool haveRecords = false;
+ for(const auto& rr: rrset) {
+ if((p->qtype.getCode() == QType::ANY || rr.qtype == p->qtype) && rr.qtype.getCode() && rr.qtype != QType::ALIAS && rr.auth) {
+ r->addRecord(rr);
+ haveRecords = true;
+ }
+ }
+
+ if (haveRecords) {
+ if(p->qtype.getCode() == QType::ANY)
+ completeANYRecords(p, r, sd, target);
+ }
+ else
+ makeNOError(p, r, rr.qname, DNSName(), sd, 0);
+
+ goto sendit;
+ }
+ else if(weHaveUnauth) {
+ DLOG(L<<"Have unauth data, so need to hunt for best NS records"<<endl);
+ if(tryReferral(p, r, sd, target, retargetcount))
+ goto sendit;
+ // check whether this could be fixed easily
+ // if (*(rr.qname.rbegin()) == '.') {
+ // L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): you have a trailing dot, this could be the problem (or run pdnsutil rectify-zone " <<sd.qname<<")"<<endl;
+ // } else {
+ L<<Logger::Error<<"Should not get here ("<<p->qdomain<<"|"<<p->qtype.getCode()<<"): please run pdnsutil rectify-zone "<<sd.qname<<endl;
+ // }
+ }
+ else {
+ DLOG(L<<"Have some data, but not the right data"<<endl);
+ makeNOError(p, r, target, DNSName(), sd, 0);
+ }
+
+ sendit:;
+ if(doAdditionalProcessingAndDropAA(p, r, sd, retargetcount)<0) {
+ delete r;
+ return 0;
+ }
+
+ editSOA(d_dk, sd.qname, r);
+
+ for(const auto& rr: r->getRRS()) {
+ if(rr.scopeMask) {
+ noCache=1;
+ break;
+ }
+ }
+ if(p->d_dnssecOk)
+ addRRSigs(d_dk, B, authSet, r->getRRS());
+
+ r->wrapup(); // needed for inserting in cache
+ if(!noCache)
+ PC.insert(p, r, false, r->getMinTTL()); // in the packet cache
+ }
+ catch(DBException &e) {
+ L<<Logger::Error<<"Backend reported condition which prevented lookup ("+e.reason+") sending out servfail"<<endl;
+ delete r;
+ r=p->replyPacket(); // generate an empty reply packet
+ r->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",p->qdomain.toLogString());
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"Backend reported permanent error which prevented lookup ("+e.reason+"), aborting"<<endl;
+ throw; // we WANT to die at this point
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"Exception building answer packet for "<<p->qdomain<<"/"<<p->qtype.getName()<<" ("<<e.what()<<") sending out servfail"<<endl;
+ delete r;
+ r=p->replyPacket(); // generate an empty reply packet
+ r->setRcode(RCode::ServFail);
+ S.inc("servfail-packets");
+ S.ringAccount("servfail-queries",p->qdomain.toLogString());
+ }
+ return r;
+
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PACKETHANDLER_HH
+#define PACKETHANDLER_HH
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "ueberbackend.hh"
+#include "dnspacket.hh"
+#include "packetcache.hh"
+#include "dnsseckeeper.hh"
+#include "lua-auth.hh"
+#include "gss_context.hh"
+
+#include "namespaces.hh"
+
+// silly Solaris people define PC
+#undef PC
+
+/** Central DNS logic according to RFC1034. Ask this class a question in the form of a DNSPacket
+ and it will return, synchronously, a DNSPacket answer, suitable for
+ sending out over the network.
+
+ The PacketHandler gives your question to the PacketCache for possible inclusion
+ in the cache.
+
+ In order to do so, the PacketHandler contains a reference to the global extern PacketCache PC
+
+ It also contains an UeberBackend instance for answering the subqueries needed to generate
+ a complete reply.
+
+*/
+class NSEC3PARAMRecordContent;
+
+class PacketHandler
+{
+public:
+ DNSPacket *questionOrRecurse(DNSPacket *, bool* shouldRecurse); //!< hand us a DNS packet with a question, we'll tell you answer, or that you should recurse
+ DNSPacket *question(DNSPacket *); //!< hand us a DNS packet with a question, we give you an answer
+ PacketHandler();
+ ~PacketHandler(); // defined in packethandler.cc, and does --count
+ static int numRunning(){return s_count;}; //!< Returns the number of running PacketHandlers. Called by Distributor
+
+ UeberBackend *getBackend();
+
+ int trySuperMasterSynchronous(DNSPacket *p, const DNSName& tsigkeyname);
+ static NetmaskGroup s_allowNotifyFrom;
+
+private:
+ int trySuperMaster(DNSPacket *p, const DNSName& tsigkeyname);
+ int processNotify(DNSPacket *);
+ void addRootReferral(DNSPacket *r);
+ int doChaosRequest(DNSPacket *p, DNSPacket *r, DNSName &target);
+ bool addDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd);
+ bool addCDNSKEY(DNSPacket *p, DNSPacket *r, const SOAData& sd);
+ bool addCDS(DNSPacket *p, DNSPacket *r, const SOAData& sd);
+ bool addNSEC3PARAM(DNSPacket *p, DNSPacket *r, const SOAData& sd);
+ int doAdditionalProcessingAndDropAA(DNSPacket *p, DNSPacket *r, const SOAData& sd, bool retargeted);
+ void addNSECX(DNSPacket *p, DNSPacket* r, const DNSName &target, const DNSName &wildcard, const DNSName &auth, int mode);
+ void addNSEC(DNSPacket *p, DNSPacket* r, const DNSName &target, const DNSName &wildcard, const DNSName& auth, int mode);
+ void addNSEC3(DNSPacket *p, DNSPacket* r, const DNSName &target, const DNSName &wildcard, const DNSName& auth, const NSEC3PARAMRecordContent& nsec3param, bool narrow, int mode);
+ void emitNSEC(DNSPacket *r, const SOAData& sd, const DNSName& name, const DNSName& next, int mode);
+ void emitNSEC3(DNSPacket *r, const SOAData& sd, const NSEC3PARAMRecordContent &ns3rc, const DNSName& unhashed, const string& begin, const string& end, int mode);
+ int processUpdate(DNSPacket *p);
+ int forwardPacket(const string &msgPrefix, DNSPacket *p, DomainInfo *di);
+ uint performUpdate(const string &msgPrefix, const DNSRecord *rr, DomainInfo *di, bool isPresigned, bool* narrow, bool* haveNSEC3, NSEC3PARAMRecordContent *ns3pr, bool *updatedSerial);
+ int checkUpdatePrescan(const DNSRecord *rr);
+ int checkUpdatePrerequisites(const DNSRecord *rr, DomainInfo *di);
+ void increaseSerial(const string &msgPrefix, const DomainInfo *di, bool haveNSEC3, bool narrow, const NSEC3PARAMRecordContent *ns3pr);
+
+ void makeNXDomain(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd);
+ void makeNOError(DNSPacket* p, DNSPacket* r, const DNSName& target, const DNSName& wildcard, SOAData& sd, int mode);
+ vector<DNSResourceRecord> getBestReferralNS(DNSPacket *p, SOAData& sd, const DNSName &target);
+ vector<DNSResourceRecord> getBestDNAMESynth(DNSPacket *p, SOAData& sd, DNSName &target);
+ bool tryDNAME(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target);
+ bool tryReferral(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target, bool retargeted);
+
+ bool getBestWildcard(DNSPacket *p, SOAData& sd, const DNSName &target, DNSName &wildcard, vector<DNSResourceRecord>* ret);
+ bool tryWildcard(DNSPacket *p, DNSPacket*r, SOAData& sd, DNSName &target, DNSName &wildcard, bool& retargeted, bool& nodata);
+ bool addDSforNS(DNSPacket* p, DNSPacket* r, SOAData& sd, const DNSName& dsname);
+ void completeANYRecords(DNSPacket *p, DNSPacket*r, SOAData& sd, const DNSName &target);
+
+ void tkeyHandler(DNSPacket *p, DNSPacket *r); //<! process TKEY record, and adds TKEY record to (r)eply, or error code.
+
+ static AtomicCounter s_count;
+ static pthread_mutex_t s_rfc2136lock;
+ bool d_doRecursion;
+ bool d_logDNSDetails;
+ bool d_doIPv6AdditionalProcessing;
+ bool d_doDNAME;
+ AuthLua* d_pdl;
+
+ UeberBackend B; // every thread an own instance
+ DNSSECKeeper d_dk; // B is shared with DNSSECKeeper
+};
+bool getNSEC3Hashes(bool narrow, DNSBackend* db, int id, const std::string& hashed, bool decrement, DNSName& unhashed, string& before, string& after, int mode=0);
+#endif /* PACKETHANDLER */
--- /dev/null
+#!/bin/sh
+# chkconfig: - 80 75
+# description: PDNS is a versatile high performance authoritative nameserver
+
+### BEGIN INIT INFO
+# Provides: pdns
+# Required-Start: $remote_fs $network $syslog
+# Required-Stop: $remote_fs $network $syslog
+# Should-Start:
+# Should-Stop:
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: PowerDNS authoritative server
+# Description: PowerDNS authoritative server
+### END INIT INFO
+
+set -e
+
+exec_prefix=@exec_prefix@
+BINARYPATH=@bindir@
+SBINARYPATH=@sbindir@
+SOCKETPATH=@socketdir@
+DAEMON_ARGS=""
+
+[ -f "$SBINARYPATH/pdns_server" ] || exit 0
+
+[ -r /etc/default/pdns ] && . /etc/default/pdns
+
+[ "$START" = "no" ] && exit 0
+
+# Make sure that /var/run exists
+mkdir -p $SOCKETPATH
+cd $SOCKETPATH
+suffix=$(basename $0 | cut -d- -f2- -s)
+if [ -n "$suffix" ]
+then
+ EXTRAOPTS=--config-name=$suffix
+ PROGNAME=pdns-$suffix
+else
+ PROGNAME=pdns
+fi
+
+pdns_server="$SBINARYPATH/pdns_server $DAEMON_ARGS $EXTRAOPTS"
+
+doPC()
+{
+ ret=$($BINARYPATH/pdns_control $EXTRAOPTS $1 $2 2> /dev/null)
+}
+
+NOTRUNNING=0
+doPC ping || NOTRUNNING=$?
+
+case "$1" in
+ status)
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC status
+ echo $ret
+ else
+ echo "not running"
+ exit 3
+ fi
+ ;;
+
+ stop)
+ echo -n "Stopping PowerDNS authoritative nameserver: "
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC quit
+ echo $ret
+ else
+ echo "not running"
+ fi
+ ;;
+
+
+ force-stop)
+ echo -n "Stopping PowerDNS authoritative nameserver: "
+ killall -v -9 pdns_server
+ echo "killed"
+ ;;
+
+ start)
+ echo -n "Starting PowerDNS authoritative nameserver: "
+ if test "$NOTRUNNING" = "0"
+ then
+ echo "already running"
+ else
+ if $pdns_server --daemon --guardian=yes
+ then
+ echo "started"
+ else
+ echo "starting failed"
+ exit 1
+ fi
+ fi
+ ;;
+
+ force-reload | restart)
+ echo -n "Restarting PowerDNS authoritative nameserver: "
+ if test "$NOTRUNNING" = "1"
+ then
+ echo "not running, starting"
+ else
+
+ echo -n stopping and waiting..
+ doPC quit
+ sleep 3
+ echo done
+ fi
+ $0 start
+ ;;
+
+ reload)
+ echo -n "Reloading PowerDNS authoritative nameserver: "
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC cycle
+ echo requested reload
+ else
+ echo not running yet
+ $0 start
+ fi
+ ;;
+
+ monitor)
+ if test "$NOTRUNNING" = "0"
+ then
+ echo "already running"
+ else
+ $pdns_server --daemon=no --guardian=no --control-console --loglevel=9
+ fi
+ ;;
+
+ dump)
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC list
+ echo $ret
+ else
+ echo "not running"
+ fi
+ ;;
+
+ show)
+ if [ $# -lt 2 ]
+ then
+ echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ echo -n "$2="
+ doPC show $2 ; echo $ret
+ else
+ echo "not running"
+ fi
+ ;;
+
+ mrtg)
+ if [ $# -lt 2 ]
+ then
+ echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC show $2 ; echo $ret
+ if [ "$3x" != "x" ]
+ then
+ doPC show $3 ; echo $ret
+ else
+ echo 0
+ fi
+ doPC uptime ; echo $ret
+ echo PowerDNS daemon
+ else
+ echo "not running"
+ fi
+
+ ;;
+
+ cricket)
+ if [ $# -lt 2 ]
+ then
+ echo Insufficient parameters
+ exit
+ fi
+ if test "$NOTRUNNING" = "0"
+ then
+ doPC show $2 ; echo $ret
+ else
+ echo "not running"
+ fi
+
+ ;;
+
+
+
+ *)
+ echo pdns [start\|stop\|force-reload\|reload\|restart\|status\|dump\|show\|mrtg\|cricket\|monitor]
+
+ ;;
+esac
+
+
--- /dev/null
+[Unit]
+Description=PowerDNS Authoritative Server
+Documentation=man:pdns_server(1) man:pdns_control(1)
+Documentation=https://doc.powerdns.com
+Wants=network-online.target
+After=network-online.target mysqld.service postgresql.service slapd.service mariadb.service
+
+[Service]
+Type=notify
+ExecStart=@sbindir@/pdns_server --guardian=no --daemon=no --disable-syslog --write-pid=no
+Restart=on-failure
+RestartSec=1
+StartLimitInterval=0
+PrivateTmp=true
+PrivateDevices=true
+CapabilityBoundingSet=CAP_NET_BIND_SERVICE CAP_SETGID CAP_SETUID CAP_CHOWN CAP_SYS_CHROOT
+NoNewPrivileges=true
+# ProtectSystem=full will disallow write access to /etc and /usr, possibly
+# not being able to write slaved-zones into sqlite3 or zonefiles.
+ProtectSystem=full
+ProtectHome=true
+RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6
+
+[Install]
+WantedBy=multi-user.target
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNSEXCEPTION_HH
+#define PDNSEXCEPTION_HH
+/* (C) 2002 POWERDNS.COM BV */
+
+#include<string>
+
+#include "namespaces.hh"
+
+//! Generic Exception thrown
+class PDNSException
+{
+public:
+ PDNSException(){reason="Unspecified";};
+ PDNSException(string r){reason=r;};
+
+ string reason; //! Print this to tell the user what went wrong
+};
+
+class TimeoutException : public PDNSException
+{
+public:
+ TimeoutException() : PDNSException() {}
+ TimeoutException(string r) : PDNSException(r) {}
+};
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsseckeeper.hh"
+#include "dnssecinfra.hh"
+#include "statbag.hh"
+#include "base32.hh"
+#include "base64.hh"
+
+#include <boost/program_options.hpp>
+#include <boost/assign/std/vector.hpp>
+#include <boost/assign/list_of.hpp>
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "arguments.hh"
+#include "packetcache.hh"
+#include "zoneparser-tng.hh"
+#include "signingpipe.hh"
+#include "dns_random.hh"
+#include <fstream>
+#include <termios.h> //termios, TCSANOW, ECHO, ICANON
+#include "opensslsigners.hh"
+#ifdef HAVE_LIBSODIUM
+#include <sodium.h>
+#endif
+#ifdef HAVE_SQLITE3
+#include "ssqlite3.hh"
+#include "bind-dnssec.schema.sqlite3.sql.h"
+#endif
+
+StatBag S;
+PacketCache PC;
+
+namespace po = boost::program_options;
+po::variables_map g_vm;
+
+string s_programname="pdns";
+
+namespace {
+ bool g_verbose;
+}
+
+ArgvMap &arg()
+{
+ static ArgvMap arg;
+ return arg;
+}
+
+string humanTime(time_t t)
+{
+ char ret[256];
+ struct tm tm;
+ localtime_r(&t, &tm);
+ strftime(ret, sizeof(ret)-1, "%c", &tm); // %h:%M %Y-%m-%d
+ return ret;
+}
+
+void loadMainConfig(const std::string& configdir)
+{
+ ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=configdir;
+ ::arg().set("default-ttl","Seconds a result is valid if not set otherwise")="3600";
+ ::arg().set("launch","Which backends to launch");
+ ::arg().set("dnssec","if we should do dnssec")="true";
+ ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")=g_vm["config-name"].as<string>();
+ ::arg().setCmd("help","Provide a helpful message");
+ //::arg().laxParse(argc,argv);
+
+ if(::arg().mustDo("help")) {
+ cout<<"syntax:"<<endl<<endl;
+ cout<<::arg().helpstring(::arg()["help"])<<endl;
+ exit(0);
+ }
+
+ if(::arg()["config-name"]!="")
+ s_programname+="-"+::arg()["config-name"];
+
+ string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
+ cleanSlashes(configname);
+
+ ::arg().set("default-ksk-algorithms","Default KSK algorithms")="ecdsa256";
+ ::arg().set("default-ksk-size","Default KSK size (0 means default)")="0";
+ ::arg().set("default-zsk-algorithms","Default ZSK algorithms")="";
+ ::arg().set("default-zsk-size","Default ZSK size (0 means default)")="0";
+ ::arg().set("default-soa-edit","Default SOA-EDIT value")="";
+ ::arg().set("default-soa-edit-signed","Default SOA-EDIT value for signed zones")="";
+ ::arg().set("max-ent-entries", "Maximum number of empty non-terminals in a zone")="100000";
+ ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR;
+ ::arg().set("entropy-source", "If set, read entropy from this file")="/dev/urandom";
+ ::arg().setSwitch("query-logging","Hint backends that queries should be logged")="no";
+ ::arg().set("loglevel","Amount of logging. Higher is more.")="3";
+ ::arg().setSwitch("direct-dnskey","Fetch DNSKEY RRs from backend during DNSKEY synthesis")="no";
+ ::arg().set("max-nsec3-iterations","Limit the number of NSEC3 hash iterations")="500"; // RFC5155 10.3
+ ::arg().set("max-signature-cache-entries", "Maximum number of signatures cache entries")="";
+ ::arg().laxFile(configname.c_str());
+
+ L.toConsole(Logger::Error); // so we print any errors
+ BackendMakers().launch(::arg()["launch"]); // vrooooom!
+ if(::arg().asNum("loglevel") >= 3) // so you can't kill our errors
+ L.toConsole((Logger::Urgency)::arg().asNum("loglevel"));
+
+ //cerr<<"Backend: "<<::arg()["launch"]<<", '" << ::arg()["gmysql-dbname"] <<"'" <<endl;
+
+ S.declare("qsize-q","Number of questions waiting for database attention");
+
+ S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
+ S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
+
+ S.declare("query-cache-hit","Number of hits on the query cache");
+ S.declare("query-cache-miss","Number of misses on the query cache");
+ ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
+ ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
+ ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
+ ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
+ ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
+ ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
+ ::arg().set("default-soa-name","name to insert in the SOA record if none set in the backend")="a.misconfigured.powerdns.server";
+ ::arg().set("default-soa-mail","mail address to insert in the SOA record if none set in the backend")="";
+ ::arg().set("soa-refresh-default","Default SOA refresh")="10800";
+ ::arg().set("soa-retry-default","Default SOA retry")="3600";
+ ::arg().set("soa-expire-default","Default SOA expire")="604800";
+ ::arg().set("soa-minimum-ttl","Default SOA minimum ttl")="3600";
+ ::arg().set("chroot","Switch to this chroot jail")="";
+ ::arg().set("dnssec-key-cache-ttl","Seconds to cache DNSSEC keys from the database")="30";
+ ::arg().set("domain-metadata-cache-ttl","Seconds to cache domain metadata from the database")="60";
+
+ // Keep this line below all ::arg().set() statements
+ if (! ::arg().laxFile(configname.c_str()))
+ cerr<<"Warning: unable to read configuration file '"<<configname<<"'."<<endl;
+
+ seedRandom(::arg()["entropy-source"]);
+
+ if (!::arg()["chroot"].empty()) {
+ if (chroot(::arg()["chroot"].c_str())<0 || chdir("/") < 0) {
+ cerr<<"Unable to chroot to '"+::arg()["chroot"]+"': "<<strerror (errno)<<endl;
+ exit(1);
+ }
+ }
+
+ UeberBackend::go();
+}
+
+// irritatingly enough, rectifyZone needs its own ueberbackend and can't therefore benefit from transactions outside its scope
+// I think this has to do with interlocking transactions between B and DK, but unsure.
+bool rectifyZone(DNSSECKeeper& dk, const DNSName& zone)
+{
+ if(dk.isPresigned(zone)){
+ cerr<<"Rectify presigned zone '"<<zone<<"' is not allowed/necessary."<<endl;
+ return false;
+ }
+
+ UeberBackend B("default");
+ bool doTransaction=true; // but see above
+ SOAData sd;
+
+ if(!B.getSOAUncached(zone, sd)) {
+ cerr<<"No SOA known for '"<<zone<<"', is such a zone in the database?"<<endl;
+ return false;
+ }
+ sd.db->list(zone, sd.domain_id);
+
+ DNSResourceRecord rr;
+ set<DNSName> qnames, nsset, dsnames, insnonterm, delnonterm;
+ map<DNSName,bool> nonterm;
+ vector<DNSResourceRecord> rrs;
+
+ while(sd.db->get(rr)) {
+ rr.qname.makeUsLowerCase();
+ if (rr.qtype.getCode())
+ {
+ rrs.push_back(rr);
+ qnames.insert(rr.qname);
+ if(rr.qtype.getCode() == QType::NS && rr.qname != zone)
+ nsset.insert(rr.qname);
+ if(rr.qtype.getCode() == QType::DS)
+ dsnames.insert(rr.qname);
+ }
+ else
+ delnonterm.insert(rr.qname);
+ }
+
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+ bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
+ bool isOptOut=(haveNSEC3 && ns3pr.d_flags);
+ if(dk.isSecuredZone(zone))
+ {
+ if(!haveNSEC3)
+ cerr<<"Adding NSEC ordering information "<<endl;
+ else if(!narrow) {
+ if(!isOptOut)
+ cerr<<"Adding NSEC3 hashed ordering information for '"<<zone<<"'"<<endl;
+ else
+ cerr<<"Adding NSEC3 opt-out hashed ordering information for '"<<zone<<"'"<<endl;
+ } else
+ cerr<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
+ }
+ else
+ cerr<<"Adding empty non-terminals for non-DNSSEC zone"<<endl;
+
+ set<DNSName> nsec3set;
+ if (haveNSEC3 && !narrow) {
+ for (auto &rr: rrs) {
+ bool skip=false;
+ DNSName shorter = rr.qname;
+ if (shorter != zone && shorter.chopOff() && shorter != zone) {
+ do {
+ if(nsset.count(shorter)) {
+ skip=true;
+ break;
+ }
+ } while(shorter.chopOff() && shorter != zone);
+ }
+ shorter = rr.qname;
+ if(!skip && (rr.qtype.getCode() != QType::NS || !isOptOut)) {
+
+ do {
+ if(!nsec3set.count(shorter)) {
+ nsec3set.insert(shorter);
+ }
+ } while(shorter != zone && shorter.chopOff());
+ }
+ }
+ }
+
+ if(doTransaction)
+ sd.db->startTransaction(zone, -1);
+
+ bool realrr=true;
+ bool doent=true;
+ uint32_t maxent = ::arg().asNum("max-ent-entries");
+
+ dononterm:;
+ for (const auto& qname: qnames)
+ {
+ bool auth=true;
+ DNSName ordername;
+ auto shorter(qname);
+
+ if(realrr) {
+ do {
+ if(nsset.count(shorter)) {
+ auth=false;
+ break;
+ }
+ } while(shorter.chopOff());
+ } else {
+ auth=nonterm.find(qname)->second;
+ }
+
+ if(haveNSEC3) // NSEC3
+ {
+ if(!narrow && nsec3set.count(qname)) {
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, qname))) + zone;
+ if(!realrr)
+ auth=true;
+ } else if(!realrr)
+ auth=false;
+ }
+ else if (realrr) // NSEC
+ ordername=qname;
+
+ if(g_verbose)
+ cerr<<"'"<<qname<<"' -> '"<< ordername <<"'"<<endl;
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, qname, ordername, auth);
+
+ if(realrr)
+ {
+ if (dsnames.count(qname))
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, qname, ordername, true, QType::DS);
+ if (!auth || nsset.count(qname)) {
+ ordername.clear();
+ if(isOptOut && !dsnames.count(qname))
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, qname, ordername, false, QType::NS);
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, qname, ordername, false, QType::A);
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, qname, ordername, false, QType::AAAA);
+ }
+
+ if(doent)
+ {
+ shorter=qname;
+ while(shorter!=zone && shorter.chopOff())
+ {
+ if(!qnames.count(shorter))
+ {
+ if(!(maxent))
+ {
+ cerr<<"Zone '"<<zone<<"' has too many empty non terminals."<<endl;
+ insnonterm.clear();
+ delnonterm.clear();
+ doent=false;
+ break;
+ }
+
+ if (!delnonterm.count(shorter) && !nonterm.count(shorter))
+ insnonterm.insert(shorter);
+ else
+ delnonterm.erase(shorter);
+
+ if (!nonterm.count(shorter)) {
+ nonterm.insert(pair<DNSName, bool>(shorter, auth));
+ --maxent;
+ } else if (auth)
+ nonterm[shorter]=true;
+ }
+ }
+ }
+ }
+ }
+
+ if(realrr)
+ {
+ //cerr<<"Total: "<<nonterm.size()<<" Insert: "<<insnonterm.size()<<" Delete: "<<delnonterm.size()<<endl;
+ if(!insnonterm.empty() || !delnonterm.empty() || !doent)
+ {
+ sd.db->updateEmptyNonTerminals(sd.domain_id, zone, insnonterm, delnonterm, !doent);
+ }
+ if(doent)
+ {
+ realrr=false;
+ qnames.clear();
+ for(const auto& nt : nonterm){
+ qnames.insert(nt.first);
+ }
+ goto dononterm;
+ }
+ }
+
+ if(doTransaction)
+ sd.db->commitTransaction();
+
+ return true;
+}
+
+void dbBench(const std::string& fname)
+{
+ ::arg().set("query-cache-ttl")="0";
+ ::arg().set("negquery-cache-ttl")="0";
+ UeberBackend B("default");
+
+ vector<string> domains;
+ if(!fname.empty()) {
+ ifstream ifs(fname.c_str());
+ if(!ifs) {
+ cerr<<"Could not open '"<<fname<<"' for reading domain names to query"<<endl;
+ }
+ string line;
+ while(getline(ifs,line)) {
+ trim(line);
+ domains.push_back(line);
+ }
+ }
+ if(domains.empty())
+ domains.push_back("powerdns.com");
+
+ int n=0;
+ DNSResourceRecord rr;
+ DTime dt;
+ dt.set();
+ unsigned int hits=0, misses=0;
+ for(; n < 10000; ++n) {
+ DNSName domain(domains[random() % domains.size()]);
+ B.lookup(QType(QType::NS), domain);
+ while(B.get(rr)) {
+ hits++;
+ }
+ B.lookup(QType(QType::A), DNSName(std::to_string(random()))+domain);
+ while(B.get(rr)) {
+ }
+ misses++;
+
+ }
+ cout<<0.001*dt.udiff()/n<<" millisecond/lookup"<<endl;
+ cout<<"Retrieved "<<hits<<" records, did "<<misses<<" queries which should have no match"<<endl;
+ cout<<"Packet cache reports: "<<S.read("query-cache-hit")<<" hits (should be 0) and "<<S.read("query-cache-miss") <<" misses"<<endl;
+}
+
+void rectifyAllZones(DNSSECKeeper &dk)
+{
+ UeberBackend B("default");
+ vector<DomainInfo> domainInfo;
+
+ B.getAllDomains(&domainInfo);
+ for(DomainInfo di : domainInfo) {
+ cerr<<"Rectifying "<<di.zone<<": ";
+ rectifyZone(dk, di.zone);
+ }
+ cout<<"Rectified "<<domainInfo.size()<<" zones."<<endl;
+}
+
+int checkZone(DNSSECKeeper &dk, UeberBackend &B, const DNSName& zone, const vector<DNSResourceRecord>* suppliedrecords=0)
+{
+ SOAData sd;
+ if(!B.getSOAUncached(zone, sd)) {
+ cout<<"[error] No SOA record present, or active, in zone '"<<zone<<"'"<<endl;
+ cout<<"Checked 0 records of '"<<zone<<"', 1 errors, 0 warnings."<<endl;
+ return 1;
+ }
+
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow = false;
+ bool haveNSEC3 = dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
+ bool isOptOut=(haveNSEC3 && ns3pr.d_flags);
+
+ bool isSecure=dk.isSecuredZone(zone);
+ bool presigned=dk.isPresigned(zone);
+ bool validKeys=dk.checkKeys(zone);
+
+ DNSResourceRecord rr;
+ uint64_t numrecords=0, numerrors=0, numwarnings=0;
+
+ if (haveNSEC3) {
+ if(isSecure && zone.wirelength() > 222) {
+ numerrors++;
+ cout<<"[Error] zone '" << zone << "' has NSEC3 semantics but is too long to have the hash prepended. Zone name is " << zone.wirelength() << " bytes long, whereas the maximum is 222 bytes." << endl;
+ }
+
+ vector<DNSBackend::KeyData> dbkeyset;
+ B.getDomainKeys(zone, 0, dbkeyset);
+
+ for(DNSBackend::KeyData& kd : dbkeyset) {
+ DNSKEYRecordContent dkrc;
+ shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content));
+
+ if(dkrc.d_algorithm == 5) {
+ cout<<"[Warning] zone '"<<zone<<"' has NSEC3 semantics, but the "<< (kd.active ? "" : "in" ) <<"active key with id "<<kd.id<<" has 'Algorithm: 5'. This should be corrected to 'Algorithm: 7' in the database (or NSEC3 should be disabled)."<<endl;
+ numwarnings++;
+ }
+ }
+ }
+
+ if (!validKeys) {
+ numerrors++;
+ cout<<"[Error] zone '" << zone << "' has at least one invalid DNS Private Key." << endl;
+ }
+
+ // Check for delegation in parent zone
+ DNSName parent(zone);
+ while(parent.chopOff()) {
+ SOAData sd_p;
+ if(B.getSOAUncached(parent, sd_p)) {
+ bool ns=false;
+ DNSResourceRecord rr;
+ B.lookup(QType(QType::ANY), zone, NULL, sd_p.domain_id);
+ while(B.get(rr))
+ ns |= (rr.qtype == QType::NS);
+ if (!ns) {
+ cout<<"[Error] No delegation for zone '"<<zone<<"' in parent '"<<parent<<"'"<<endl;
+ numerrors++;
+ }
+ break;
+ }
+ }
+
+
+ bool hasNsAtApex = false;
+ set<DNSName> tlsas, cnames, noncnames, glue, checkglue;
+ set<string> recordcontents;
+ map<string, unsigned int> ttl;
+
+ ostringstream content;
+ pair<map<string, unsigned int>::iterator,bool> ret;
+
+ vector<DNSResourceRecord> records;
+ if(!suppliedrecords) {
+ sd.db->list(zone, sd.domain_id, g_verbose);
+ while(sd.db->get(rr)) {
+ records.push_back(rr);
+ }
+ }
+ else
+ records=*suppliedrecords;
+
+ for(auto rr : records) { // we modify this
+ if(!rr.qtype.getCode())
+ continue;
+
+ numrecords++;
+
+ if(rr.qtype.getCode() == QType::TLSA)
+ tlsas.insert(rr.qname);
+ if(rr.qtype.getCode() == QType::SOA) {
+ vector<string>parts;
+ stringtok(parts, rr.content);
+
+ ostringstream o;
+ o<<rr.content;
+ for(int pleft=parts.size(); pleft < 7; ++pleft) {
+ o<<" 0";
+ }
+ rr.content=o.str();
+ }
+
+ if(rr.qtype.getCode() == QType::TXT && !rr.content.empty() && rr.content[0]!='"')
+ rr.content = "\""+rr.content+"\"";
+
+ try {
+ shared_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content));
+ string tmp=drc->serialize(rr.qname);
+ tmp = drc->getZoneRepresentation(true);
+ if (rr.qtype.getCode() != QType::AAAA) {
+ if (!pdns_iequals(tmp, rr.content)) {
+ if(rr.qtype.getCode() == QType::SOA) {
+ tmp = drc->getZoneRepresentation(false);
+ }
+ if(!pdns_iequals(tmp, rr.content)) {
+ cout<<"[Warning] Parsed and original record content are not equal: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " '" << rr.content<<"' (Content parsed as '"<<tmp<<"')"<<endl;
+ numwarnings++;
+ }
+ }
+ } else {
+ struct in6_addr tmpbuf;
+ if (inet_pton(AF_INET6, rr.content.c_str(), &tmpbuf) != 1 || rr.content.find('.') != string::npos) {
+ cout<<"[Warning] Following record is not a valid IPv6 address: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " '" << rr.content<<"'"<<endl;
+ numwarnings++;
+ }
+ }
+ }
+ catch(std::exception& e)
+ {
+ cout<<"[Error] Following record had a problem: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
+ cout<<"[Error] Error was: "<<e.what()<<endl;
+ numerrors++;
+ continue;
+ }
+
+ if(!rr.qname.isPartOf(zone)) {
+ cout<<"[Error] Record '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"' is out-of-zone."<<endl;
+ numerrors++;
+ continue;
+ }
+
+ content.str("");
+ content<<rr.qname<<" "<<rr.qtype.getName()<<" "<<rr.content;
+ if (recordcontents.count(toLower(content.str()))) {
+ cout<<"[Error] Duplicate record found in rrset: '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"'"<<endl;
+ numerrors++;
+ continue;
+ } else
+ recordcontents.insert(toLower(content.str()));
+
+ content.str("");
+ content<<rr.qname<<" "<<rr.qtype.getName();
+ if (rr.qtype.getCode() == QType::RRSIG) {
+ RRSIGRecordContent rrc(rr.content);
+ content<<" ("<<DNSRecordContent::NumberToType(rrc.d_type)<<")";
+ }
+ ret = ttl.insert(pair<string, unsigned int>(toLower(content.str()), rr.ttl));
+ if (ret.second == false && ret.first->second != rr.ttl) {
+ cout<<"[Error] TTL mismatch in rrset: '"<<rr.qname<<" IN " <<rr.qtype.getName()<<" "<<rr.content<<"' ("<<ret.first->second<<" != "<<rr.ttl<<")"<<endl;
+ numerrors++;
+ continue;
+ }
+
+ if (isSecure && isOptOut && (rr.qname.countLabels() && rr.qname.getRawLabels()[0] == "*")) {
+ cout<<"[Warning] wildcard record '"<<rr.qname<<" IN " <<rr.qtype.getName()<<" "<<rr.content<<"' is insecure"<<endl;
+ cout<<"[Info] Wildcard records in opt-out zones are insecure. Disable the opt-out flag for this zone to avoid this warning. Command: pdnsutil set-nsec3 "<<zone<<endl;
+ numwarnings++;
+ }
+
+ if(rr.qname==zone) {
+ if (rr.qtype.getCode() == QType::NS) {
+ hasNsAtApex=true;
+ } else if (rr.qtype.getCode() == QType::DS) {
+ cout<<"[Warning] DS at apex in zone '"<<zone<<"', should not be here."<<endl;
+ numwarnings++;
+ }
+ } else {
+ if (rr.qtype.getCode() == QType::SOA) {
+ cout<<"[Error] SOA record not at apex '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"'"<<endl;
+ numerrors++;
+ continue;
+ } else if (rr.qtype.getCode() == QType::DNSKEY) {
+ cout<<"[Warning] DNSKEY record not at apex '"<<rr.qname<<" IN "<<rr.qtype.getName()<<" "<<rr.content<<"' in zone '"<<zone<<"', should not be here."<<endl;
+ numwarnings++;
+ } else if (rr.qtype.getCode() == QType::NS && DNSName(rr.content).isPartOf(rr.qname)) {
+ checkglue.insert(DNSName(toLower(rr.content)));
+ } else if (rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) {
+ glue.insert(rr.qname);
+ }
+ }
+
+ if (rr.qtype.getCode() == QType::CNAME) {
+ if (!cnames.count(rr.qname))
+ cnames.insert(rr.qname);
+ else {
+ cout<<"[Error] Duplicate CNAME found at '"<<rr.qname<<"'"<<endl;
+ numerrors++;
+ continue;
+ }
+ } else {
+ if (rr.qtype.getCode() == QType::RRSIG) {
+ if(!presigned) {
+ cout<<"[Error] RRSIG found at '"<<rr.qname<<"' in non-presigned zone. These do not belong in the database."<<endl;
+ numerrors++;
+ continue;
+ }
+ } else
+ noncnames.insert(rr.qname);
+ }
+
+ if(rr.qtype.getCode() == QType::NSEC || rr.qtype.getCode() == QType::NSEC3)
+ {
+ cout<<"[Error] NSEC or NSEC3 found at '"<<rr.qname<<"'. These do not belong in the database."<<endl;
+ numerrors++;
+ continue;
+ }
+
+ if(!presigned && rr.qtype.getCode() == QType::DNSKEY)
+ {
+ if(::arg().mustDo("direct-dnskey"))
+ {
+ if(rr.ttl != sd.default_ttl)
+ {
+ cout<<"[Warning] DNSKEY TTL of "<<rr.ttl<<" at '"<<rr.qname<<"' differs from SOA minimum of "<<sd.default_ttl<<endl;
+ numwarnings++;
+ }
+ }
+ else
+ {
+ cout<<"[Warning] DNSKEY at '"<<rr.qname<<"' in non-presigned zone will mostly be ignored and can cause problems."<<endl;
+ numwarnings++;
+ }
+ }
+
+ if(rr.auth == 0 && rr.qtype.getCode()!=QType::NS && rr.qtype.getCode()!=QType::A && rr.qtype.getCode()!=QType::AAAA)
+ {
+ cout<<"[Error] Following record is auth=0, run pdnsutil rectify-zone?: "<<rr.qname<<" IN " <<rr.qtype.getName()<< " " << rr.content<<endl;
+ numerrors++;
+ }
+ }
+
+ for(auto &i: cnames) {
+ if (noncnames.find(i) != noncnames.end()) {
+ cout<<"[Error] CNAME "<<i<<" found, but other records with same label exist."<<endl;
+ numerrors++;
+ }
+ }
+
+ for(const auto &i: tlsas) {
+ DNSName name = DNSName(i);
+ name.trimToLabels(name.countLabels()-2);
+ if (cnames.find(name) == cnames.end() && noncnames.find(name) == noncnames.end()) {
+ // No specific record for the name in the TLSA record exists, this
+ // is already worth emitting a warning. Let's see if a wildcard exist.
+ cout<<"[Warning] ";
+ DNSName wcname(name);
+ wcname.chopOff();
+ wcname.prependRawLabel("*");
+ if (cnames.find(wcname) != cnames.end() || noncnames.find(wcname) != noncnames.end()) {
+ cout<<"A wildcard record exist for '"<<wcname<<"' and a TLSA record for '"<<i<<"'.";
+ } else {
+ cout<<"No record for '"<<name<<"' exists, but a TLSA record for '"<<i<<"' does.";
+ }
+ numwarnings++;
+ cout<<" A query for '"<<name<<"' will yield an empty response. This is most likely a mistake, please create records for '"<<name<<"'."<<endl;
+ }
+ }
+
+ if(!hasNsAtApex) {
+ cout<<"[Error] No NS record at zone apex in zone '"<<zone<<"'"<<endl;
+ numerrors++;
+ }
+
+ for(const auto &qname : checkglue) {
+ if (!glue.count(qname)) {
+ cout<<"[Warning] Missing glue for '"<<qname<<"' in zone '"<<zone<<"'"<<endl;
+ numwarnings++;
+ }
+ }
+
+ cout<<"Checked "<<numrecords<<" records of '"<<zone<<"', "<<numerrors<<" errors, "<<numwarnings<<" warnings."<<endl;
+ if(!numerrors)
+ return 0;
+ return 1;
+}
+
+int checkAllZones(DNSSECKeeper &dk, bool exitOnError)
+{
+ UeberBackend B("default");
+ vector<DomainInfo> domainInfo;
+
+ B.getAllDomains(&domainInfo, true);
+ int errors=0;
+ for(auto di : domainInfo) {
+ if (checkZone(dk, B, di.zone) > 0) {
+ errors++;
+ if(exitOnError)
+ return EXIT_FAILURE;
+ }
+ }
+ cout<<"Checked "<<domainInfo.size()<<" zones, "<<errors<<" had errors."<<endl;
+ if(!errors)
+ return EXIT_SUCCESS;
+ return EXIT_FAILURE;
+}
+
+int increaseSerial(const DNSName& zone, DNSSECKeeper &dk)
+{
+ UeberBackend B("default");
+ SOAData sd;
+ if(!B.getSOAUncached(zone, sd)) {
+ cerr<<"No SOA for zone '"<<zone<<"'"<<endl;
+ return -1;
+ }
+
+ if (dk.isPresigned(zone)) {
+ cerr<<"Serial increase of presigned zone '"<<zone<<"' is not allowed."<<endl;
+ return -1;
+ }
+
+ string soaEditKind;
+ dk.getSoaEdit(zone, soaEditKind);
+
+ sd.db->lookup(QType(QType::SOA), zone);
+ vector<DNSResourceRecord> rrs;
+ DNSResourceRecord rr;
+ while (sd.db->get(rr)) {
+ if (rr.qtype.getCode() == QType::SOA)
+ rrs.push_back(rr);
+ }
+
+ if (rrs.size() > 1) {
+ cerr<<rrs.size()<<" SOA records found for "<<zone<<"!"<<endl;
+ return -1;
+ }
+ if (rrs.size() < 1) {
+ cerr<<zone<<" not found!"<<endl;
+ }
+
+ if (soaEditKind.empty()) {
+ sd.serial++;
+ }
+ else if(pdns_iequals(soaEditKind,"INCREMENT-WEEKS")) {
+ sd.serial++;
+ }
+ else if(pdns_iequals(soaEditKind,"INCEPTION-INCREMENT")) {
+ uint32_t today_serial = localtime_format_YYYYMMDDSS(time(NULL), 1);
+
+ if (sd.serial < today_serial) {
+ sd.serial = today_serial;
+ }
+ else {
+ sd.serial++;
+ }
+ }
+ else {
+ sd.serial = calculateEditSOA(sd, soaEditKind) + 1;
+ }
+ rrs[0].content = serializeSOAData(sd);
+
+ sd.db->startTransaction(zone, -1);
+
+ if (! sd.db->replaceRRSet(sd.domain_id, zone, rr.qtype, rrs)) {
+ sd.db->abortTransaction();
+ cerr<<"Backend did not replace SOA record. Backend might not support this operation."<<endl;
+ return -1;
+ }
+
+ if (sd.db->doesDNSSEC()) {
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+ bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
+
+ DNSName ordername;
+ if(haveNSEC3) {
+ if(!narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(ns3pr, zone))) + zone;
+ } else
+ ordername=zone;
+ if(g_verbose)
+ cerr<<"'"<<rrs[0].qname<<"' -> '"<< ordername <<"'"<<endl;
+ sd.db->updateDNSSECOrderNameAndAuth(sd.domain_id, zone, rrs[0].qname, ordername, true);
+ }
+
+ sd.db->commitTransaction();
+
+ cout<<"SOA serial for zone "<<zone<<" set to "<<sd.serial<<endl;
+ return 0;
+}
+
+int deleteZone(const DNSName &zone) {
+ UeberBackend B;
+ DomainInfo di;
+ if (! B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' not found!"<<endl;
+ return EXIT_FAILURE;
+ }
+
+ if(di.backend->deleteDomain(zone))
+ return EXIT_SUCCESS;
+
+ cerr<<"Failed to delete domain '"<<zone<<"'"<<endl;;
+ return EXIT_FAILURE;
+}
+
+void listKey(DomainInfo const &di, DNSSECKeeper& dk, bool printHeader = true) {
+ if (printHeader) {
+ cout<<"Zone Type Size Algorithm ID Location Keytag"<<endl;
+ cout<<"----------------------------------------------------------------------------------"<<endl;
+ }
+ unsigned int spacelen = 0;
+ for (auto const &key : dk.getKeys(di.zone)) {
+ cout<<di.zone;
+ if (di.zone.toStringNoDot().length() > 29)
+ cout<<endl<<string(30, ' ');
+ else
+ cout<<string(30 - di.zone.toStringNoDot().length(), ' ');
+
+ cout<<DNSSECKeeper::keyTypeToString(key.second.keyType)<<" ";
+
+ spacelen = (std::to_string(key.first.getKey()->getBits()).length() >= 8) ? 1 : 8 - std::to_string(key.first.getKey()->getBits()).length();
+ if (key.first.getKey()->getBits() < 1) {
+ cout<<"invalid "<<endl;
+ continue;
+ } else {
+ cout<<key.first.getKey()->getBits()<<string(spacelen, ' ');
+ }
+
+ string algname = DNSSECKeeper::algorithm2name(key.first.d_algorithm);
+ spacelen = (algname.length() >= 13) ? 1 : 13 - algname.length();
+ cout<<algname<<string(spacelen, ' ');
+
+ spacelen = (std::to_string(key.second.id).length() > 5) ? 1 : 5 - std::to_string(key.second.id).length();
+ cout<<key.second.id<<string(spacelen, ' ');
+
+#ifdef HAVE_P11KIT1
+ auto stormap = key.first.getKey()->convertToISCVector();
+ string engine, slot, label = "";
+ for (auto const &elem : stormap) {
+ //cout<<elem.first<<" "<<elem.second<<endl;
+ if (elem.first == "Engine")
+ engine = elem.second;
+ if (elem.first == "Slot")
+ slot = elem.second;
+ if (elem.first == "Label")
+ label = elem.second;
+ }
+ if (engine.empty() || slot.empty()){
+ cout<<"cryptokeys ";
+ } else {
+ spacelen = (engine.length()+slot.length()+label.length()+2 >= 12) ? 1 : 12 - engine.length()-slot.length()-label.length()-2;
+ cout<<engine<<","<<slot<<","<<label<<string(spacelen, ' ');
+ }
+#else
+ cout<<"cryptokeys ";
+#endif
+ cout<<key.first.getDNSKEY().getTag()<<endl;
+ }
+}
+
+int listKeys(const string &zname, DNSSECKeeper& dk){
+ UeberBackend B("default");
+
+ if (zname != "all") {
+ DomainInfo di;
+ if(!B.getDomainInfo(DNSName(zname), di)) {
+ cerr << "Zone "<<zname<<" not found."<<endl;
+ return EXIT_FAILURE;
+ }
+ listKey(di, dk);
+ } else {
+ vector<DomainInfo> domainInfo;
+ B.getAllDomains(&domainInfo);
+ bool printHeader = true;
+ for (auto const di : domainInfo) {
+ listKey(di, dk, printHeader);
+ printHeader = false;
+ }
+ }
+ return EXIT_SUCCESS;
+}
+
+int listZone(const DNSName &zone) {
+ UeberBackend B;
+ DomainInfo di;
+
+ if (! B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' not found!"<<endl;
+ return EXIT_FAILURE;
+ }
+ di.backend->list(zone, di.id);
+ DNSResourceRecord rr;
+ while(di.backend->get(rr)) {
+ if(rr.qtype.getCode()) {
+ if ( (rr.qtype.getCode() == QType::NS || rr.qtype.getCode() == QType::SRV || rr.qtype.getCode() == QType::MX || rr.qtype.getCode() == QType::CNAME) && !rr.content.empty() && rr.content[rr.content.size()-1] != '.')
+ rr.content.append(1, '.');
+
+ cout<<rr.qname<<"\t"<<rr.ttl<<"\tIN\t"<<rr.qtype.getName()<<"\t"<<rr.content<<endl;
+ }
+ }
+ return EXIT_SUCCESS;
+}
+
+// lovingly copied from http://stackoverflow.com/questions/1798511/how-to-avoid-press-enter-with-any-getchar
+int read1char(){
+ int c;
+ static struct termios oldt, newt;
+
+ /*tcgetattr gets the parameters of the current terminal
+ STDIN_FILENO will tell tcgetattr that it should write the settings
+ of stdin to oldt*/
+ tcgetattr( STDIN_FILENO, &oldt);
+ /*now the settings will be copied*/
+ newt = oldt;
+
+ /*ICANON normally takes care that one line at a time will be processed
+ that means it will return if it sees a "\n" or an EOF or an EOL*/
+ newt.c_lflag &= ~(ICANON);
+
+ /*Those new settings will be set to STDIN
+ TCSANOW tells tcsetattr to change attributes immediately. */
+ tcsetattr( STDIN_FILENO, TCSANOW, &newt);
+
+ c=getchar();
+
+ /*restore the old settings*/
+ tcsetattr( STDIN_FILENO, TCSANOW, &oldt);
+
+ return c;
+}
+
+int clearZone(DNSSECKeeper& dk, const DNSName &zone) {
+ UeberBackend B;
+ DomainInfo di;
+
+ if (! B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' not found!"<<endl;
+ return EXIT_FAILURE;
+ }
+ if(!di.backend->startTransaction(zone, di.id)) {
+ cerr<<"Unable to start transaction for load of zone '"<<zone<<"'"<<endl;
+ return EXIT_FAILURE;
+ }
+ di.backend->commitTransaction();
+ return EXIT_SUCCESS;
+}
+
+int editZone(DNSSECKeeper& dk, const DNSName &zone) {
+ UeberBackend B;
+ DomainInfo di;
+
+ if (! B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' not found!"<<endl;
+ return EXIT_FAILURE;
+ }
+ vector<DNSRecord> pre, post;
+ char tmpnam[]="/tmp/pdnsutil-XXXXXX";
+ int tmpfd=mkstemp(tmpnam);
+ if(tmpfd < 0)
+ unixDie("Making temporary filename in "+string(tmpnam));
+ struct deleteme {
+ ~deleteme() { unlink(d_name.c_str()); }
+ deleteme(string name) : d_name(name) {}
+ string d_name;
+ } dm(tmpnam);
+
+ vector<DNSResourceRecord> checkrr;
+ int gotoline=0;
+ string editor="editor";
+ if(auto e=getenv("EDITOR")) // <3
+ editor=e;
+ string cmdline;
+ editAgain:;
+ di.backend->list(zone, di.id);
+ pre.clear(); post.clear();
+ DNSResourceRecord rr;
+ {
+ if(tmpfd < 0 && (tmpfd=open(tmpnam, O_WRONLY | O_TRUNC, 0600)) < 0)
+ unixDie("Error reopening temporary file "+string(tmpnam));
+ string header("; Warning - every name in this file is ABSOLUTE!\n$ORIGIN .\n");
+ if(write(tmpfd, header.c_str(), header.length()) < 0)
+ unixDie("Writing zone to temporary file");
+ while(di.backend->get(rr)) {
+ if(!rr.qtype.getCode())
+ continue;
+ DNSRecord dr(rr);
+ pre.push_back(dr);
+ }
+ sort(pre.begin(), pre.end(), DNSRecord::prettyCompare);
+ for(const auto& dr : pre) {
+ ostringstream os;
+ os<<dr.d_name<<"\t"<<dr.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(dr.d_type)<<"\t"<<dr.d_content->getZoneRepresentation(true)<<endl;
+ if(write(tmpfd, os.str().c_str(), os.str().length()) < 0)
+ unixDie("Writing zone to temporary file");
+ }
+ close(tmpfd);
+ tmpfd=-1;
+ }
+ editMore:;
+ cmdline=editor+" ";
+ if(gotoline > 0)
+ cmdline+="+"+std::to_string(gotoline)+" ";
+ cmdline += tmpnam;
+ int err=system(cmdline.c_str());
+ if(err) {
+ unixDie("Editing file with: '"+cmdline+"', perhaps set EDITOR variable");
+ }
+ cmdline.clear();
+ ZoneParserTNG zpt(tmpnam, DNSName("."));
+ map<pair<DNSName,uint16_t>, vector<DNSRecord> > grouped;
+ while(zpt.get(rr)) {
+ try {
+ DNSRecord dr(rr);
+ post.push_back(dr);
+ grouped[{dr.d_name,dr.d_type}].push_back(dr);
+ }
+ catch(std::exception& e) {
+ cerr<<"Problem "<<e.what()<<" "<<zpt.getLineOfFile()<<endl;
+ auto fnum = zpt.getLineNumAndFile();
+ gotoline = fnum.second;
+ goto reAsk;
+ }
+ }
+ sort(post.begin(), post.end(), DNSRecord::prettyCompare);
+ checkrr.clear();
+
+ for(const DNSRecord& rr : post) {
+ DNSResourceRecord drr(rr);
+ drr.domain_id = di.id;
+ checkrr.push_back(drr);
+ }
+ if(checkZone(dk, B, zone, &checkrr)) {
+ reAsk:;
+ cerr<<"\x1b[31;1mThere was a problem with your zone\x1b[0m\nOptions are: (e)dit your changes, (r)etry with original zone, (a)pply change anyhow, (q)uit: "<<endl;
+ int c=read1char();
+ cerr<<"\n";
+ if(c!='a')
+ post.clear();
+ if(c=='e')
+ goto editMore;
+ else if(c=='r')
+ goto editAgain;
+ else if(c=='q')
+ return EXIT_FAILURE;
+ else if(c!='a')
+ goto reAsk;
+ }
+
+
+ vector<DNSRecord> diff;
+
+ map<pair<DNSName,uint16_t>, string> changed;
+ set_difference(pre.cbegin(), pre.cend(), post.cbegin(), post.cend(), back_inserter(diff), DNSRecord::prettyCompare);
+ for(const auto& d : diff) {
+ ostringstream str;
+ str<<'-'<< d.d_name <<" "<<d.d_ttl<<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation(true)<<endl;
+ changed[{d.d_name,d.d_type}] += str.str();
+
+ }
+ diff.clear();
+ set_difference(post.cbegin(), post.cend(), pre.cbegin(), pre.cend(), back_inserter(diff), DNSRecord::prettyCompare);
+ for(const auto& d : diff) {
+ ostringstream str;
+
+ str<<'+'<< d.d_name <<" "<<d.d_ttl<<" IN "<<DNSRecordContent::NumberToType(d.d_type)<<" "<<d.d_content->getZoneRepresentation(true)<<endl;
+ changed[{d.d_name,d.d_type}]+=str.str();
+ }
+ if (changed.size() > 0)
+ cout<<"Detected the following changes:"<<endl;
+ for(const auto& c : changed) {
+ cout<<c.second;
+ }
+ reAsk2:;
+ if(changed.empty()) {
+ cout<<endl<<"No changes to apply."<<endl;
+ return(EXIT_SUCCESS);
+ }
+ cout<<endl<<"(a)pply these changes, (e)dit again, (r)etry with original zone, (q)uit: ";
+ int c=read1char();
+ post.clear();
+ cerr<<'\n';
+ if(c=='q')
+ return(EXIT_SUCCESS);
+ else if(c=='e')
+ goto editMore;
+ else if(c=='r')
+ goto editAgain;
+ else if(changed.empty() || c!='a')
+ goto reAsk2;
+
+ for(const auto& c : changed) {
+ vector<DNSResourceRecord> vrr;
+ for(const DNSRecord& rr : grouped[c.first]) {
+ DNSResourceRecord drr(rr);
+ drr.domain_id = di.id;
+ vrr.push_back(drr);
+ }
+ di.backend->replaceRRSet(di.id, c.first.first, QType(c.first.second), vrr);
+ }
+ rectifyZone(dk, zone);
+ return EXIT_SUCCESS;
+}
+
+
+int loadZone(DNSName zone, const string& fname) {
+ UeberBackend B;
+ DomainInfo di;
+
+ if (B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' exists already, replacing contents"<<endl;
+ }
+ else {
+ cerr<<"Creating '"<<zone<<"'"<<endl;
+ B.createDomain(zone);
+
+ if(!B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' was not created - perhaps backend ("<<::arg()["launch"]<<") does not support storing new zones."<<endl;
+ return EXIT_FAILURE;
+ }
+ }
+ DNSBackend* db = di.backend;
+ ZoneParserTNG zpt(fname, zone);
+
+ DNSResourceRecord rr;
+ if(!db->startTransaction(zone, di.id)) {
+ cerr<<"Unable to start transaction for load of zone '"<<zone<<"'"<<endl;
+ return EXIT_FAILURE;
+ }
+ rr.domain_id=di.id;
+ bool haveSOA = false;
+ while(zpt.get(rr)) {
+ if(!rr.qname.isPartOf(zone) && rr.qname!=zone) {
+ cerr<<"File contains record named '"<<rr.qname<<"' which is not part of zone '"<<zone<<"'"<<endl;
+ return EXIT_FAILURE;
+ }
+ if (rr.qtype == QType::SOA) {
+ if (haveSOA)
+ continue;
+ else
+ haveSOA = true;
+ }
+ db->feedRecord(rr);
+ }
+ db->commitTransaction();
+ return EXIT_SUCCESS;
+}
+
+int createZone(const DNSName &zone, const DNSName& nsname) {
+ UeberBackend B;
+ DomainInfo di;
+ if (B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' exists already"<<endl;
+ return EXIT_FAILURE;
+ }
+ cerr<<"Creating empty zone '"<<zone<<"'"<<endl;
+ B.createDomain(zone);
+ if(!B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' was not created!"<<endl;
+ return EXIT_FAILURE;
+ }
+
+ DNSResourceRecord rr;
+ rr.qname = zone;
+ rr.auth = 1;
+ rr.ttl = ::arg().asNum("default-ttl");
+ rr.qtype = "SOA";
+
+ string soa = (boost::format("%s %s 1")
+ % (nsname.empty() ? ::arg()["default-soa-name"] : nsname.toString())
+ % (::arg().isEmpty("default-soa-mail") ? (DNSName("hostmaster.") + zone).toString() : ::arg()["default-soa-mail"])
+ ).str();
+ SOAData sd;
+ fillSOAData(soa, sd); // fills out default values for us
+ rr.content = DNSRecordContent::mastermake(rr.qtype.getCode(), 1, serializeSOAData(sd))->getZoneRepresentation(true);
+ rr.domain_id = di.id;
+ di.backend->startTransaction(zone, di.id);
+ di.backend->feedRecord(rr);
+ if(!nsname.empty()) {
+ cout<<"Also adding one NS record"<<endl;
+ rr.qtype=QType::NS;
+ rr.content=nsname.toStringNoDot();
+ di.backend->feedRecord(rr);
+ }
+
+ di.backend->commitTransaction();
+
+ return EXIT_SUCCESS;
+}
+
+int createSlaveZone(const vector<string>& cmds) {
+ UeberBackend B;
+ DomainInfo di;
+ DNSName zone(cmds[1]);
+ if (B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' exists already"<<endl;
+ return EXIT_FAILURE;
+ }
+ vector<string> masters;
+ for (unsigned i=2; i < cmds.size(); i++) {
+ ComboAddress master(cmds[2], 53);
+ masters.push_back(master.toStringWithPort());
+ }
+ cerr<<"Creating slave zone '"<<zone<<"', with master(s) '"<<boost::join(masters, ",")<<"'"<<endl;
+ B.createDomain(zone);
+ if(!B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' was not created!"<<endl;
+ return EXIT_FAILURE;
+ }
+ di.backend->setKind(zone, DomainInfo::Slave);
+ di.backend->setMaster(zone, boost::join(masters, ","));
+ return EXIT_SUCCESS;
+}
+
+// add-record ZONE name type [ttl] "content" ["content"]
+int addOrReplaceRecord(bool addOrReplace, const vector<string>& cmds) {
+ DNSResourceRecord rr;
+ vector<DNSResourceRecord> newrrs;
+ DNSName zone(cmds[1]);
+ DNSName name;
+ if(cmds[2]=="@")
+ name=zone;
+ else
+ name=DNSName(cmds[2])+zone;
+
+ rr.qtype = DNSRecordContent::TypeToNumber(cmds[3]);
+ rr.ttl = ::arg().asNum("default-ttl");
+
+ UeberBackend B;
+ DomainInfo di;
+
+ if(!B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' does not exist"<<endl;
+ return EXIT_FAILURE;
+ }
+ rr.auth = 1;
+ rr.domain_id = di.id;
+ rr.qname = name;
+ DNSResourceRecord oldrr;
+ if(addOrReplace) { // the 'add' case
+ B.lookup(rr.qtype, rr.qname, 0, di.id);
+
+ while(B.get(oldrr))
+ newrrs.push_back(oldrr);
+ }
+
+ unsigned int contentStart = 4;
+ if(cmds.size() > 5) {
+ rr.ttl=atoi(cmds[4].c_str());
+ if(std::to_string(rr.ttl)==cmds[4]) {
+ contentStart++;
+ }
+ else rr.ttl = ::arg().asNum("default-ttl");
+ }
+
+ B.lookup(QType(QType::ANY), rr.qname, 0, di.id);
+ bool found=false;
+ if(rr.qtype.getCode() == QType::CNAME) { // this will save us SO many questions
+
+ while(B.get(oldrr)) {
+ if(addOrReplace || oldrr.qtype.getCode() != QType::CNAME) // the replace case is ok if we replace one CNAME by the other
+ found=true;
+ }
+ if(found) {
+ cerr<<"Attempting to add CNAME to "<<rr.qname<<" which already had existing records"<<endl;
+ return EXIT_FAILURE;
+ }
+ }
+ else {
+ while(B.get(oldrr)) {
+ if(oldrr.qtype.getCode() == QType::CNAME)
+ found=true;
+ }
+ if(found) {
+ cerr<<"Attempting to add record to "<<rr.qname<<" which already had a CNAME record"<<endl;
+ return EXIT_FAILURE;
+ }
+ }
+
+ if(!addOrReplace) {
+ cout<<"Current records for "<<rr.qname<<" IN "<<rr.qtype.getName()<<" will be replaced"<<endl;
+ }
+ for(auto i = contentStart ; i < cmds.size() ; ++i) {
+ rr.content = DNSRecordContent::mastermake(rr.qtype.getCode(), 1, cmds[i])->getZoneRepresentation(true);
+
+ newrrs.push_back(rr);
+ }
+
+
+ di.backend->replaceRRSet(di.id, name, rr.qtype, newrrs);
+ // need to be explicit to bypass the ueberbackend cache!
+ di.backend->lookup(rr.qtype, name, 0, di.id);
+ cout<<"New rrset:"<<endl;
+ while(di.backend->get(rr)) {
+ cout<<rr.qname.toString()<<" IN "<<rr.qtype.getName()<<" "<<rr.ttl<<" "<<rr.content<<endl;
+ }
+ return EXIT_SUCCESS;
+}
+
+// delete-rrset zone name type
+int deleteRRSet(const std::string& zone_, const std::string& name_, const std::string& type_)
+{
+ UeberBackend B;
+ DomainInfo di;
+ DNSName zone(zone_);
+ if(!B.getDomainInfo(zone, di)) {
+ cerr<<"Domain '"<<zone<<"' does not exist"<<endl;
+ return EXIT_FAILURE;
+ }
+
+ DNSName name;
+ if(name_=="@")
+ name=zone;
+ else
+ name=DNSName(name_)+zone;
+
+ QType qt(QType::chartocode(type_.c_str()));
+ di.backend->replaceRRSet(di.id, name, qt, vector<DNSResourceRecord>());
+ return EXIT_SUCCESS;
+}
+
+int listAllZones(const string &type="") {
+
+ int kindFilter = -1;
+ if (type.size()) {
+ if (toUpper(type) == "MASTER")
+ kindFilter = 0;
+ else if (toUpper(type) == "SLAVE")
+ kindFilter = 1;
+ else if (toUpper(type) == "NATIVE")
+ kindFilter = 2;
+ else {
+ cerr<<"Syntax: pdnsutil list-all-zones [master|slave|native]"<<endl;
+ return 1;
+ }
+ }
+
+ UeberBackend B("default");
+
+ vector<DomainInfo> domains;
+ B.getAllDomains(&domains, true);
+
+ int count = 0;
+ for (vector<DomainInfo>::const_iterator di=domains.begin(); di != domains.end(); di++) {
+ if (di->kind == kindFilter || kindFilter == -1) {
+ cout<<di->zone<<endl;
+ count++;
+ }
+ }
+
+ if (kindFilter != -1)
+ cout<<type<<" zonecount: "<<count<<endl;
+ else
+ cout<<"All zonecount: "<<count<<endl;
+ return 0;
+}
+
+bool testAlgorithm(int algo)
+{
+ return DNSCryptoKeyEngine::testOne(algo);
+}
+
+bool testAlgorithms()
+{
+ return DNSCryptoKeyEngine::testAll();
+}
+
+void testSpeed(DNSSECKeeper& dk, const DNSName& zone, const string& remote, int cores)
+{
+ DNSResourceRecord rr;
+ rr.qname=DNSName("blah")+zone;
+ rr.qtype=QType::A;
+ rr.ttl=3600;
+ rr.auth=1;
+ rr.qclass = QClass::IN;
+ rr.d_place=DNSResourceRecord::ANSWER;
+
+ UeberBackend db("key-only");
+
+ if ( ! db.backends.size() )
+ {
+ throw runtime_error("No backends available for DNSSEC key storage");
+ }
+
+ ChunkedSigningPipe csp(DNSName(zone), 1, remote, cores);
+
+ vector<DNSResourceRecord> signatures;
+ uint32_t rnd;
+ unsigned char* octets = (unsigned char*)&rnd;
+ char tmp[25];
+ DTime dt;
+ dt.set();
+ for(unsigned int n=0; n < 100000; ++n) {
+ rnd = random();
+ snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
+ octets[0], octets[1], octets[2], octets[3]);
+ rr.content=tmp;
+
+ snprintf(tmp, sizeof(tmp), "r-%u", rnd);
+ rr.qname=DNSName(tmp)+zone;
+
+ if(csp.submit(rr))
+ while(signatures = csp.getChunk(), !signatures.empty())
+ ;
+ }
+ cerr<<"Flushing the pipe, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
+ cerr<<"Net speed: "<<csp.d_signed/ (dt.udiffNoReset()/1000000.0) << " sigs/s"<<endl;
+ while(signatures = csp.getChunk(true), !signatures.empty())
+ ;
+ cerr<<"Done, "<<csp.d_signed<<" signed, "<<csp.d_queued<<" queued, "<<csp.d_outstanding<<" outstanding"<< endl;
+ cerr<<"Net speed: "<<csp.d_signed/ (dt.udiff()/1000000.0) << " sigs/s"<<endl;
+}
+
+void verifyCrypto(const string& zone)
+{
+ ZoneParserTNG zpt(zone);
+ DNSResourceRecord rr;
+ DNSKEYRecordContent drc;
+ RRSIGRecordContent rrc;
+ DSRecordContent dsrc;
+ vector<shared_ptr<DNSRecordContent> > toSign;
+ DNSName qname, apex;
+ dsrc.d_digesttype=0;
+ while(zpt.get(rr)) {
+ if(rr.qtype.getCode() == QType::DNSKEY) {
+ cerr<<"got DNSKEY!"<<endl;
+ apex=rr.qname;
+ drc = *dynamic_cast<DNSKEYRecordContent*>(DNSRecordContent::mastermake(QType::DNSKEY, 1, rr.content));
+ }
+ else if(rr.qtype.getCode() == QType::RRSIG) {
+ cerr<<"got RRSIG"<<endl;
+ rrc = *dynamic_cast<RRSIGRecordContent*>(DNSRecordContent::mastermake(QType::RRSIG, 1, rr.content));
+ }
+ else if(rr.qtype.getCode() == QType::DS) {
+ cerr<<"got DS"<<endl;
+ dsrc = *dynamic_cast<DSRecordContent*>(DNSRecordContent::mastermake(QType::DS, 1, rr.content));
+ }
+ else {
+ qname = rr.qname;
+ toSign.push_back(shared_ptr<DNSRecordContent>(DNSRecordContent::mastermake(rr.qtype.getCode(), 1, rr.content)));
+ }
+ }
+
+ string msg = getMessageForRRSET(qname, rrc, toSign);
+ cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(msg, rrc.d_signature)<<endl;
+ if(dsrc.d_digesttype) {
+ cerr<<"Calculated DS: "<<apex.toString()<<" IN DS "<<makeDSFromDNSKey(apex, drc, dsrc.d_digesttype).getZoneRepresentation()<<endl;
+ cerr<<"Original DS: "<<apex.toString()<<" IN DS "<<dsrc.getZoneRepresentation()<<endl;
+ }
+#if 0
+ std::shared_ptr<DNSCryptoKeyEngine> key=DNSCryptoKeyEngine::makeFromISCString(drc, "Private-key-format: v1.2\n"
+ "Algorithm: 12 (ECC-GOST)\n"
+ "GostAsn1: MEUCAQAwHAYGKoUDAgITMBIGByqFAwICIwEGByqFAwICHgEEIgQg/9MiXtXKg9FDXDN/R9CmVhJDyuzRAIgh4tPwCu4NHIs=\n");
+ string resign=key->sign(hash);
+ cerr<<Base64Encode(resign)<<endl;
+ cerr<<"Verify: "<<DNSCryptoKeyEngine::makeFromPublicKeyString(drc.d_algorithm, drc.d_key)->verify(hash, resign)<<endl;
+#endif
+
+}
+bool disableDNSSECOnZone(DNSSECKeeper& dk, const DNSName& zone)
+{
+ UeberBackend B("default");
+ DomainInfo di;
+
+ if (!B.getDomainInfo(zone, di)){
+ cerr << "No such zone in the database" << endl;
+ return false;
+ }
+
+ if(!dk.isSecuredZone(zone)) {
+ cerr<<"Zone is not secured"<<endl;
+ return false;
+ }
+ DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
+
+ if(keyset.empty()) {
+ cerr << "No keys for zone '"<<zone<<"'."<<endl;
+ }
+ else {
+ for(DNSSECKeeper::keyset_t::value_type value : keyset) {
+ dk.deactivateKey(zone, value.second.id);
+ dk.removeKey(zone, value.second.id);
+ }
+ }
+ dk.unsetNSEC3PARAM(zone);
+ dk.unsetPresigned(zone);
+ return true;
+}
+
+int setZoneKind(const DNSName& zone, const DomainInfo::DomainKind kind)
+{
+ UeberBackend B("default");
+ DomainInfo di;
+ std::vector<std::string> meta;
+
+ if (!B.getDomainInfo(zone, di)){
+ cerr << "No such zone "<<zone<<" in the database" << endl;
+ return EXIT_FAILURE;
+ }
+ if(!di.backend->setKind(zone, kind)) {
+ cerr<<"Could not find backend willing to accept new zone configuration"<<endl;
+ return EXIT_FAILURE;
+ }
+ return EXIT_SUCCESS;
+}
+
+bool showZone(DNSSECKeeper& dk, const DNSName& zone)
+{
+ UeberBackend B("default");
+ DomainInfo di;
+ std::vector<std::string> meta;
+
+ if (!B.getDomainInfo(zone, di)){
+ cerr << "No such zone in the database" << endl;
+ return false;
+ }
+
+ cout<<"This is a "<<DomainInfo::getKindString(di.kind)<<" zone"<<endl;
+ if(di.kind == DomainInfo::Master) {
+ cout<<"Last SOA serial number we notified: "<<di.notified_serial<<" ";
+ SOAData sd;
+ if(B.getSOAUncached(zone, sd)) {
+ if(sd.serial == di.notified_serial)
+ cout<< "== ";
+ else
+ cout << "!= ";
+ cout<<sd.serial<<" (serial in the database)"<<endl;
+ }
+ else
+ cout<<"- no serial found in database"<<endl;
+ }
+ else if(di.kind == DomainInfo::Slave) {
+ cout<<"Master"<<addS(di.masters)<<": ";
+ for(const auto& m : di.masters)
+ cout<<m<<" ";
+ cout<<endl;
+ struct tm tm;
+ localtime_r(&di.last_check, &tm);
+ char buf[80];
+ if(di.last_check)
+ strftime(buf, sizeof(buf)-1, "%a %F %H:%M:%S", &tm);
+ else
+ strncpy(buf, "Never", sizeof(buf)-1);
+ buf[sizeof(buf)-1] = '\0';
+ cout<<"Last time we got update from master: "<<buf<<endl;
+ SOAData sd;
+ if(B.getSOAUncached(zone, sd)) {
+ cout<<"SOA serial in database: "<<sd.serial<<endl;
+ cout<<"Refresh interval: "<<sd.refresh<<" seconds"<<endl;
+ }
+ else
+ cout<<"No SOA serial found in database"<<endl;
+ }
+
+
+ if(!dk.isSecuredZone(zone)) {
+ cout<<"Zone is not actively secured"<<endl;
+ }
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+ bool haveNSEC3=dk.getNSEC3PARAM(zone, &ns3pr, &narrow);
+
+ DNSSECKeeper::keyset_t keyset=dk.getKeys(zone);
+ if (B.getDomainMetadata(zone, "TSIG-ALLOW-AXFR", meta) && meta.size() > 0) {
+ cout << "Zone has following allowed TSIG key(s): " << boost::join(meta, ",") << endl;
+ }
+
+ meta.clear();
+ if (B.getDomainMetadata(zone, "AXFR-MASTER-TSIG", meta) && meta.size() > 0) {
+ cout << "Zone uses following TSIG key(s): " << boost::join(meta, ",") << endl;
+ }
+
+ std::map<std::string, std::vector<std::string> > metamap;
+ if(B.getAllDomainMetadata(zone, metamap)) {
+ cout<<"Metadata items: ";
+ if(metamap.empty())
+ cout<<"None";
+ cout<<endl;
+
+ for(const auto& m : metamap) {
+ for(const auto i : m.second)
+ cout << '\t' << m.first<<'\t' << i <<endl;
+ }
+ }
+
+ if (dk.isPresigned(zone)) {
+ cout <<"Zone is presigned"<<endl;
+ // get us some keys
+ vector<DNSKEYRecordContent> keys;
+ DNSResourceRecord rr;
+
+ B.lookup(QType(QType::DNSKEY), zone);
+ while(B.get(rr)) {
+ if (rr.qtype != QType::DNSKEY) continue;
+ keys.push_back(DNSKEYRecordContent(rr.getZoneRepresentation()));
+ }
+
+ if(keys.empty()) {
+ cerr << "No keys for zone '"<<zone<<"'."<<endl;
+ return true;
+ }
+
+ if(!haveNSEC3)
+ cout<<"Zone has NSEC semantics"<<endl;
+ else
+ cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
+ cout << "keys: "<<endl;
+ sort(keys.begin(),keys.end());
+ reverse(keys.begin(),keys.end());
+ bool shown=false;
+ for(const auto& key : keys) {
+ string algname = DNSSECKeeper::algorithm2name(key.d_algorithm);
+
+ int bits = -1;
+ try {
+ std::shared_ptr<DNSCryptoKeyEngine> engine(DNSCryptoKeyEngine::makeFromPublicKeyString(key.d_algorithm, key.d_key)); // throws on unknown algo or bad key
+ bits=engine->getBits();
+ }
+ catch(std::exception& e) {
+ cout<<"Could not process key to extract metadata: "<<e.what()<<endl;
+ }
+ cout << (key.d_flags == 257 ? "KSK" : "ZSK") << ", tag = " << key.getTag() << ", algo = "<<(int)key.d_algorithm << ", bits = " << bits << endl;
+ cout << "DNSKEY = " <<zone.toString()<<" IN DNSKEY "<< key.getZoneRepresentation() << "; ( " + algname + " ) " <<endl;
+ if (shown) continue;
+ shown=true;
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl;
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl;
+ try {
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, 3).getZoneRepresentation() << " ; ( GOST R 34.11-94 digest )" << endl;
+ }
+ catch(...)
+ {}
+ try {
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, key, 4).getZoneRepresentation() << " ; ( SHA-384 digest )" << endl;
+ }
+ catch(...)
+ {}
+ }
+ }
+ else if(keyset.empty()) {
+ cerr << "No keys for zone '"<<zone<<"'."<<endl;
+ }
+ else {
+ if(!haveNSEC3)
+ cout<<"Zone has NSEC semantics"<<endl;
+ else
+ cout<<"Zone has " << (narrow ? "NARROW " : "") <<"hashed NSEC3 semantics, configuration: "<<ns3pr.getZoneRepresentation()<<endl;
+
+ cout << "keys: "<<endl;
+ for(DNSSECKeeper::keyset_t::value_type value : keyset) {
+ string algname = DNSSECKeeper::algorithm2name(value.first.d_algorithm);
+ cout<<"ID = "<<value.second.id<<" ("<<DNSSECKeeper::keyTypeToString(value.second.keyType)<<")";
+ if (value.first.getKey()->getBits() < 1) {
+ cout<<" <key missing or defunct>" <<endl;
+ continue;
+ }
+ cout<<", flags = "<<std::to_string(value.first.d_flags);
+ cout<<", tag = "<<value.first.getDNSKEY().getTag();
+ cout<<", algo = "<<(int)value.first.d_algorithm<<", bits = "<<value.first.getKey()->getBits()<<"\t"<<((int)value.second.active == 1 ? " A" : "Ina")<<"ctive ( " + algname + " ) "<<endl;
+ if(value.second.keyType == DNSSECKeeper::KSK || value.second.keyType == DNSSECKeeper::CSK || ::arg().mustDo("direct-dnskey"))
+ cout<<DNSSECKeeper::keyTypeToString(value.second.keyType)<<" DNSKEY = "<<zone.toString()<<" IN DNSKEY "<< value.first.getDNSKEY().getZoneRepresentation() << " ; ( " + algname + " )" << endl;
+ if(value.second.keyType == DNSSECKeeper::KSK || value.second.keyType == DNSSECKeeper::CSK) {
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 1).getZoneRepresentation() << " ; ( SHA1 digest )" << endl;
+ cout<<"DS = "<<zone.toString()<<" IN DS "<<makeDSFromDNSKey(zone, value.first.getDNSKEY(), 2).getZoneRepresentation() << " ; ( SHA256 digest )" << endl;
+ try {
+ string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 3).getZoneRepresentation();
+ cout<<"DS = "<<zone.toString()<<" IN DS "<< output << " ; ( GOST R 34.11-94 digest )" << endl;
+ }
+ catch(...)
+ {
+ }
+ try {
+ string output=makeDSFromDNSKey(zone, value.first.getDNSKEY(), 4).getZoneRepresentation();
+ cout<<"DS = "<<zone.toString()<<" IN DS "<< output << " ; ( SHA-384 digest )" << endl;
+ }
+ catch(...)
+ {
+ }
+ cout<<endl;
+ }
+ }
+ }
+ return true;
+}
+
+bool secureZone(DNSSECKeeper& dk, const DNSName& zone)
+{
+ // parse attribute
+ vector<string> k_algos;
+ vector<string> z_algos;
+ int k_size;
+ int z_size;
+
+ stringtok(k_algos, ::arg()["default-ksk-algorithms"], " ,");
+ k_size = ::arg().asNum("default-ksk-size");
+ stringtok(z_algos, ::arg()["default-zsk-algorithms"], " ,");
+ z_size = ::arg().asNum("default-zsk-size");
+
+ if (k_size < 0) {
+ throw runtime_error("KSK key size must be equal to or greater than 0");
+ }
+
+ if (k_algos.size() < 1 && z_algos.size() < 1) {
+ throw runtime_error("Zero algorithms given for KSK+ZSK in total");
+ }
+
+ if (z_size < 0) {
+ throw runtime_error("ZSK key size must be equal to or greater than 0");
+ }
+
+ if(dk.isSecuredZone(zone)) {
+ cerr << "Zone '"<<zone<<"' already secure, remove keys with pdnsutil remove-zone-key if needed"<<endl;
+ return false;
+ }
+
+ DomainInfo di;
+ UeberBackend B("default");
+ if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
+ cerr<<"Can't find a zone called '"<<zone<<"'"<<endl;
+ return false;
+ }
+
+ if(di.kind == DomainInfo::Slave)
+ {
+ cerr<<"Warning! This is a slave domain! If this was a mistake, please run"<<endl;
+ cerr<<"pdnsutil disable-dnssec "<<zone<<" right now!"<<endl;
+ }
+
+ if (k_size)
+ cout << "Securing zone with key size " << k_size << endl;
+ else
+ cout << "Securing zone with default key size" << endl;
+
+ if (k_algos.empty()) { /* only a ZSK was requested by the defaults, set the SEP bit */
+ }
+
+
+ for(auto &k_algo: k_algos) {
+ cout << "Adding "<<(z_algos.empty()? "CSK (257)" : "KSK")<<" with algorithm " << k_algo << endl;
+
+ int algo = DNSSECKeeper::shorthand2algorithm(k_algo);
+
+ if(!dk.addKey(zone, true, algo, k_size, true)) {
+ cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC"<<endl;
+ cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl;
+ cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl;
+ cerr<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl;
+ return false;
+ }
+ }
+
+ for(auto &z_algo : z_algos)
+ {
+ cout << "Adding "<<(k_algos.empty()? "CSK (256)" : "ZSK")<<" with algorithm " << z_algo << endl;
+
+ int algo = DNSSECKeeper::shorthand2algorithm(z_algo);
+
+ if(!dk.addKey(zone, false, algo, z_size, true)) {
+ cerr<<"No backend was able to secure '"<<zone<<"', most likely because no DNSSEC"<<endl;
+ cerr<<"capable backends are loaded, or because the backends have DNSSEC disabled."<<endl;
+ cerr<<"For the Generic SQL backends, set the 'gsqlite3-dnssec', 'gmysql-dnssec' or"<<endl;
+ cerr<<"'gpgsql-dnssec' flag. Also make sure the schema has been updated for DNSSEC!"<<endl;
+ return false;
+ }
+ }
+
+ if(!dk.isSecuredZone(zone)) {
+ cerr<<"Failed to secure zone. Is your backend dnssec enabled? (set "<<endl;
+ cerr<<"gsqlite3-dnssec, or gmysql-dnssec etc). Check this first."<<endl;
+ cerr<<"If you run with the BIND backend, make sure you have configured"<<endl;
+ cerr<<"it to use DNSSEC with 'bind-dnssec-db=/path/fname' and"<<endl;
+ cerr<<"'pdnsutil create-bind-db /path/fname'!"<<endl;
+ return false;
+ }
+
+ // rectifyZone(dk, zone);
+ // showZone(dk, zone);
+ cout<<"Zone "<<zone<<" secured"<<endl;
+ return true;
+}
+
+void testSchema(DNSSECKeeper& dk, const DNSName& zone)
+{
+ cout<<"Note: test-schema will try to create the zone, but it will not remove it."<<endl;
+ cout<<"Please clean up after this."<<endl;
+ cout<<endl;
+ cout<<"Constructing UeberBackend"<<endl;
+ UeberBackend B("default");
+ cout<<"Picking first backend - if this is not what you want, edit launch line!"<<endl;
+ DNSBackend *db = B.backends[0];
+ cout<<"Creating slave domain "<<zone<<endl;
+ db->createSlaveDomain("127.0.0.1", zone, "", "_testschema");
+ cout<<"Slave domain created"<<endl;
+
+ DomainInfo di;
+ if(!B.getDomainInfo(zone, di) || !di.backend) { // di.backend and B are mostly identical
+ cout<<"Can't find domain we just created, aborting"<<endl;
+ return;
+ }
+ db=di.backend;
+ DNSResourceRecord rr, rrget;
+ cout<<"Starting transaction to feed records"<<endl;
+ db->startTransaction(zone, di.id);
+
+ rr.qtype=QType::SOA;
+ rr.qname=zone;
+ rr.ttl=86400;
+ rr.domain_id=di.id;
+ rr.auth=1;
+ rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
+ cout<<"Feeding SOA"<<endl;
+ db->feedRecord(rr);
+ rr.qtype=QType::TXT;
+ // 300 As
+ rr.content="\"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA\"";
+ cout<<"Feeding overlong TXT"<<endl;
+ db->feedRecord(rr);
+ cout<<"Committing"<<endl;
+ db->commitTransaction();
+ cout<<"Querying TXT"<<endl;
+ db->lookup(QType(QType::TXT), zone, NULL, di.id);
+ if(db->get(rrget))
+ {
+ DNSResourceRecord rrthrowaway;
+ if(db->get(rrthrowaway)) // should not touch rr but don't assume anything
+ {
+ cout<<"Expected one record, got multiple, aborting"<<endl;
+ return;
+ }
+ int size=rrget.content.size();
+ if(size != 302)
+ {
+ cout<<"Expected 302 bytes, got "<<size<<", aborting"<<endl;
+ return;
+ }
+ }
+ cout<<"[+] content field is over 255 bytes"<<endl;
+
+ cout<<"Dropping all records, inserting SOA+2xA"<<endl;
+ db->startTransaction(zone, di.id);
+
+ rr.qtype=QType::SOA;
+ rr.qname=zone;
+ rr.ttl=86400;
+ rr.domain_id=di.id;
+ rr.auth=1;
+ rr.content="ns1.example.com. ahu.example.com. 2012081039 7200 3600 1209600 3600";
+ cout<<"Feeding SOA"<<endl;
+ db->feedRecord(rr);
+
+ rr.qtype=QType::A;
+ rr.qname=DNSName("_underscore")+zone;
+ rr.content="127.0.0.1";
+ db->feedRecord(rr);
+
+ rr.qname=DNSName("bla")+zone;
+ cout<<"Committing"<<endl;
+ db->commitTransaction();
+
+ cout<<"Securing zone"<<endl;
+ secureZone(dk, zone);
+ cout<<"Rectifying zone"<<endl;
+ rectifyZone(dk, zone);
+ cout<<"Checking underscore ordering"<<endl;
+ DNSName before, after;
+ db->getBeforeAndAfterNames(di.id, zone, DNSName("z")+zone, before, after);
+ cout<<"got '"<<before.toString()<<"' < 'z."<<zone.toString()<<"' < '"<<after.toString()<<"'"<<endl;
+ if(before != DNSName("_underscore")+zone)
+ {
+ cout<<"before is wrong, got '"<<before.toString()<<"', expected '_underscore."<<zone.toString()<<"', aborting"<<endl;
+ return;
+ }
+ if(after != zone)
+ {
+ cout<<"after is wrong, got '"<<after.toString()<<"', expected '"<<zone.toString()<<"', aborting"<<endl;
+ return;
+ }
+ cout<<"[+] ordername sorting is correct for names starting with _"<<endl;
+ cout<<endl;
+ cout<<"End of tests, please remove "<<zone<<" from domains+records"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ po::options_description desc("Allowed options");
+ desc.add_options()
+ ("help,h", "produce help message")
+ ("version", "show version")
+ ("verbose,v", "be verbose")
+ ("force", "force an action")
+ ("config-name", po::value<string>()->default_value(""), "virtual configuration name")
+ ("config-dir", po::value<string>()->default_value(SYSCONFDIR), "location of pdns.conf")
+ ("commands", po::value<vector<string> >());
+
+ po::positional_options_description p;
+ p.add("commands", -1);
+ po::store(po::command_line_parser(argc, argv).options(desc).positional(p).run(), g_vm);
+ po::notify(g_vm);
+
+ vector<string> cmds;
+
+ if(g_vm.count("commands"))
+ cmds = g_vm["commands"].as<vector<string> >();
+
+ g_verbose = g_vm.count("verbose");
+
+ if (g_vm.count("version")) {
+ cout<<"pdnsutil "<<VERSION<<endl;
+ return 0;
+ }
+
+ if(cmds.empty() || g_vm.count("help") || cmds[0] == "help") {
+ cout<<"Usage: \npdnsutil [options] <command> [params ..]\n"<<endl;
+ cout<<"Commands:"<<endl;
+ cout<<"activate-tsig-key ZONE NAME {master|slave}"<<endl;
+ cout<<" Enable TSIG authenticated AXFR using the key NAME for ZONE"<<endl;
+ cout<<"activate-zone-key ZONE KEY-ID Activate the key with key id KEY-ID in ZONE"<<endl;
+ cout<<"add-record ZONE NAME TYPE [ttl] content"<<endl;
+ cout<<" [content..] Add one or more records to ZONE"<<endl;
+ cout<<"add-zone-key ZONE {zsk|ksk} [BITS] [active|inactive]"<<endl;
+ cout<<" [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384";
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF)
+ cout<<"|ed25519";
+#endif
+#ifdef HAVE_LIBDECAF
+ cout<<"|ed448";
+#endif
+ cout<<"]"<<endl;
+ cout<<" Add a ZSK or KSK to zone and specify algo&bits"<<endl;
+ cout<<"backend-cmd BACKEND CMD [CMD..] Perform one or more backend commands"<<endl;
+ cout<<"b2b-migrate OLD NEW Move all data from one backend to another"<<endl;
+ cout<<"bench-db [filename] Bench database backend with queries, one domain per line"<<endl;
+ cout<<"check-zone ZONE Check a zone for correctness"<<endl;
+ cout<<"check-all-zones [exit-on-error] Check all zones for correctness. Set exit-on-error to exit immediately"<<endl;
+ cout<<" after finding an error in a zone."<<endl;
+ cout<<"clear-zone ZONE Clear all records of a zone, but keep everything else"<<endl;
+ cout<<"create-bind-db FNAME Create DNSSEC db for BIND backend (bind-dnssec-db)"<<endl;
+ cout<<"create-slave-zone ZONE master-ip [master-ip..]"<<endl;
+ cout<<" Create slave zone ZONE with master IP address master-ip"<<endl;
+ cout<<"create-zone ZONE [nsname] Create empty zone ZONE"<<endl;
+ cout<<"deactivate-tsig-key ZONE NAME {master|slave}"<<endl;
+ cout<<" Disable TSIG authenticated AXFR using the key NAME for ZONE"<<endl;
+ cout<<"deactivate-zone-key ZONE KEY-ID Deactivate the key with key id KEY-ID in ZONE"<<endl;
+ cout<<"delete-rrset ZONE NAME TYPE Delete named RRSET from zone"<<endl;
+ cout<<"delete-tsig-key NAME Delete TSIG key (warning! will not unmap key!)"<<endl;
+ cout<<"delete-zone ZONE Delete the zone"<<endl;
+ cout<<"disable-dnssec ZONE Deactivate all keys and unset PRESIGNED in ZONE"<<endl;
+ cout<<"edit-zone ZONE Edit zone contents using $EDITOR"<<endl;
+ cout<<"export-zone-dnskey ZONE KEY-ID Export to stdout the public DNSKEY described"<<endl;
+ cout<<"export-zone-key ZONE KEY-ID Export to stdout the private key described"<<endl;
+ cout<<"generate-tsig-key NAME ALGORITHM Generate new TSIG key"<<endl;
+ cout<<"generate-zone-key {zsk|ksk} [ALGORITHM] [BITS]"<<endl;
+ cout<<" Generate a ZSK or KSK to stdout with specified ALGORITHM and BITS"<<endl;
+ cout<<"get-meta ZONE [KIND ...] Get zone metadata. If no KIND given, lists all known"<<endl;
+ cout<<"hash-zone-record ZONE RNAME Calculate the NSEC3 hash for RNAME in ZONE"<<endl;
+#ifdef HAVE_P11KIT1
+ cout<<"hsm assign ZONE ALGORITHM {ksk|zsk} MODULE SLOT PIN LABEL"<<endl<<
+ " Assign a hardware signing module to a ZONE"<<endl;
+ cout<<"hsm create-key ZONE KEY-ID [BITS] Create a key using hardware signing module for ZONE (use assign first)"<<endl;
+ cout<<" BITS defaults to 2048"<<endl;
+#endif
+ cout<<"increase-serial ZONE Increases the SOA-serial by 1. Uses SOA-EDIT"<<endl;
+ cout<<"import-tsig-key NAME ALGORITHM KEY Import TSIG key"<<endl;
+ cout<<"import-zone-key ZONE FILE Import from a file a private key, ZSK or KSK"<<endl;
+ cout<<" [active|inactive] [ksk|zsk] Defaults to KSK and active"<<endl;
+ cout<<"load-zone ZONE FILE Load ZONE from FILE, possibly creating zone or atomically"<<endl;
+ cout<<" replacing contents"<<endl;
+ cout<<"list-algorithms [with-backend] List all DNSSEC algorithms supported, optionally also listing the crypto library used"<<endl;
+ cout<<"list-keys [ZONE] List DNSSEC keys for ZONE. When ZONE is unset or \"all\", display all keys for all zones"<<endl;
+ cout<<"list-zone ZONE List zone contents"<<endl;
+ cout<<"list-all-zones [master|slave|native]"<<endl;
+ cout<<" List all zone names"<<endl;;
+ cout<<"list-tsig-keys List all TSIG keys"<<endl;
+ cout<<"rectify-zone ZONE [ZONE ..] Fix up DNSSEC fields (order, auth)"<<endl;
+ cout<<"rectify-all-zones Rectify all zones."<<endl;
+ cout<<"remove-zone-key ZONE KEY-ID Remove key with KEY-ID from ZONE"<<endl;
+ cout<<"replace-rrset ZONE NAME TYPE [ttl] Replace named RRSET from zone"<<endl;
+ cout<<" content [content..]"<<endl;
+ cout<<"secure-all-zones [increase-serial] Secure all zones without keys"<<endl;
+ cout<<"secure-zone ZONE [ZONE ..] Add DNSSEC to zone ZONE"<<endl;
+ cout<<"set-kind ZONE KIND Change the kind of ZONE to KIND (master, slave native)"<<endl;
+ cout<<"set-nsec3 ZONE ['PARAMS' [narrow]] Enable NSEC3 with PARAMS. Optionally narrow"<<endl;
+ cout<<"set-presigned ZONE Use presigned RRSIGs from storage"<<endl;
+ cout<<"set-publish-cdnskey ZONE Enable sending CDNSKEY responses for ZONE"<<endl;
+ cout<<"set-publish-cds ZONE [DIGESTALGOS] Enable sending CDS responses for ZONE, using DIGESTALGOS as signature algirithms"<<endl;
+ cout<<" DIGESTALGOS should be a comma separated list of numbers, is is '1,2' by default"<<endl;
+ cout<<"set-meta ZONE KIND [VALUE] [VALUE] Set zone metadata, optionally providing a value. *No* value clears meta"<<endl;
+ cout<<" Note - this will replace all metadata records of KIND!"<<endl;
+ cout<<"show-zone ZONE Show DNSSEC (public) key details about a zone"<<endl;
+ cout<<"unset-nsec3 ZONE Switch back to NSEC"<<endl;
+ cout<<"unset-presigned ZONE No longer use presigned RRSIGs"<<endl;
+ cout<<"unset-publish-cdnskey ZONE Disable sending CDNSKEY responses for ZONE"<<endl;
+ cout<<"unset-publish-cds ZONE Disable sending CDS responses for ZONE"<<endl;
+ cout<<"test-schema ZONE Test DB schema - will create ZONE"<<endl;
+ cout<<desc<<endl;
+ return 0;
+ }
+
+loadMainConfig(g_vm["config-dir"].as<string>());
+
+#ifdef HAVE_LIBSODIUM
+ if (sodium_init() == -1) {
+ cerr<<"Unable to initialize sodium crypto library"<<endl;
+ exit(99);
+ }
+#endif
+
+ openssl_seed();
+
+ if (cmds[0] == "test-algorithm") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil test-algorithm algonum"<<endl;
+ return 0;
+ }
+ if (testAlgorithm(pdns_stou(cmds[1])))
+ return 0;
+ return 1;
+ }
+
+ if(cmds[0] == "test-algorithms") {
+ if (testAlgorithms())
+ return 0;
+ return 1;
+ }
+
+ if(cmds[0] == "list-algorithms") {
+ if((cmds.size() == 2 && cmds[1] != "with-backend") || cmds.size() > 2) {
+ cerr<<"Syntax: pdnsutil list-algorithms [with-backend]"<<endl;
+ return 1;
+ }
+
+ cout<<"DNSKEY algorithms supported by this installation of PowerDNS:"<<endl;
+
+ auto algosWithBackend = DNSCryptoKeyEngine::listAllAlgosWithBackend();
+ for (auto const algoWithBackend : algosWithBackend){
+ string algoName = DNSSECKeeper::algorithm2name(algoWithBackend.first);
+ cout<<std::to_string(algoWithBackend.first)<<" - "<<algoName;
+ if (cmds.size() == 2 && cmds[1] == "with-backend")
+ cout<<" using "<<algoWithBackend.second;
+ cout<<endl;
+ }
+ return 0;
+ }
+
+ reportAllTypes();
+
+ if(cmds[0] == "create-bind-db") {
+#ifdef HAVE_SQLITE3
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil create-bind-db FNAME"<<endl;
+ return 0;
+ }
+ try {
+ SSQLite3 db(cmds[1], true); // create=ok
+ vector<string> statements;
+ stringtok(statements, sqlCreate, ";");
+ for(const string& statement : statements) {
+ db.execute(statement);
+ }
+ }
+ catch(SSqlException& se) {
+ throw PDNSException("Error creating database in BIND backend: "+se.txtReason());
+ }
+ return 0;
+#else
+ cerr<<"bind-dnssec-db requires building PowerDNS with SQLite3"<<endl;
+ return 1;
+#endif
+ }
+
+ DNSSECKeeper dk;
+
+ if (cmds[0] == "test-schema") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil test-schema ZONE"<<endl;
+ return 0;
+ }
+ testSchema(dk, DNSName(cmds[1]));
+ return 0;
+ }
+ if(cmds[0] == "rectify-zone") {
+ if(cmds.size() < 2) {
+ cerr << "Syntax: pdnsutil rectify-zone ZONE [ZONE..]"<<endl;
+ return 0;
+ }
+ unsigned int exitCode = 0;
+ for(unsigned int n = 1; n < cmds.size(); ++n)
+ if (!rectifyZone(dk, DNSName(cmds[n])))
+ exitCode = 1;
+ return exitCode;
+ }
+ else if (cmds[0] == "rectify-all-zones") {
+ rectifyAllZones(dk);
+ }
+ else if(cmds[0] == "check-zone") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil check-zone ZONE"<<endl;
+ return 0;
+ }
+ UeberBackend B("default");
+ exit(checkZone(dk, B, DNSName(cmds[1])));
+ }
+ else if(cmds[0] == "bench-db") {
+ dbBench(cmds.size() > 1 ? cmds[1] : "");
+ }
+ else if (cmds[0] == "check-all-zones") {
+ bool exitOnError = ((cmds.size() >= 2 ? cmds[1] : "") == "exit-on-error");
+ exit(checkAllZones(dk, exitOnError));
+ }
+ else if (cmds[0] == "list-all-zones") {
+ if (cmds.size() > 2) {
+ cerr << "Syntax: pdnsutil list-all-zones [master|slave|native]"<<endl;
+ return 0;
+ }
+ if (cmds.size() == 2)
+ return listAllZones(cmds[1]);
+ return listAllZones();
+ }
+ else if (cmds[0] == "test-zone") {
+ cerr << "Did you mean check-zone?"<<endl;
+ return 0;
+ }
+ else if (cmds[0] == "test-all-zones") {
+ cerr << "Did you mean check-all-zones?"<<endl;
+ return 0;
+ }
+#if 0
+ else if(cmds[0] == "signing-server" )
+ {
+ signingServer();
+ }
+ else if(cmds[0] == "signing-slave")
+ {
+ launchSigningService(0);
+ }
+#endif
+ else if(cmds[0] == "test-speed") {
+ if(cmds.size() < 2) {
+ cerr << "Syntax: pdnsutil test-speed numcores [signing-server]"<<endl;
+ return 0;
+ }
+ testSpeed(dk, DNSName(cmds[1]), (cmds.size() > 3) ? cmds[3] : "", pdns_stou(cmds[2]));
+ }
+ else if(cmds[0] == "verify-crypto") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil verify-crypto FILE"<<endl;
+ return 0;
+ }
+ verifyCrypto(cmds[1]);
+ }
+ else if(cmds[0] == "show-zone") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil show-zone ZONE"<<endl;
+ return 0;
+ }
+ if (!showZone(dk, DNSName(cmds[1]))) return 1;
+ }
+ else if(cmds[0] == "disable-dnssec") {
+ if(cmds.size() != 2) {
+ cerr << "Syntax: pdnsutil disable-dnssec ZONE"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ if(!disableDNSSECOnZone(dk, zone)) {
+ cerr << "Cannot disable DNSSEC on " << zone << endl;
+ return 1;
+ }
+ }
+ else if(cmds[0] == "activate-zone-key") {
+ if(cmds.size() != 3) {
+ cerr << "Syntax: pdnsutil activate-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ unsigned int id=atoi(cmds[2].c_str()); // if you make this pdns_stou, the error gets worse
+ if(!id)
+ {
+ cerr<<"Invalid KEY-ID '"<<cmds[2]<<"'"<<endl;
+ return 1;
+ }
+ if (!dk.activateKey(zone, id)) {
+ cerr<<"Activation of key failed"<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0] == "deactivate-zone-key") {
+ if(cmds.size() != 3) {
+ cerr << "Syntax: pdnsutil deactivate-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ unsigned int id=pdns_stou(cmds[2]);
+ if(!id)
+ {
+ cerr<<"Invalid KEY-ID"<<endl;
+ return 1;
+ }
+ if (!dk.deactivateKey(zone, id)) {
+ cerr<<"Deactivation of key failed"<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0] == "add-zone-key") {
+ if(cmds.size() < 3 ) {
+ cerr << "Syntax: pdnsutil add-zone-key ZONE zsk|ksk [bits] [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384]"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+
+ UeberBackend B("default");
+ DomainInfo di;
+
+ if (!B.getDomainInfo(zone, di)){
+ cerr << "No such zone in the database" << endl;
+ return 0;
+ }
+
+ // need to get algorithm, bits & ksk or zsk from commandline
+ bool keyOrZone=false;
+ int tmp_algo=0;
+ int bits=0;
+ int algorithm=13; // ecdsa256
+ bool active=false;
+ for(unsigned int n=2; n < cmds.size(); ++n) {
+ if(pdns_iequals(cmds[n], "zsk"))
+ keyOrZone = false;
+ else if(pdns_iequals(cmds[n], "ksk"))
+ keyOrZone = true;
+ else if((tmp_algo = DNSSECKeeper::shorthand2algorithm(cmds[n]))>0) {
+ algorithm = tmp_algo;
+ } else if(pdns_iequals(cmds[n], "active")) {
+ active=true;
+ } else if(pdns_iequals(cmds[n], "inactive") || pdns_iequals(cmds[n], "passive")) { // 'passive' eventually needs to be removed
+ active=false;
+ } else if(pdns_stou(cmds[n])) {
+ bits = pdns_stou(cmds[n]);
+ } else {
+ cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
+ exit(EXIT_FAILURE);;
+ }
+ }
+ if(!dk.addKey(zone, keyOrZone, algorithm, bits, active)) {
+ cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
+ exit(1);
+ }
+ else {
+ cerr<<"Added a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<", active="<<active<<endl;
+ if(bits)
+ cerr<<"Requested specific key size of "<<bits<<" bits"<<endl;
+ }
+ }
+ else if(cmds[0] == "remove-zone-key") {
+ if(cmds.size() < 3) {
+ cerr<<"Syntax: pdnsutil remove-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ unsigned int id=pdns_stou(cmds[2]);
+ if (!dk.removeKey(zone, id)) {
+ cerr<<"Cannot remove key " << id << " from " << zone <<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0] == "delete-zone") {
+ if(cmds.size() != 2) {
+ cerr<<"Syntax: pdnsutil delete-zone ZONE"<<endl;
+ return 0;
+ }
+ exit(deleteZone(DNSName(cmds[1])));
+ }
+ else if(cmds[0] == "create-zone") {
+ if(cmds.size() != 2 && cmds.size()!=3 ) {
+ cerr<<"Syntax: pdnsutil create-zone ZONE [nsname]"<<endl;
+ return 0;
+ }
+ exit(createZone(DNSName(cmds[1]), cmds.size() > 2 ? DNSName(cmds[2]): DNSName()));
+ }
+ else if(cmds[0] == "create-slave-zone") {
+ if(cmds.size() < 3 ) {
+ cerr<<"Syntax: pdnsutil create-slave-zone ZONE master-ip [master-ip..]"<<endl;
+ return 0;
+ }
+ exit(createSlaveZone(cmds));
+ }
+ else if(cmds[0] == "add-record") {
+ if(cmds.size() < 5) {
+ cerr<<"Syntax: pdnsutil add-record ZONE name type [ttl] \"content\" [\"content\"...]"<<endl;
+ return 0;
+ }
+ exit(addOrReplaceRecord(true, cmds));
+ }
+ else if(cmds[0] == "replace-rrset") {
+ if(cmds.size() < 5) {
+ cerr<<"Syntax: pdnsutil replace-record ZONE name type [ttl] \"content\" [\"content\"...]"<<endl;
+ return 0;
+ }
+ exit(addOrReplaceRecord(false , cmds));
+ }
+ else if(cmds[0] == "delete-rrset") {
+ if(cmds.size() != 4) {
+ cerr<<"Syntax: pdnsutil delete-rrset ZONE name type"<<endl;
+ return 0;
+ }
+ exit(deleteRRSet(cmds[1], cmds[2], cmds[3]));
+ }
+ else if(cmds[0] == "list-zone") {
+ if(cmds.size() != 2) {
+ cerr<<"Syntax: pdnsutil list-zone ZONE"<<endl;
+ return 0;
+ }
+ if(cmds[1]==".")
+ cmds[1].clear();
+
+ exit(listZone(DNSName(cmds[1])));
+ }
+ else if(cmds[0] == "edit-zone") {
+ if(cmds.size() != 2) {
+ cerr<<"Syntax: pdnsutil edit-zone ZONE"<<endl;
+ return 0;
+ }
+ if(cmds[1]==".")
+ cmds[1].clear();
+
+ exit(editZone(dk, DNSName(cmds[1])));
+ }
+ else if(cmds[0] == "clear-zone") {
+ if(cmds.size() != 2) {
+ cerr<<"Syntax: pdnsutil edit-zone ZONE"<<endl;
+ return 0;
+ }
+ if(cmds[1]==".")
+ cmds[1].clear();
+
+ exit(clearZone(dk, DNSName(cmds[1])));
+ }
+ else if(cmds[0] == "list-keys") {
+ if(cmds.size() > 2) {
+ cerr<<"Syntax: pdnsutil list-keys [ZONE]"<<endl;
+ return 0;
+ }
+ string zname = (cmds.size() == 2) ? cmds[1] : "all";
+ exit(listKeys(zname, dk));
+ }
+ else if(cmds[0] == "load-zone") {
+ if(cmds.size() != 3) {
+ cerr<<"Syntax: pdnsutil load-zone ZONE FILENAME"<<endl;
+ return 0;
+ }
+ if(cmds[1]==".")
+ cmds[1].clear();
+
+ exit(loadZone(DNSName(cmds[1]), cmds[2]));
+ }
+ else if(cmds[0] == "secure-zone") {
+ if(cmds.size() < 2) {
+ cerr << "Syntax: pdnsutil secure-zone ZONE"<<endl;
+ return 0;
+ }
+ vector<DNSName> mustRectify;
+ unsigned int zoneErrors=0;
+ for(unsigned int n = 1; n < cmds.size(); ++n) {
+ DNSName zone(cmds[n]);
+ dk.startTransaction(zone, -1);
+ if(secureZone(dk, zone)) {
+ mustRectify.push_back(zone);
+ } else {
+ zoneErrors++;
+ }
+ dk.commitTransaction();
+ }
+
+ for(const auto& zone : mustRectify)
+ rectifyZone(dk, zone);
+
+ if (zoneErrors) {
+ return 1;
+ }
+ return 0;
+ }
+ else if (cmds[0] == "secure-all-zones") {
+ if (cmds.size() >= 2 && !pdns_iequals(cmds[1], "increase-serial")) {
+ cerr << "Syntax: pdnsutil secure-all-zones [increase-serial]"<<endl;
+ return 0;
+ }
+
+ UeberBackend B("default");
+
+ vector<DomainInfo> domainInfo;
+ B.getAllDomains(&domainInfo);
+
+ unsigned int zonesSecured=0, zoneErrors=0;
+ for(DomainInfo di : domainInfo) {
+ if(!dk.isSecuredZone(di.zone)) {
+ cout<<"Securing "<<di.zone<<": ";
+ if (secureZone(dk, di.zone)) {
+ zonesSecured++;
+ if (cmds.size() == 2) {
+ if (!increaseSerial(di.zone, dk))
+ continue;
+ } else
+ continue;
+ }
+ zoneErrors++;
+ }
+ }
+
+ cout<<"Secured: "<<zonesSecured<<" zones. Errors: "<<zoneErrors<<endl;
+
+ if (zoneErrors) {
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="set-kind") {
+ if(cmds.size() != 3) {
+ cerr<<"Syntax: pdnsutil set-kind ZONE KIND"<<endl;
+ }
+ DNSName zone(cmds[1]);
+ auto kind=DomainInfo::stringToKind(cmds[2]);
+ exit(setZoneKind(zone, kind));
+ }
+ else if(cmds[0]=="set-nsec3") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil set-nsec3 ZONE 'params' [narrow]"<<endl;
+ return 0;
+ }
+ string nsec3params = cmds.size() > 2 ? cmds[2] : "1 0 1 ab";
+ bool narrow = cmds.size() > 3 && cmds[3]=="narrow";
+ NSEC3PARAMRecordContent ns3pr(nsec3params);
+
+ DNSName zone(cmds[1]);
+ if (zone.wirelength() > 222) {
+ cerr<<"Cannot enable NSEC3 for " << zone << " as it is too long (" << zone.wirelength() << " bytes, maximum is 222 bytes)"<<endl;
+ return 1;
+ }
+ if(ns3pr.d_algorithm != 1) {
+ cerr<<"NSEC3PARAM algorithm set to '"<<std::to_string(ns3pr.d_algorithm)<<"', but '1' is the only valid value"<<endl;
+ return EXIT_FAILURE;
+ }
+ if (! dk.setNSEC3PARAM(zone, ns3pr, narrow)) {
+ cerr<<"Cannot set NSEC3 param for " << zone << endl;
+ return 1;
+ }
+
+ if (!ns3pr.d_flags)
+ cerr<<"NSEC3 set, ";
+ else
+ cerr<<"NSEC3 (opt-out) set, ";
+
+ if(dk.isSecuredZone(zone))
+ cerr<<"please rectify your zone if your backend needs it"<<endl;
+ else
+ cerr<<"please secure and rectify your zone."<<endl;
+
+ return 0;
+ }
+ else if(cmds[0]=="set-presigned") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil set-presigned ZONE"<<endl;
+ return 0;
+ }
+ if (! dk.setPresigned(DNSName(cmds[1]))) {
+ cerr << "Could not set presigned on for " << cmds[1] << endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="set-publish-cdnskey") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil set-publish-cdnskey ZONE"<<endl;
+ return 0;
+ }
+ if (! dk.setPublishCDNSKEY(DNSName(cmds[1]))) {
+ cerr << "Could not set publishing for CDNSKEY records for "<< cmds[1]<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="set-publish-cds") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil set-publish-cds ZONE [DIGESTALGOS]"<<endl;
+ return 0;
+ }
+
+ // If DIGESTALGOS is unset
+ if(cmds.size() == 2)
+ cmds.push_back("1,2");
+
+ if (! dk.setPublishCDS(DNSName(cmds[1]), cmds[2])) {
+ cerr << "Could not set publishing for CDS records for "<< cmds[1]<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="unset-presigned") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil unset-presigned ZONE"<<endl;
+ return 0;
+ }
+ if (! dk.unsetPresigned(DNSName(cmds[1]))) {
+ cerr << "Could not unset presigned on for " << cmds[1] << endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="unset-publish-cdnskey") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil unset-publish-cdnskey ZONE"<<endl;
+ return 0;
+ }
+ if (! dk.unsetPublishCDNSKEY(DNSName(cmds[1]))) {
+ cerr << "Could not unset publishing for CDNSKEY records for "<< cmds[1]<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="unset-publish-cds") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil unset-publish-cds ZONE"<<endl;
+ return 0;
+ }
+ if (! dk.unsetPublishCDS(DNSName(cmds[1]))) {
+ cerr << "Could not unset publishing for CDS records for "<< cmds[1]<<endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="hash-zone-record") {
+ if(cmds.size() < 3) {
+ cerr<<"Syntax: pdnsutil hash-zone-record ZONE RNAME"<<endl;
+ return 0;
+ }
+ DNSName zone(cmds[1]);
+ DNSName record(cmds[2]);
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+ if(!dk.getNSEC3PARAM(zone, &ns3pr, &narrow)) {
+ cerr<<"The '"<<zone<<"' zone does not use NSEC3"<<endl;
+ return 0;
+ }
+ if(narrow) {
+ cerr<<"The '"<<zone<<"' zone uses narrow NSEC3, but calculating hash anyhow"<<endl;
+ }
+
+ cout<<toBase32Hex(hashQNameWithSalt(ns3pr, record))<<endl;
+ }
+ else if(cmds[0]=="unset-nsec3") {
+ if(cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil unset-nsec3 ZONE"<<endl;
+ return 0;
+ }
+ if ( ! dk.unsetNSEC3PARAM(DNSName(cmds[1]))) {
+ cerr<<"Cannot unset NSEC3 param for " << cmds[1] << endl;
+ return 1;
+ }
+ return 0;
+ }
+ else if(cmds[0]=="export-zone-key") {
+ if(cmds.size() < 3) {
+ cerr<<"Syntax: pdnsutil export-zone-key ZONE KEY-ID"<<endl;
+ return 0;
+ }
+
+ string zone=cmds[1];
+ unsigned int id=pdns_stou(cmds[2]);
+ DNSSECPrivateKey dpk=dk.getKeyById(DNSName(zone), id);
+ cout << dpk.getKey()->convertToISC() <<endl;
+ }
+ else if(cmds[0]=="increase-serial") {
+ if (cmds.size() < 2) {
+ cerr<<"Syntax: pdnsutil increase-serial ZONE"<<endl;
+ return 0;
+ }
+ return increaseSerial(DNSName(cmds[1]), dk);
+ }
+ else if(cmds[0]=="import-zone-key-pem") {
+ if(cmds.size() < 4) {
+ cerr<<"Syntax: pdnsutil import-zone-key-pem ZONE FILE ALGORITHM {ksk|zsk}"<<endl;
+ exit(1);
+ }
+ string zone=cmds[1];
+ string fname=cmds[2];
+ string line;
+ ifstream ifs(fname.c_str());
+ string tmp, interim, raw;
+ while(getline(ifs, line)) {
+ if(line[0]=='-')
+ continue;
+ trim(line);
+ interim += line;
+ }
+ B64Decode(interim, raw);
+ DNSSECPrivateKey dpk;
+ DNSKEYRecordContent drc;
+ shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromPEMString(drc, raw));
+ dpk.setKey(key);
+
+ dpk.d_algorithm = pdns_stou(cmds[3]);
+
+ if(dpk.d_algorithm == 7)
+ dpk.d_algorithm = 5;
+
+ cerr<<(int)dpk.d_algorithm<<endl;
+
+ if(cmds.size() > 4) {
+ if(pdns_iequals(cmds[4], "ZSK"))
+ dpk.d_flags = 256;
+ else if(pdns_iequals(cmds[4], "KSK"))
+ dpk.d_flags = 257;
+ else {
+ cerr<<"Unknown key flag '"<<cmds[4]<<"'"<<endl;
+ exit(1);
+ }
+ }
+ else
+ dpk.d_flags = 257; // ksk
+
+ if(!dk.addKey(DNSName(zone), dpk)) {
+ cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
+ exit(1);
+ }
+
+ }
+ else if(cmds[0]=="import-zone-key") {
+ if(cmds.size() < 3) {
+ cerr<<"Syntax: pdnsutil import-zone-key ZONE FILE [ksk|zsk] [active|inactive]"<<endl;
+ exit(1);
+ }
+ string zone=cmds[1];
+ string fname=cmds[2];
+ DNSSECPrivateKey dpk;
+ DNSKEYRecordContent drc;
+ shared_ptr<DNSCryptoKeyEngine> key(DNSCryptoKeyEngine::makeFromISCFile(drc, fname.c_str()));
+ dpk.setKey(key);
+ dpk.d_algorithm = drc.d_algorithm;
+
+ if(dpk.d_algorithm == 7)
+ dpk.d_algorithm = 5;
+
+ dpk.d_flags = 257;
+ bool active=true;
+
+ for(unsigned int n = 3; n < cmds.size(); ++n) {
+ if(pdns_iequals(cmds[n], "ZSK"))
+ dpk.d_flags = 256;
+ else if(pdns_iequals(cmds[n], "KSK"))
+ dpk.d_flags = 257;
+ else if(pdns_iequals(cmds[n], "active"))
+ active = 1;
+ else if(pdns_iequals(cmds[n], "passive") || pdns_iequals(cmds[n], "inactive")) // passive eventually needs to be removed
+ active = 0;
+ else {
+ cerr<<"Unknown key flag '"<<cmds[n]<<"'"<<endl;
+ exit(1);
+ }
+ }
+ if(!dk.addKey(DNSName(zone), dpk, active)) {
+ cerr<<"Adding key failed, perhaps DNSSEC not enabled in configuration?"<<endl;
+ exit(1);
+ }
+ }
+ else if(cmds[0]=="export-zone-dnskey") {
+ if(cmds.size() < 3) {
+ cerr<<"Syntax: pdnsutil export-zone-dnskey ZONE KEY-ID"<<endl;
+ exit(1);
+ }
+
+ DNSName zone(cmds[1]);
+ unsigned int id=pdns_stou(cmds[2]);
+ DNSSECPrivateKey dpk=dk.getKeyById(zone, id);
+ cout << zone<<" IN DNSKEY "<<dpk.getDNSKEY().getZoneRepresentation() <<endl;
+ if(dpk.d_flags == 257) {
+ cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 1).getZoneRepresentation() << endl;
+ cout << zone << " IN DS "<<makeDSFromDNSKey(zone, dpk.getDNSKEY(), 2).getZoneRepresentation() << endl;
+ }
+ }
+ else if(cmds[0] == "generate-zone-key") {
+ if(cmds.size() < 2 ) {
+ cerr << "Syntax: pdnsutil generate-zone-key zsk|ksk [rsasha1|rsasha256|rsasha512|gost|ecdsa256|ecdsa384] [bits]"<<endl;
+ return 0;
+ }
+ // need to get algorithm, bits & ksk or zsk from commandline
+ bool keyOrZone=false;
+ int tmp_algo=0;
+ int bits=0;
+ int algorithm=13; // ecdsa256
+ for(unsigned int n=1; n < cmds.size(); ++n) {
+ if(pdns_iequals(cmds[n], "zsk"))
+ keyOrZone = false;
+ else if(pdns_iequals(cmds[n], "ksk"))
+ keyOrZone = true;
+ else if((tmp_algo = DNSSECKeeper::shorthand2algorithm(cmds[n]))>0) {
+ algorithm = tmp_algo;
+ } else if(pdns_stou(cmds[n]))
+ bits = pdns_stou(cmds[n]);
+ else {
+ cerr<<"Unknown algorithm, key flag or size '"<<cmds[n]<<"'"<<endl;
+ return 0;
+ }
+ }
+ cerr<<"Generating a " << (keyOrZone ? "KSK" : "ZSK")<<" with algorithm = "<<algorithm<<endl;
+ if(bits)
+ cerr<<"Requesting specific key size of "<<bits<<" bits"<<endl;
+
+ DNSSECPrivateKey dspk;
+ shared_ptr<DNSCryptoKeyEngine> dpk(DNSCryptoKeyEngine::make(algorithm)); // defaults to RSA for now, could be smart w/algorithm! XXX FIXME
+ if(!bits) {
+ if(algorithm <= 10)
+ bits = keyOrZone ? 2048 : 1024;
+ else {
+ if(algorithm == 12 || algorithm == 13 || algorithm == 15) // ECDSA, GOST, ED25519
+ bits = 256;
+ else if(algorithm == 14)
+ bits = 384;
+ else if(algorithm == 16) // ED448
+ bits = 456;
+ else {
+ throw runtime_error("Can't guess key size for algorithm "+std::to_string(algorithm));
+ }
+ }
+ }
+ dpk->create(bits);
+ dspk.setKey(dpk);
+ dspk.d_algorithm = algorithm;
+ dspk.d_flags = keyOrZone ? 257 : 256;
+
+ // print key to stdout
+ cout << "Flags: " << dspk.d_flags << endl <<
+ dspk.getKey()->convertToISC() << endl;
+ } else if (cmds[0]=="generate-tsig-key") {
+ if (cmds.size() < 3) {
+ cerr << "Syntax: " << cmds[0] << " name (hmac-md5|hmac-sha1|hmac-sha224|hmac-sha256|hmac-sha384|hmac-sha512)" << endl;
+ return 0;
+ }
+ DNSName name(cmds[1]);
+ string algo = cmds[2];
+ string key;
+ char tmpkey[64];
+
+ size_t klen = 0;
+ if (algo == "hmac-md5") {
+ klen = 32;
+ } else if (algo == "hmac-sha1") {
+ klen = 32;
+ } else if (algo == "hmac-sha224") {
+ klen = 32;
+ } else if (algo == "hmac-sha256") {
+ klen = 64;
+ } else if (algo == "hmac-sha384") {
+ klen = 64;
+ } else if (algo == "hmac-sha512") {
+ klen = 64;
+ } else {
+ cerr << "Cannot generate key for " << algo << endl;
+ return 1;
+ }
+
+ cerr << "Generating new key with " << klen << " bytes (this can take a while)" << endl;
+ for(size_t i = 0; i < klen; i+=4) {
+ *(unsigned int*)(tmpkey+i) = dns_random(0xffffffff);
+ }
+ key = Base64Encode(std::string(tmpkey, klen));
+
+ UeberBackend B("default");
+ if (B.setTSIGKey(name, DNSName(algo), key)) { // you are feeling bored, put up DNSName(algo) up earlier
+ cout << "Create new TSIG key " << name << " " << algo << " " << key << endl;
+ } else {
+ cerr << "Failure storing new TSIG key " << name << " " << algo << " " << key << endl;
+ return 1;
+ }
+ return 0;
+ } else if (cmds[0]=="import-tsig-key") {
+ if (cmds.size() < 4) {
+ cerr << "Syntax: " << cmds[0] << " name algorithm key" << endl;
+ return 0;
+ }
+ DNSName name(cmds[1]);
+ string algo = cmds[2];
+ string key = cmds[3];
+
+ UeberBackend B("default");
+ if (B.setTSIGKey(name, DNSName(algo), key)) {
+ cout << "Imported TSIG key " << name << " " << algo << endl;
+ } else {
+ cerr << "Failure importing TSIG key " << name << " " << algo << endl;
+ return 1;
+ }
+ return 0;
+ } else if (cmds[0]=="delete-tsig-key") {
+ if (cmds.size() < 2) {
+ cerr << "Syntax: " << cmds[0] << " name" << endl;
+ return 0;
+ }
+ DNSName name(cmds[1]);
+
+ UeberBackend B("default");
+ if (B.deleteTSIGKey(name)) {
+ cout << "Deleted TSIG key " << name << endl;
+ } else {
+ cerr << "Failure deleting TSIG key " << name << endl;
+ return 1;
+ }
+ return 0;
+ } else if (cmds[0]=="list-tsig-keys") {
+ std::vector<struct TSIGKey> keys;
+ UeberBackend B("default");
+ if (B.getTSIGKeys(keys)) {
+ for(const TSIGKey &key : keys) {
+ cout << key.name.toString() << " " << key.algorithm.toString() << " " << key.key << endl;
+ }
+ }
+ return 0;
+ } else if (cmds[0]=="activate-tsig-key") {
+ string metaKey;
+ if (cmds.size() < 4) {
+ cerr << "Syntax: " << cmds[0] << " ZONE NAME {master|slave}" << endl;
+ return 0;
+ }
+ DNSName zname(cmds[1]);
+ string name = cmds[2];
+ if (cmds[3] == "master")
+ metaKey = "TSIG-ALLOW-AXFR";
+ else if (cmds[3] == "slave")
+ metaKey = "AXFR-MASTER-TSIG";
+ else {
+ cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
+ return 1;
+ }
+ UeberBackend B("default");
+ std::vector<std::string> meta;
+ if (!B.getDomainMetadata(zname, metaKey, meta)) {
+ cerr << "Failure enabling TSIG key " << name << " for " << zname << endl;
+ return 1;
+ }
+ bool found = false;
+ for(std::string tmpname : meta) {
+ if (tmpname == name) { found = true; break; }
+ }
+ if (!found) meta.push_back(name);
+ if (B.setDomainMetadata(zname, metaKey, meta)) {
+ cout << "Enabled TSIG key " << name << " for " << zname << endl;
+ } else {
+ cerr << "Failure enabling TSIG key " << name << " for " << zname << endl;
+ return 1;
+ }
+ return 0;
+ } else if (cmds[0]=="deactivate-tsig-key") {
+ string metaKey;
+ if (cmds.size() < 4) {
+ cerr << "Syntax: " << cmds[0] << " ZONE NAME {master|slave}" << endl;
+ return 0;
+ }
+ DNSName zname(cmds[1]);
+ string name = cmds[2];
+ if (cmds[3] == "master")
+ metaKey = "TSIG-ALLOW-AXFR";
+ else if (cmds[3] == "slave")
+ metaKey = "AXFR-MASTER-TSIG";
+ else {
+ cerr << "Invalid parameter '" << cmds[3] << "', expected master or slave" << endl;
+ return 1;
+ }
+
+ UeberBackend B("default");
+ std::vector<std::string> meta;
+ if (!B.getDomainMetadata(zname, metaKey, meta)) {
+ cerr << "Failure disabling TSIG key " << name << " for " << zname << endl;
+ return 1;
+ }
+ std::vector<std::string>::iterator iter = meta.begin();
+ for(;iter != meta.end(); iter++) if (*iter == name) break;
+ if (iter != meta.end()) meta.erase(iter);
+ if (B.setDomainMetadata(zname, metaKey, meta)) {
+ cout << "Disabled TSIG key " << name << " for " << zname << endl;
+ } else {
+ cerr << "Failure disabling TSIG key " << name << " for " << zname << endl;
+ return 1;
+ }
+ return 0;
+ } else if (cmds[0]=="get-meta") {
+ UeberBackend B("default");
+ if (cmds.size() < 2) {
+ cerr << "Syntax: " << cmds[0] << " zone [kind kind ..]" << endl;
+ return 1;
+ }
+ DNSName zone(cmds[1]);
+ vector<string> keys;
+ DomainInfo di;
+
+ if (!B.getDomainInfo(zone, di)) {
+ cerr << "Invalid zone '" << zone << "'" << endl;
+ return 1;
+ }
+
+ if (cmds.size() > 2) {
+ keys.assign(cmds.begin() + 2, cmds.end());
+ std::cout << "Metadata for '" << zone << "'" << endl;
+ for(const string kind : keys) {
+ vector<string> meta;
+ meta.clear();
+ if (B.getDomainMetadata(zone, kind, meta)) {
+ cout << kind << " = " << boost::join(meta, ", ") << endl;
+ }
+ }
+ } else {
+ std::map<std::string, std::vector<std::string> > meta;
+ std::cout << "Metadata for '" << zone << "'" << endl;
+ B.getAllDomainMetadata(zone, meta);
+ for(std::map<std::string, std::vector<std::string> >::const_iterator each_meta = meta.begin(); each_meta != meta.end(); each_meta++) {
+ cout << each_meta->first << " = " << boost::join(each_meta->second, ", ") << endl;
+ }
+ }
+ return 0;
+
+ } else if (cmds[0]=="set-meta") {
+ UeberBackend B("default");
+ if (cmds.size() < 3) {
+ cerr << "Syntax: " << cmds[0] << " zone kind [value value ..]" << endl;
+ return 1;
+ }
+ DNSName zone(cmds[1]);
+ string kind = cmds[2];
+ vector<string> meta(cmds.begin() + 3, cmds.end());
+
+ if (!B.setDomainMetadata(zone, kind, meta)) {
+ cerr << "Unable to set meta for '" << zone << "'" << endl;
+ return 1;
+ } else {
+ cout << "Set '" << zone << "' meta " << kind << " = " << boost::join(meta, ", ") << endl;
+ }
+ } else if (cmds[0]=="hsm") {
+#ifdef HAVE_P11KIT1
+ UeberBackend B("default");
+ if (cmds[1] == "assign") {
+ DNSCryptoKeyEngine::storvector_t storvect;
+ DomainInfo di;
+ std::vector<DNSBackend::KeyData> keys;
+
+ if (cmds.size() < 9) {
+ std::cout << "Usage: pdnsutil hsm assign ZONE ALGORITHM {ksk|zsk} MODULE TOKEN PIN LABEL" << std::endl;
+ return 1;
+ }
+
+ DNSName zone(cmds[2]);
+
+ // verify zone
+ if (!B.getDomainInfo(zone, di)) {
+ cerr << "Unable to assign module to unknown zone '" << zone << "'" << std::endl;
+ return 1;
+ }
+
+ int algorithm = DNSSECKeeper::shorthand2algorithm(cmds[3]);
+ if (algorithm<0) {
+ cerr << "Unable to use unknown algorithm '" << cmds[3] << "'" << std::endl;
+ return 1;
+ }
+
+ int id;
+ bool keyOrZone = (cmds[4] == "ksk" ? true : false);
+ string module = cmds[5];
+ string slot = cmds[6];
+ string pin = cmds[7];
+ string label = cmds[8];
+
+ std::ostringstream iscString;
+ iscString << "Private-key-format: v1.2" << std::endl <<
+ "Algorithm: " << algorithm << std::endl <<
+ "Engine: " << module << std::endl <<
+ "Slot: " << slot << std::endl <<
+ "PIN: " << pin << std::endl <<
+ "Label: " << label << std::endl;
+
+ DNSKEYRecordContent drc;
+ DNSSECPrivateKey dpk;
+ dpk.d_flags = (keyOrZone ? 257 : 256);
+
+ shared_ptr<DNSCryptoKeyEngine> dke(DNSCryptoKeyEngine::makeFromISCString(drc, iscString.str()));
+ if(!dke->checkKey()) {
+ cerr << "Invalid DNS Private Key in engine " << module << " slot " << slot << std::endl;
+ return 1;
+ }
+ dpk.setKey(dke);
+
+ // make sure this key isn't being reused.
+ B.getDomainKeys(zone, 0, keys);
+ id = -1;
+
+ for(DNSBackend::KeyData& kd : keys) {
+ if (kd.content == iscString.str()) {
+ // it's this one, I guess...
+ id = kd.id;
+ break;
+ }
+ }
+
+ if (id > -1) {
+ cerr << "You have already assigned this key with ID=" << id << std::endl;
+ return 1;
+ }
+
+ if (!(id = dk.addKey(zone, dpk))) {
+ cerr << "Unable to assign module slot to zone" << std::endl;
+ return 1;
+ }
+
+ // figure out key id.
+
+ B.getDomainKeys(zone, 0, keys);
+
+ // validate which one got the key...
+ for(DNSBackend::KeyData& kd : keys) {
+ if (kd.content == iscString.str()) {
+ // it's this one, I guess...
+ id = kd.id;
+ break;
+ }
+ }
+
+ cerr << "Module " << module << " slot " << slot << " assigned to " << zone << " with key id " << id << endl;
+
+ return 0;
+ } else if (cmds[1] == "create-key") {
+
+ if (cmds.size() < 4) {
+ cerr << "Usage: pdnsutil hsm create-key ZONE KEY-ID [BITS]" << endl;
+ return 1;
+ }
+ DomainInfo di;
+ DNSName zone(cmds[2]);
+ unsigned int id;
+ int bits = 2048;
+ // verify zone
+ if (!B.getDomainInfo(zone, di)) {
+ cerr << "Unable to create key for unknown zone '" << zone << "'" << std::endl;
+ return 1;
+ }
+
+ id = pdns_stou(cmds[3]);
+ std::vector<DNSBackend::KeyData> keys;
+ if (!B.getDomainKeys(zone, 0, keys)) {
+ cerr << "No keys found for zone " << zone << std::endl;
+ return 1;
+ }
+
+ std::shared_ptr<DNSCryptoKeyEngine> dke = nullptr;
+ // lookup correct key
+ for(DNSBackend::KeyData &kd : keys) {
+ if (kd.id == id) {
+ // found our key.
+ DNSKEYRecordContent dkrc;
+ dke = DNSCryptoKeyEngine::makeFromISCString(dkrc, kd.content);
+ }
+ }
+
+ if (!dke) {
+ cerr << "Could not find key with ID " << id << endl;
+ return 1;
+ }
+ if (cmds.size() > 4) {
+ bits = pdns_stou(cmds[4]);
+ }
+ if (bits < 1) {
+ cerr << "Invalid bit size " << bits << "given, must be positive integer";
+ return 1;
+ }
+ try {
+ dke->create(bits);
+ } catch (PDNSException& e) {
+ cerr << e.reason << endl;
+ return 1;
+ }
+
+ cerr << "Key of size " << bits << " created" << std::endl;
+ return 0;
+ }
+#else
+ cerr<<"PKCS#11 support not enabled"<<endl;
+ return 1;
+#endif
+ } else if (cmds[0] == "b2b-migrate") {
+ if (cmds.size() < 3) {
+ cerr<<"Usage: b2b-migrate OLD NEW"<<endl;
+ return 1;
+ }
+
+ DNSBackend *src,*tgt;
+ src = tgt = NULL;
+
+ for(DNSBackend *b : BackendMakers().all()) {
+ if (b->getPrefix() == cmds[1]) src = b;
+ if (b->getPrefix() == cmds[2]) tgt = b;
+ }
+ if (!src) {
+ cerr<<"Unknown source backend '"<<cmds[1]<<"'"<<endl;
+ return 1;
+ }
+ if (!tgt) {
+ cerr<<"Unknown target backend '"<<cmds[2]<<"'"<<endl;
+ return 1;
+ }
+
+ cout<<"Moving zone(s) from "<<src->getPrefix()<<" to "<<tgt->getPrefix()<<endl;
+
+ vector<DomainInfo> domains;
+
+ tgt->getAllDomains(&domains, true);
+ if (domains.size()>0)
+ throw PDNSException("Target backend has domain(s), please clean it first");
+
+ src->getAllDomains(&domains, true);
+ // iterate zones
+ for(const DomainInfo& di: domains) {
+ size_t nr,nc,nm,nk;
+ DNSResourceRecord rr;
+ cout<<"Processing '"<<di.zone<<"'"<<endl;
+ // create zone
+ if (!tgt->createDomain(di.zone)) throw PDNSException("Failed to create zone");
+ tgt->setKind(di.zone, di.kind);
+ tgt->setAccount(di.zone,di.account);
+ for(const string& master: di.masters) {
+ tgt->setMaster(di.zone, master);
+ }
+ // move records
+ if (!src->list(di.zone, di.id, true)) throw PDNSException("Failed to list records");
+ nr=0;
+ while(src->get(rr)) {
+ if (!tgt->feedRecord(rr)) throw PDNSException("Failed to feed record");
+ nr++;
+ }
+ // move comments
+ nc=0;
+ if (src->listComments(di.id)) {
+ Comment c;
+ while(src->getComment(c)) {
+ tgt->feedComment(c);
+ nc++;
+ }
+ }
+ // move metadata
+ nm=0;
+ std::map<std::string, std::vector<std::string> > meta;
+ if (src->getAllDomainMetadata(di.zone, meta)) {
+ std::map<std::string, std::vector<std::string> >::iterator i;
+ for(i=meta.begin(); i != meta.end(); i++) {
+ if (!tgt->setDomainMetadata(di.zone, i->first, i->second)) throw PDNSException("Failed to feed domain metadata");
+ nm++;
+ }
+ }
+ // move keys
+ nk=0;
+ std::vector<DNSBackend::KeyData> keys;
+ if (src->getDomainKeys(di.zone, 0, keys)) {
+ for(const DNSBackend::KeyData& k: keys) {
+ tgt->addDomainKey(di.zone, k);
+ nk++;
+ }
+ }
+ cout<<"Moved "<<nr<<" record(s), "<<nc<<" comment(s), "<<nm<<" metadata(s) and "<<nk<<" cryptokey(s)"<<endl;
+ }
+
+ int ntk=0;
+ // move tsig keys
+ std::vector<struct TSIGKey> tkeys;
+ if (src->getTSIGKeys(tkeys)) {
+ for(auto& tk: tkeys) {
+ if (!tgt->setTSIGKey(tk.name, tk.algorithm, tk.key)) throw PDNSException("Failed to feed TSIG key");
+ ntk++;
+ }
+ }
+ cout<<"Moved "<<ntk<<" TSIG key(s)"<<endl;
+
+ cout<<"Remember to drop the old backend and run rectify-all-zones"<<endl;
+
+ return 0;
+ } else if (cmds[0] == "backend-cmd") {
+ if (cmds.size() < 3) {
+ cerr<<"Usage: backend-cmd BACKEND CMD [CMD..]"<<endl;
+ return 1;
+ }
+
+ DNSBackend *db;
+ db = NULL;
+
+ for(DNSBackend *b : BackendMakers().all()) {
+ if (b->getPrefix() == cmds[1]) db = b;
+ }
+
+ if (!db) {
+ cerr<<"Unknown backend '"<<cmds[1]<<"'"<<endl;
+ return 1;
+ }
+
+ for(auto i=next(begin(cmds),2); i != end(cmds); ++i) {
+ cerr<<"== "<<*i<<endl;
+ cout<<db->directBackendCmd(*i);
+ }
+
+ return 0;
+ } else {
+ cerr<<"Unknown command '"<<cmds[0] <<"'"<< endl;
+ return 1;
+ }
+ return 0;
+}
+catch(PDNSException& ae) {
+ cerr<<"Error: "<<ae.reason<<endl;
+ return 1;
+}
+catch(std::exception& e) {
+ cerr<<"Error: "<<e.what()<<endl;
+ return 1;
+}
+catch(...)
+{
+ cerr<<"Caught an unknown exception"<<endl;
+ return 1;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/assign/std/vector.hpp> // for 'operator+=()'
+#include <boost/assign/list_of.hpp>
+#include <boost/make_shared.hpp>
+
+#include <boost/format.hpp>
+#include <p11-kit/p11-kit.h>
+
+#include "pdns/dnssecinfra.hh"
+#include "pdns/logger.hh"
+#include "pdns/pdnsexception.hh"
+#include "pdns/sha.hh"
+#include "pdns/lock.hh"
+
+#include "pkcs11signers.hh"
+/* TODO
+
+ - list possible tokens and supported modes
+ - Engine: <name>, Slot: <slot>, PIN: <pin>
+ - ECDSA support (how to test?)
+
+NB! If you do use this, here is a simple way to get softhsm working
+
+create /etc/pkcs11/modules/softhsm.module
+
+put
+
+module: /usr/lib/softhsm/libsofthsm.so
+managed: yes
+
+in it. you need to use softhsm tools to manage this all.
+
+*/
+
+#ifdef HAVE_P11KIT1_V2
+static CK_FUNCTION_LIST** p11_modules;
+#endif
+
+// map for signing algorithms
+static std::map<unsigned int,CK_MECHANISM_TYPE> dnssec2smech = boost::assign::map_list_of
+(5, CKM_SHA1_RSA_PKCS)
+(7, CKM_SHA1_RSA_PKCS)
+(8, CKM_SHA256_RSA_PKCS)
+(10, CKM_SHA512_RSA_PKCS)
+(13, CKM_ECDSA)
+(14, CKM_ECDSA);
+
+// map for hashing algorithms
+static std::map<unsigned int,CK_MECHANISM_TYPE> dnssec2hmech = boost::assign::map_list_of
+(5, CKM_SHA_1)
+(7, CKM_SHA_1)
+(8, CKM_SHA256)
+(10, CKM_SHA512)
+(13, CKM_SHA256)
+(14, CKM_SHA384);
+
+typedef enum { Attribute_Byte, Attribute_Long, Attribute_String } CkaValueType;
+
+// Attribute handling
+class P11KitAttribute {
+private:
+ CK_ATTRIBUTE_TYPE type;
+ CK_BYTE ckByte;
+ CK_ULONG ckLong;
+ std::string ckString;
+ CkaValueType ckType;
+ unsigned char *buffer;
+ CK_ULONG buflen;
+protected:
+ void Init() {
+ buffer = NULL;
+ buflen = 0;
+ };
+public:
+ P11KitAttribute(CK_ATTRIBUTE_TYPE type, const std::string& value) {
+ Init();
+ this->type = type;
+ setString(value);
+ }
+
+ P11KitAttribute(CK_ATTRIBUTE_TYPE type, char value) {
+ Init();
+ this->type = type;
+ setByte(value);
+ }
+
+ P11KitAttribute(CK_ATTRIBUTE_TYPE type, unsigned char value) {
+ Init();
+ this->type = type;
+ setByte(value);
+ }
+
+ P11KitAttribute(CK_ATTRIBUTE_TYPE type, unsigned long value) {
+ Init();
+ this->type = type;
+ setLong(value);
+ }
+
+ CkaValueType valueType() const {
+ return ckType;
+ }
+
+ const std::string &str() const {
+ return ckString;
+ };
+
+ unsigned char byte() const {
+ return ckByte;
+ }
+
+ unsigned long ulong() const {
+ return ckLong;
+ }
+
+ void setString(const std::string& value) {
+ this->ckString = value;
+ this->ckType = Attribute_String;
+ }
+
+ void setByte(char value) {
+ this->ckByte = value;
+ this->ckType = Attribute_Byte;
+ }
+
+ void setByte(unsigned char value) {
+ this->ckByte = value;
+ this->ckType = Attribute_Byte;
+ }
+
+ void setLong(unsigned long value) {
+ this->ckLong = value;
+ this->ckType = Attribute_Long;
+ }
+
+// this bit is used for getting attribute from object
+// we provide a pointer for GetAttributeValue to write to
+ CK_BYTE_PTR allocate(CK_ULONG amount) {
+ buffer = new unsigned char[amount];
+ buflen = amount;
+ return buffer;
+ }
+
+// and here we copy the results back and delete buffer
+ void commit(CK_ULONG amount) {
+ if (buffer) {
+ this->ckString.assign((char*)buffer, amount);
+ delete [] buffer;
+ }
+ buffer = NULL;
+ buflen = 0;
+ }
+
+// this is *writable* attribute (you write into it)
+ void wattr(CK_ATTRIBUTE_PTR attr) {
+ attr->type = type;
+ switch(ckType) {
+ case Attribute_Byte: {
+ attr->pValue = (void*)&ckByte;
+ attr->ulValueLen = 1;
+ break;
+ }
+ case Attribute_Long: {
+ attr->pValue = (void*)&ckLong;
+ attr->ulValueLen = sizeof(CK_ULONG);
+ break;
+ }
+ case Attribute_String: {
+ attr->pValue = buffer;
+ attr->ulValueLen = buflen;
+ }
+ };
+ };
+
+// this is *readable* attribute (you read from it)
+ void rattr(CK_ATTRIBUTE_PTR attr) const {
+ attr->type = type;
+ switch(ckType) {
+ case Attribute_Byte: {
+ attr->pValue = (void*)&ckByte;
+ attr->ulValueLen = 1;
+ break;
+ }
+ case Attribute_Long: {
+ attr->pValue = (void*)&ckLong;
+ attr->ulValueLen = sizeof(CK_ULONG);
+ break;
+ }
+ case Attribute_String: {
+ attr->pValue = (void*)ckString.c_str();
+ attr->ulValueLen = ckString.size();
+ }
+ };
+ };
+};
+
+
+class Pkcs11Slot {
+ private:
+ bool d_logged_in;
+ CK_FUNCTION_LIST* d_functions; // module functions
+ CK_SESSION_HANDLE d_session;
+ CK_SLOT_ID d_slot;
+ CK_RV d_err;
+ pthread_mutex_t d_m;
+
+ void logError(const std::string& operation) const {
+ if (d_err) {
+ std::string msg = boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation % p11_kit_strerror(d_err) % d_err );
+ L<<Logger::Error<< msg << endl;
+ }
+ }
+
+ public:
+ Pkcs11Slot(CK_FUNCTION_LIST* functions, const CK_SLOT_ID& slot) {
+ CK_TOKEN_INFO tokenInfo;
+ d_slot = slot;
+ d_functions = functions;
+ d_err = 0;
+ d_logged_in = false;
+ pthread_mutex_init(&(this->d_m), NULL);
+ Lock l(&d_m);
+
+ if ((d_err = d_functions->C_OpenSession(this->d_slot, CKF_SERIAL_SESSION|CKF_RW_SESSION, 0, 0, &(this->d_session)))) {
+ logError("C_OpenSession");
+ throw PDNSException("Could not open session");
+ }
+ // check if we need to login
+ if ((d_err = d_functions->C_GetTokenInfo(d_slot, &tokenInfo)) == 0) {
+ d_logged_in = !((tokenInfo.flags & CKF_LOGIN_REQUIRED) == CKF_LOGIN_REQUIRED);
+ } else {
+ logError("C_GetTokenInfo");
+ throw PDNSException("Cannot get token info for slot " + std::to_string(slot));
+ }
+ }
+
+ bool Login(const std::string& pin) {
+ if (d_logged_in) return true;
+
+ unsigned char *uPin = new unsigned char[pin.size()];
+ memcpy(uPin, pin.c_str(), pin.size());
+ d_err = d_functions->C_Login(this->d_session, CKU_USER, uPin, pin.size());
+ memset(uPin, 0, pin.size());
+ delete [] uPin;
+ logError("C_Login");
+
+ if (d_err == 0) {
+ d_logged_in = true;
+ }
+
+ return d_logged_in;
+ }
+
+ bool LoggedIn() const { return d_logged_in; }
+
+ CK_SESSION_HANDLE& Session() { return d_session; }
+
+ CK_FUNCTION_LIST* f() { return d_functions; }
+
+ pthread_mutex_t *m() { return &d_m; }
+
+ static std::shared_ptr<Pkcs11Slot> GetSlot(const std::string& module, const string& tokenId);
+ static CK_RV HuntSlot(const string& tokenId, CK_SLOT_ID &slotId, _CK_SLOT_INFO* info, CK_FUNCTION_LIST* functions);
+};
+
+class Pkcs11Token {
+ private:
+ std::shared_ptr<Pkcs11Slot> d_slot;
+
+ CK_OBJECT_HANDLE d_public_key;
+ CK_OBJECT_HANDLE d_private_key;
+ CK_KEY_TYPE d_key_type;
+
+ CK_ULONG d_bits;
+ std::string d_exponent;
+ std::string d_modulus;
+ std::string d_ec_point;
+ std::string d_ecdsa_params;
+
+ std::string d_label;
+ bool d_loaded;
+ CK_RV d_err;
+
+ void logError(const std::string& operation) const {
+ if (d_err) {
+ std::string msg = boost::str( boost::format("PKCS#11 operation %s failed: %s (0x%X)") % operation % p11_kit_strerror(d_err) % d_err );
+ L<<Logger::Error<< msg << endl;
+ }
+ }
+
+ public:
+ Pkcs11Token(const std::shared_ptr<Pkcs11Slot>& slot, const std::string& label);
+ ~Pkcs11Token();
+
+ bool Login(const std::string& pin) {
+ if (pin.empty()) return false; // no empty pin.
+ if (d_slot->Login(pin) == true) {
+ LoadAttributes();
+ }
+
+ return LoggedIn();
+ }
+
+ bool LoggedIn() {
+ if (d_loaded == false && d_slot->LoggedIn() == true) {
+ LoadAttributes();
+ }
+ return d_slot->LoggedIn();
+ }
+
+ void LoadAttributes() {
+ Lock l(d_slot->m());
+ std::vector<P11KitAttribute> attr;
+ std::vector<CK_OBJECT_HANDLE> key;
+ attr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PRIVATE_KEY));
+// attr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
+ attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+ FindObjects2(attr, key, 1);
+ if (key.size() == 0) {
+ L<<Logger::Warning<<"Cannot load PCKS#11 private key "<<d_label<<std::endl;;
+ return;
+ }
+ d_private_key = key[0];
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PUBLIC_KEY));
+// attr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
+ attr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+ FindObjects2(attr, key, 1);
+ if (key.size() == 0) {
+ L<<Logger::Warning<<"Cannot load PCKS#11 public key "<<d_label<<std::endl;
+ return;
+ }
+ d_public_key = key[0];
+
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_KEY_TYPE, 0UL));
+
+ if (GetAttributeValue2(d_public_key, attr)==0) {
+ d_key_type = attr[0].ulong();
+ if (d_key_type == CKK_RSA) {
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_MODULUS, ""));
+ attr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, ""));
+ attr.push_back(P11KitAttribute(CKA_MODULUS_BITS, 0UL));
+
+ if (!GetAttributeValue2(d_public_key, attr)) {
+ d_modulus = attr[0].str();
+ d_exponent = attr[1].str();
+ d_bits = attr[2].ulong();
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
+ } else if (d_key_type == CKK_EC || d_key_type == CKK_ECDSA) {
+ attr.clear();
+ attr.push_back(P11KitAttribute(CKA_ECDSA_PARAMS, ""));
+ attr.push_back(P11KitAttribute(CKA_EC_POINT, ""));
+ if (!GetAttributeValue2(d_public_key, attr)) {
+ d_ecdsa_params = attr[0].str();
+ if (d_ecdsa_params == "\x06\x08\x2a\x86\x48\xce\x3d\x03\x01\x07") d_bits = 256;
+ else if (d_ecdsa_params == "\x06\x05\x2b\x81\x04\x00\x22") d_bits = 384;
+ else throw PDNSException("Unsupported EC key");
+ if (attr[1].str().length() != (d_bits*2/8 + 3)) throw PDNSException("EC Point data invalid");
+ d_ec_point = attr[1].str().substr(3);
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
+ } else {
+ throw PDNSException("Cannot determine type for PCKS#11 public key " + d_label);
+ }
+ } else {
+ throw PDNSException("Cannot load attributes for PCKS#11 public key " + d_label);
+ }
+
+ d_loaded = true;
+ }
+
+ int GenerateKeyPair(CK_MECHANISM_PTR mechanism, std::vector<P11KitAttribute>& pubAttributes, std::vector<P11KitAttribute>& privAttributes, CK_OBJECT_HANDLE_PTR pubKey, CK_OBJECT_HANDLE_PTR privKey) {
+ {
+ Lock l(d_slot->m());
+
+ size_t k;
+ CK_ATTRIBUTE_PTR pubAttr, privAttr;
+ pubAttr = new CK_ATTRIBUTE[pubAttributes.size()];
+ privAttr = new CK_ATTRIBUTE[privAttributes.size()];
+
+ k = 0;
+ for(P11KitAttribute& attribute : pubAttributes) {
+ attribute.rattr(pubAttr+k);
+ k++;
+ }
+
+ k = 0;
+ for(P11KitAttribute& attribute : privAttributes) {
+ attribute.rattr(privAttr+k);
+ k++;
+ }
+
+ d_err = this->d_slot->f()->C_GenerateKeyPair(d_slot->Session(), mechanism, pubAttr, pubAttributes.size(), privAttr, privAttributes.size(), pubKey, privKey);
+ logError("C_GenerateKeyPair");
+ delete [] pubAttr;
+ delete [] privAttr;
+ }
+
+ if (d_err == 0) LoadAttributes();
+
+ return d_err;
+ }
+
+ int Sign(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
+
+ CK_BYTE buffer[1024];
+ CK_ULONG buflen = sizeof buffer; // should be enough for most signatures.
+
+ // perform signature
+ if ((d_err = this->d_slot->f()->C_SignInit(d_slot->Session(), mechanism, d_private_key))) { logError("C_SignInit"); return d_err; }
+ d_err = this->d_slot->f()->C_Sign(d_slot->Session(), (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
+
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
+
+ memset(buffer,0,sizeof buffer);
+ logError("C_Sign");
+ return d_err;
+ }
+
+ int Verify(const std::string& data, const std::string& signature, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
+
+ if ((d_err = this->d_slot->f()->C_VerifyInit(d_slot->Session(), mechanism, d_public_key))) { logError("C_VerifyInit"); return d_err; }
+ d_err = this->d_slot->f()->C_Verify(d_slot->Session(), (unsigned char*)data.c_str(), data.size(), (unsigned char*)signature.c_str(), signature.size());
+ logError("C_Verify");
+ return d_err;
+ }
+
+ int Digest(const std::string& data, std::string& result, CK_MECHANISM_PTR mechanism) {
+ Lock l(d_slot->m());
+
+ CK_BYTE buffer[1024];
+ CK_ULONG buflen = sizeof buffer; // should be enough for most digests
+ if ((d_err = this->d_slot->f()->C_DigestInit(d_slot->Session(), mechanism))) { logError("C_DigestInit"); return d_err; }
+ d_err = this->d_slot->f()->C_Digest(d_slot->Session(), (unsigned char*)data.c_str(), data.size(), buffer, &buflen);
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
+ memset(buffer,0,sizeof buffer);
+ logError("C_Digest");
+ return d_err;
+ }
+
+ int DigestInit(CK_MECHANISM_PTR mechanism) {
+ d_err = d_slot->f()->C_DigestInit(d_slot->Session(), mechanism);
+ logError("C_DigestInit");
+ return d_err;
+ }
+
+ int DigestUpdate(const std::string& data) {
+ d_err = d_slot->f()->C_DigestUpdate(d_slot->Session(), (unsigned char*)data.c_str(), data.size());
+ logError("C_DigestUpdate");
+ return d_err;
+ }
+
+ int DigestKey(std::string& result) {
+ Lock l(d_slot->m());
+ CK_MECHANISM mech;
+ mech.mechanism = CKM_SHA_1;
+
+ DigestInit(&mech);
+
+ if (d_key_type == CKK_RSA) {
+ DigestUpdate(d_modulus);
+ DigestUpdate(d_exponent);
+ } else if (d_key_type == CKK_EC || d_key_type == CKK_ECDSA) {
+ DigestUpdate(d_ec_point);
+ }
+
+ DigestFinal(result);
+
+ return d_err;
+ }
+
+ int DigestFinal(std::string& result) {
+ CK_BYTE buffer[1024] = {0};
+ CK_ULONG buflen = sizeof buffer; // should be enough for most digests
+ d_err = d_slot->f()->C_DigestFinal(d_slot->Session(), buffer, &buflen);
+ if (!d_err) {
+ result.assign((char*)buffer, buflen);
+ }
+ memset(buffer,0,sizeof buffer);
+ logError("C_DigestFinal");
+ return d_err;
+ }
+
+ int FindObjects(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, int maxobjects) {
+ Lock l(d_slot->m());
+ return FindObjects2(attributes, objects, maxobjects);
+ }
+
+ int FindObjects2(const std::vector<P11KitAttribute>& attributes, std::vector<CK_OBJECT_HANDLE>& objects, int maxobjects) {
+ CK_RV rv;
+ size_t k;
+ unsigned long count;
+
+ CK_ATTRIBUTE_PTR attr;
+ CK_OBJECT_HANDLE_PTR handles = new CK_OBJECT_HANDLE[maxobjects];
+ attr = new CK_ATTRIBUTE[attributes.size()];
+
+ k = 0;
+ for(const P11KitAttribute& attribute : attributes) {
+ attribute.rattr(attr+k);
+ k++;
+ }
+
+ // perform search
+ d_err = this->d_slot->f()->C_FindObjectsInit(d_slot->Session(), attr, k);
+
+ if (d_err) {
+ delete [] attr;
+ delete [] handles;
+ logError("C_FindObjectsInit");
+ return d_err;
+ }
+
+ count = maxobjects;
+ rv = d_err = this->d_slot->f()->C_FindObjects(d_slot->Session(), handles, maxobjects, &count);
+ objects.clear();
+
+ if (!rv) {
+ for(k=0;k<count;k++) {
+ objects.push_back(handles[k]);
+ }
+ }
+
+ logError("C_FindObjects");
+
+ delete [] attr;
+ delete [] handles;
+
+ d_err = this->d_slot->f()->C_FindObjectsFinal(d_slot->Session());
+ logError("C_FindObjectsFinal");
+
+ return rv;
+ }
+
+ int GetAttributeValue(const CK_OBJECT_HANDLE& object, std::vector<P11KitAttribute>& attributes)
+ {
+ Lock l(d_slot->m());
+ return GetAttributeValue2(object, attributes);
+ }
+
+ int GetAttributeValue2(const CK_OBJECT_HANDLE& object, std::vector<P11KitAttribute>& attributes)
+ {
+ size_t k;
+ CK_ATTRIBUTE_PTR attr;
+ attr = new CK_ATTRIBUTE[attributes.size()];
+
+ k = 0;
+ for(P11KitAttribute &attribute : attributes) {
+ attribute.wattr(attr+k);
+ k++;
+ }
+
+ // round 1 - get attribute sizes
+ d_err = d_slot->f()->C_GetAttributeValue(d_slot->Session(), object, attr, attributes.size());
+ logError("C_GetAttributeValue");
+ if (d_err) {
+ delete [] attr;
+ return d_err;
+ }
+
+ // then allocate memory
+ for(size_t k=0; k < attributes.size(); k++) {
+ if (attributes[k].valueType() == Attribute_String) {
+ attr[k].pValue = attributes[k].allocate(attr[k].ulValueLen);
+ }
+ }
+
+ // round 2 - get actual values
+ d_err = d_slot->f()->C_GetAttributeValue(d_slot->Session(), object, attr, attributes.size());
+ logError("C_GetAttributeValue");
+
+ // copy values to map and release allocated memory
+ for(size_t k=0; k < attributes.size(); k++) {
+ if (attributes[k].valueType() == Attribute_String) {
+ attributes[k].commit(attr[k].ulValueLen);
+ }
+ }
+
+ delete [] attr;
+
+ return d_err;
+ };
+
+ const std::string& Modulus() {
+ return d_modulus;
+ }
+
+ const std::string& Exponent() {
+ return d_exponent;
+ }
+
+ const std::string& ECPoint() {
+ return d_ec_point;
+ }
+
+ const std::string& ECParameters() {
+ return d_ecdsa_params;
+ }
+
+ CK_KEY_TYPE KeyType() {
+ return d_key_type;
+ }
+
+ CK_ULONG Bits() {
+ return d_bits;
+ }
+
+ static std::shared_ptr<Pkcs11Token> GetToken(const std::string& module, const string& tokenId, const std::string& label);
+};
+
+static std::map<std::string, std::shared_ptr<Pkcs11Slot> > pkcs11_slots;
+static std::map<std::string, std::shared_ptr<Pkcs11Token> > pkcs11_tokens;
+
+CK_RV Pkcs11Slot::HuntSlot(const string& tokenId, CK_SLOT_ID &slotId, _CK_SLOT_INFO* info, CK_FUNCTION_LIST* functions)
+{
+ CK_RV err;
+ unsigned long slots;
+ _CK_TOKEN_INFO tinfo;
+
+ // go thru all slots
+ // this is required by certain tokens, otherwise C_GetSlotInfo will not return a token
+ err = functions->C_GetSlotList(CK_FALSE, NULL_PTR, &slots);
+ if (err) {
+ L<<Logger::Warning<<"C_GetSlotList(CK_FALSE, NULL_PTR, &slots) = " << err << std::endl;
+ return err;
+ }
+
+ // iterate all slots
+ for(slotId=0;slotId<slots;slotId++) {
+ if ((err = functions->C_GetSlotInfo(slotId, info))) {
+ L<<Logger::Warning<<"C_GetSlotList("<<slotId<<", info) = " << err << std::endl;
+ return err;
+ }
+ if ((err = functions->C_GetTokenInfo(slotId, &tinfo))) {
+ L<<Logger::Warning<<"C_GetSlotList("<<slotId<<", &tinfo) = " << err << std::endl;
+ return err;
+ }
+ std::string slotName;
+ slotName.assign(reinterpret_cast<char*>(tinfo.label), 32);
+ // trim it
+ boost::trim(slotName);
+ if (boost::iequals(slotName, tokenId)) {
+ return 0;
+ }
+ }
+
+ // see if we can find it with slotId
+ try {
+ slotId = std::stoi(tokenId);
+ if ((err = functions->C_GetSlotInfo(slotId, info))) {
+ L<<Logger::Warning<<"C_GetSlotList("<<slotId<<", info) = " << err << std::endl;
+ return err;
+ }
+ L<<Logger::Warning<<"Specifying PKCS#11 token by SLOT ID is deprecated and should not be used"<<std::endl;
+ return 0;
+ } catch (...) {
+ return CKR_SLOT_ID_INVALID;
+ }
+ return CKR_SLOT_ID_INVALID;
+}
+
+std::shared_ptr<Pkcs11Slot> Pkcs11Slot::GetSlot(const std::string& module, const string& tokenId) {
+ // see if we can find module
+ std::string sidx = module;
+ sidx.append("|");
+ sidx.append(tokenId);
+ std::map<std::string, std::shared_ptr<Pkcs11Slot> >::iterator slotIter;
+ CK_RV err;
+ CK_FUNCTION_LIST* functions;
+
+ // see if we have slot
+ if ((slotIter = pkcs11_slots.find(sidx)) != pkcs11_slots.end()) {
+ return slotIter->second;
+ }
+
+#ifdef HAVE_P11KIT1_V2
+ functions = p11_kit_module_for_name(p11_modules, module.c_str());
+#else
+ functions = p11_kit_registered_name_to_module(module.c_str());
+#endif
+ if (functions == NULL) throw PDNSException("Cannot find PKCS#11 module " + module);
+ functions->C_Initialize(NULL); // initialize the module in case it hasn't been done yet.
+
+ // try to locate a slot
+ _CK_SLOT_INFO info;
+ CK_SLOT_ID slotId;
+
+ if ((err = Pkcs11Slot::HuntSlot(tokenId, slotId, &info, functions))) {
+ throw PDNSException(std::string("Cannot find PKCS#11 token ") + tokenId + std::string(" on module ") + module + std::string(": ") + boost::str( boost::format("%s (0x%X)") % p11_kit_strerror(err) % err));
+ }
+
+ // store slot
+ pkcs11_slots[sidx] = std::make_shared<Pkcs11Slot>(functions, slotId);
+
+ return pkcs11_slots[sidx];
+}
+
+std::shared_ptr<Pkcs11Token> Pkcs11Token::GetToken(const std::string& module, const string& tokenId, const std::string& label) {
+ // see if we can find module
+ std::string tidx = module;
+ tidx.append("|");
+ tidx.append(tokenId);
+ tidx.append("|");
+ tidx.append(label);
+ std::map<std::string, std::shared_ptr<Pkcs11Token> >::iterator tokenIter;
+ if ((tokenIter = pkcs11_tokens.find(tidx)) != pkcs11_tokens.end()) return tokenIter->second;
+
+ std::shared_ptr<Pkcs11Slot> slot = Pkcs11Slot::GetSlot(module, tokenId);
+ pkcs11_tokens[tidx] = std::make_shared<Pkcs11Token>(slot, label);
+ return pkcs11_tokens[tidx];
+}
+
+Pkcs11Token::Pkcs11Token(const std::shared_ptr<Pkcs11Slot>& slot, const std::string& label) {
+ // open a session
+ this->d_bits = 0;
+ this->d_slot = slot;
+ this->d_label = label;
+ this->d_err = 0;
+ this->d_loaded = false;
+ if (this->d_slot->LoggedIn()) LoadAttributes();
+}
+
+Pkcs11Token::~Pkcs11Token() {
+}
+
+bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin)
+{
+ std::shared_ptr<Pkcs11Slot> slot;
+ slot = Pkcs11Slot::GetSlot(module, tokenId);
+ if (slot->LoggedIn()) return true; // no point failing
+ return slot->Login(pin);
+}
+
+PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(unsigned int algorithm): DNSCryptoKeyEngine(algorithm) {}
+PKCS11DNSCryptoKeyEngine::~PKCS11DNSCryptoKeyEngine() {}
+PKCS11DNSCryptoKeyEngine::PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine& orig) : DNSCryptoKeyEngine(orig.d_algorithm) {}
+
+void PKCS11DNSCryptoKeyEngine::create(unsigned int bits) {
+ std::vector<P11KitAttribute> pubAttr;
+ std::vector<P11KitAttribute> privAttr;
+ CK_MECHANISM mech;
+ CK_OBJECT_HANDLE pubKey, privKey;
+ CK_RV rv;
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ std::string pubExp("\000\001\000\001", 4); // 65537
+
+ pubAttr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PUBLIC_KEY));
+ pubAttr.push_back(P11KitAttribute(CKA_KEY_TYPE, (unsigned long)CKK_RSA));
+ pubAttr.push_back(P11KitAttribute(CKA_TOKEN, (char)CK_TRUE));
+ pubAttr.push_back(P11KitAttribute(CKA_ENCRYPT, (char)CK_TRUE));
+ pubAttr.push_back(P11KitAttribute(CKA_VERIFY, (char)CK_TRUE));
+ pubAttr.push_back(P11KitAttribute(CKA_WRAP, (char)CK_TRUE));
+ pubAttr.push_back(P11KitAttribute(CKA_MODULUS_BITS, (unsigned long)bits));
+ pubAttr.push_back(P11KitAttribute(CKA_PUBLIC_EXPONENT, pubExp));
+ pubAttr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+
+ privAttr.push_back(P11KitAttribute(CKA_CLASS, (unsigned long)CKO_PRIVATE_KEY));
+ privAttr.push_back(P11KitAttribute(CKA_KEY_TYPE, (unsigned long)CKK_RSA));
+ privAttr.push_back(P11KitAttribute(CKA_TOKEN, (char)CK_TRUE));
+ privAttr.push_back(P11KitAttribute(CKA_PRIVATE, (char)CK_TRUE));
+// privAttr.push_back(P11KitAttribute(CKA_SUBJECT, "CN=keygen"));
+ privAttr.push_back(P11KitAttribute(CKA_ID, "\x01\x02\x03\x04")); // this is mandatory if you want to export anything
+ privAttr.push_back(P11KitAttribute(CKA_SENSITIVE, (char)CK_TRUE));
+ privAttr.push_back(P11KitAttribute(CKA_DECRYPT, (char)CK_TRUE));
+ privAttr.push_back(P11KitAttribute(CKA_SIGN, (char)CK_TRUE));
+ privAttr.push_back(P11KitAttribute(CKA_UNWRAP, (char)CK_TRUE));
+ privAttr.push_back(P11KitAttribute(CKA_LABEL, d_label));
+
+ mech.mechanism = CKM_RSA_PKCS_KEY_PAIR_GEN;
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ if ((rv = d_slot->GenerateKeyPair(&mech, pubAttr, privAttr, &pubKey, &privKey))) {
+ throw PDNSException("Keypair generation failed");
+ }
+};
+
+std::string PKCS11DNSCryptoKeyEngine::sign(const std::string& msg) const {
+ std::string result;
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ CK_MECHANISM mech;
+ mech.mechanism = dnssec2smech[d_algorithm];
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+
+ if (mech.mechanism == CKM_ECDSA) {
+ if (d_slot->Sign(this->hash(msg), result, &mech)) throw PDNSException("Could not sign data");
+ } else {
+ if (d_slot->Sign(msg, result, &mech)) throw PDNSException("Could not sign data");
+ }
+ return result;
+};
+
+std::string PKCS11DNSCryptoKeyEngine::hash(const std::string& msg) const {
+ std::string result;
+ CK_MECHANISM mech;
+ mech.mechanism = dnssec2hmech[d_algorithm];
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ if (d_slot->Digest(msg, result, &mech)) {
+ L<<Logger::Error<<"Could not digest using PKCS#11 token - using software workaround"<<endl;
+ // FINE! I'll do this myself, then, shall I?
+ switch(d_algorithm) {
+ case 5: {
+ return pdns_sha1sum(msg);
+ }
+ case 8: {
+ return pdns_sha256sum(msg);
+ }
+ case 10: {
+ return pdns_sha512sum(msg);
+ }
+ case 13: {
+ return pdns_sha256sum(msg);
+ }
+ case 14: {
+ return pdns_sha384sum(msg);
+ }
+ };
+ };
+ return result;
+};
+
+bool PKCS11DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const {
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ CK_MECHANISM mech;
+ mech.mechanism = dnssec2smech[d_algorithm];
+ mech.pParameter = NULL;
+ mech.ulParameterLen = 0;
+ if (mech.mechanism == CKM_ECDSA) {
+ return (d_slot->Verify(this->hash(msg), signature, &mech)==0);
+ } else {
+ return (d_slot->Verify(msg, signature, &mech) == 0);
+ }
+};
+
+std::string PKCS11DNSCryptoKeyEngine::getPubKeyHash() const {
+ // find us a public key
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ std::string result;
+ if (d_slot->DigestKey(result) == 0) return result;
+ throw PDNSException("Could not digest key (maybe it's missing?)");
+};
+
+std::string PKCS11DNSCryptoKeyEngine::getPublicKeyString() const {
+ std::string result("");
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ if (d_slot->KeyType() == CKK_RSA) {
+ if (d_slot->Exponent().length() < 255) {
+ result.assign(1, (char) (unsigned int) d_slot->Exponent().length());
+ } else {
+ result.assign(1, 0);
+ uint16_t len=htons(d_slot->Exponent().length());
+ result.append((char*)&len, 2);
+ }
+ result.append(d_slot->Exponent());
+ result.append(d_slot->Modulus());
+ } else {
+ result.append(d_slot->ECPoint());
+ }
+ return result;
+};
+
+int PKCS11DNSCryptoKeyEngine::getBits() const {
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Not logged in to token");
+
+ return d_slot->Bits();
+};
+
+DNSCryptoKeyEngine::storvector_t PKCS11DNSCryptoKeyEngine::convertToISCVector() const {
+ storvector_t storvect;
+ typedef std::vector<std::pair<std::string, std::string> > outputs_t;
+ outputs_t outputs;
+
+ boost::assign::push_back(storvect)
+ (make_pair("Algorithm", std::to_string(d_algorithm)))
+ (make_pair("Engine", d_module))
+ (make_pair("Slot", d_slot_id))
+ (make_pair("PIN", d_pin))
+ (make_pair("Label", d_label));
+ return storvect;
+};
+
+void PKCS11DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap) {
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ d_module = stormap["engine"];
+ d_slot_id = stormap["slot"];
+ boost::trim(d_slot_id);
+ d_pin = stormap["pin"];
+ d_label = stormap["label"];
+ // validate parameters
+
+ std::shared_ptr<Pkcs11Token> d_slot;
+ d_slot = Pkcs11Token::GetToken(d_module, d_slot_id, d_label);
+ if (d_pin != "" && d_slot->LoggedIn() == false)
+ if (d_slot->Login(d_pin) == false)
+ throw PDNSException("Could not log in to token (PIN wrong?)");
+};
+
+std::shared_ptr<DNSCryptoKeyEngine> PKCS11DNSCryptoKeyEngine::maker(unsigned int algorithm)
+{
+ return std::make_shared<PKCS11DNSCryptoKeyEngine>(algorithm);
+}
+
+// this is called during program startup
+namespace {
+ static struct LoaderStruct
+ {
+ LoaderStruct()
+ {
+#ifdef HAVE_P11KIT1_V2
+ p11_modules = p11_kit_modules_load_and_initialize(0);
+#else
+ p11_kit_initialize_registered();
+#endif
+ };
+ ~LoaderStruct() {
+#ifdef HAVE_P11KIT1_V2
+ p11_kit_modules_release(p11_modules);
+#else
+ p11_kit_finalize_registered();
+#endif
+ };
+ } loaderPkcs11;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_PKCS11SIGNERS_HH
+#define PDNS_PKCS11SIGNERS_HH
+
+class PKCS11DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+ protected:
+ std::string d_module;
+ std::string d_slot_id;
+ std::string d_pin;
+ std::string d_label;
+
+ public:
+ PKCS11DNSCryptoKeyEngine(unsigned int algorithm);
+ ~PKCS11DNSCryptoKeyEngine();
+
+ bool operator<(const PKCS11DNSCryptoKeyEngine& rhs) const
+ {
+ return false;
+ }
+ PKCS11DNSCryptoKeyEngine(const PKCS11DNSCryptoKeyEngine& orig);
+
+ string getName() const override { return "P11 Kit PKCS#11"; };
+
+ void create(unsigned int bits) override;
+
+ storvector_t convertToISCVector() const override;
+
+ std::string sign(const std::string& msg) const override;
+
+ std::string hash(const std::string& msg) const override;
+
+ bool verify(const std::string& msg, const std::string& signature) const override;
+
+ std::string getPubKeyHash() const override;
+
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+
+ void fromISCMap(DNSKEYRecordContent& drc, stormap_t& stormap) override;
+
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override { throw "Unimplemented"; };
+ void fromPublicKeyString(const std::string& content) override { throw "Unimplemented"; };
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm);
+};
+
+bool PKCS11ModuleSlotLogin(const std::string& module, const string& tokenId, const std::string& pin);
+
+#endif /* PDNS_PKCS11SIGNERS_HH */
--- /dev/null
+
+#include "protobuf.hh"
+#include "dnsparser.hh"
+#include "gettime.hh"
+
+DNSProtoBufMessage::DNSProtoBufMessage(DNSProtoBufMessageType type)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_type(type == DNSProtoBufMessage::DNSProtoBufMessageType::Query ? PBDNSMessage_Type_DNSQueryType : PBDNSMessage_Type_DNSResponseType);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass)
+{
+#ifdef HAVE_PROTOBUF
+ PBDNSMessage_DNSQuestion* question = d_message.mutable_question();
+ if (question) {
+ question->set_qname(qname.toString());
+ question->set_qtype(qtype);
+ question->set_qclass(qclass);
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setBytes(size_t bytes)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_inbytes(bytes);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setResponseCode(uint8_t rcode)
+{
+#ifdef HAVE_PROTOBUF
+ PBDNSMessage_DNSResponse* response = d_message.mutable_response();
+ if (response) {
+ response->set_rcode(rcode);
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setTime(time_t sec, uint32_t usec)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_timesec(sec);
+ d_message.set_timeusec(usec);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setQueryTime(time_t sec, uint32_t usec)
+{
+#ifdef HAVE_PROTOBUF
+ PBDNSMessage_DNSResponse* response = d_message.mutable_response();
+ if (response) {
+ response->set_querytimesec(sec);
+ response->set_querytimeusec(usec);
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setEDNSSubnet(const Netmask& subnet, uint8_t mask)
+{
+#ifdef HAVE_PROTOBUF
+ if (!subnet.empty()) {
+ ComboAddress ca(subnet.getNetwork());
+ ca.truncate(mask);
+ if (ca.sin4.sin_family == AF_INET) {
+ d_message.set_originalrequestorsubnet(&ca.sin4.sin_addr.s_addr, sizeof(ca.sin4.sin_addr.s_addr));
+ }
+ else if (ca.sin4.sin_family == AF_INET6) {
+ d_message.set_originalrequestorsubnet(&ca.sin6.sin6_addr.s6_addr, sizeof(ca.sin6.sin6_addr.s6_addr));
+ }
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::addRRsFromPacket(const char* packet, const size_t len)
+{
+#ifdef HAVE_PROTOBUF
+ if (len < sizeof(struct dnsheader))
+ return;
+
+ const struct dnsheader* dh = (const struct dnsheader*) packet;
+
+ if (ntohs(dh->ancount) == 0)
+ return;
+
+ if (ntohs(dh->qdcount) == 0)
+ return;
+
+ PBDNSMessage_DNSResponse* response = d_message.mutable_response();
+ if (!response)
+ return;
+
+ vector<uint8_t> content(len - sizeof(dnsheader));
+ copy(packet + sizeof(dnsheader), packet + len, content.begin());
+ PacketReader pr(content);
+
+ size_t idx = 0;
+ DNSName rrname;
+ uint16_t qdcount = ntohs(dh->qdcount);
+ uint16_t ancount = ntohs(dh->ancount);
+ uint16_t rrtype;
+ uint16_t rrclass;
+ string blob;
+ struct dnsrecordheader ah;
+
+ rrname = pr.getName();
+ rrtype = pr.get16BitInt();
+ rrclass = pr.get16BitInt();
+
+ /* consume remaining qd if any */
+ if (qdcount > 1) {
+ for(idx = 1; idx < qdcount; idx++) {
+ rrname = pr.getName();
+ rrtype = pr.get16BitInt();
+ rrclass = pr.get16BitInt();
+ (void) rrtype;
+ (void) rrclass;
+ }
+ }
+
+ /* parse AN */
+ for (idx = 0; idx < ancount; idx++) {
+ rrname = pr.getName();
+ pr.getDnsrecordheader(ah);
+
+ pr.xfrBlob(blob);
+
+ if (ah.d_type == QType::A || ah.d_type == QType::AAAA) {
+ PBDNSMessage_DNSResponse_DNSRR* rr = response->add_rrs();
+ if (rr) {
+ rr->set_name(rrname.toString());
+ rr->set_type(ah.d_type);
+ rr->set_class_(ah.d_class);
+ rr->set_ttl(ah.d_ttl);
+ rr->set_rdata(blob.c_str(), blob.length());
+ }
+ }
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setRequestor(const std::string& requestor)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_from(requestor);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setRequestor(const ComboAddress& requestor)
+{
+#ifdef HAVE_PROTOBUF
+ if (requestor.sin4.sin_family == AF_INET) {
+ d_message.set_from(&requestor.sin4.sin_addr.s_addr, sizeof(requestor.sin4.sin_addr.s_addr));
+ }
+ else if (requestor.sin4.sin_family == AF_INET6) {
+ d_message.set_from(&requestor.sin6.sin6_addr.s6_addr, sizeof(requestor.sin6.sin6_addr.s6_addr));
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setResponder(const std::string& responder)
+{
+#ifdef HAVE_PROTOBUF
+ d_message.set_from(responder);
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::setResponder(const ComboAddress& responder)
+{
+#ifdef HAVE_PROTOBUF
+ if (responder.sin4.sin_family == AF_INET) {
+ d_message.set_from(&responder.sin4.sin_addr.s_addr, sizeof(responder.sin4.sin_addr.s_addr));
+ }
+ else if (responder.sin4.sin_family == AF_INET6) {
+ d_message.set_from(&responder.sin6.sin6_addr.s6_addr, sizeof(responder.sin6.sin6_addr.s6_addr));
+ }
+#endif /* HAVE_PROTOBUF */
+}
+
+void DNSProtoBufMessage::serialize(std::string& data) const
+{
+#ifdef HAVE_PROTOBUF
+ d_message.SerializeToString(&data);
+#endif /* HAVE_PROTOBUF */
+}
+
+std::string DNSProtoBufMessage::toDebugString() const
+{
+#ifdef HAVE_PROTOBUF
+ return d_message.DebugString();
+#else
+ return std::string();
+#endif /* HAVE_PROTOBUF */
+}
+
+#ifdef HAVE_PROTOBUF
+
+void DNSProtoBufMessage::setUUID(const boost::uuids::uuid& uuid)
+{
+ std::string* messageId = d_message.mutable_messageid();
+ messageId->resize(uuid.size());
+ std::copy(uuid.begin(), uuid.end(), messageId->begin());
+}
+
+void DNSProtoBufMessage::update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id)
+{
+ struct timespec ts;
+ gettime(&ts, true);
+ setTime(ts.tv_sec, ts.tv_nsec / 1000);
+
+ setUUID(uuid);
+ d_message.set_id(ntohs(id));
+
+ d_message.set_socketfamily((requestor && requestor->sin4.sin_family == AF_INET) ? PBDNSMessage_SocketFamily_INET : PBDNSMessage_SocketFamily_INET6);
+ d_message.set_socketprotocol(isTCP ? PBDNSMessage_SocketProtocol_TCP : PBDNSMessage_SocketProtocol_UDP);
+
+ if (responder) {
+ setResponder(*responder);
+ }
+ if (requestor) {
+ setRequestor(*requestor);
+ }
+}
+
+
+DNSProtoBufMessage::DNSProtoBufMessage(DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* to, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes)
+{
+ update(uuid, requestor, to, isTCP, qid);
+
+ d_message.set_type(type == DNSProtoBufMessage::DNSProtoBufMessageType::Query ? PBDNSMessage_Type_DNSQueryType : PBDNSMessage_Type_DNSResponseType);
+
+ setBytes(bytes);
+ setQuestion(domain, qtype, qclass);
+}
+
+#endif /* HAVE_PROTOBUF */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include <cstddef>
+#include <string>
+
+#include "config.h"
+
+#include "dnsname.hh"
+#include "iputils.hh"
+
+#ifdef HAVE_PROTOBUF
+#include <boost/uuid/uuid.hpp>
+#include <boost/uuid/uuid_generators.hpp>
+#include "dnsmessage.pb.h"
+#endif /* HAVE_PROTOBUF */
+
+class DNSProtoBufMessage
+{
+public:
+ enum DNSProtoBufMessageType {
+ Query,
+ Response
+ };
+
+ DNSProtoBufMessage()
+ {
+ }
+
+ DNSProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type);
+
+ ~DNSProtoBufMessage()
+ {
+ }
+
+ void setQuestion(const DNSName& qname, uint16_t qtype, uint16_t qclass);
+ void setEDNSSubnet(const Netmask& subnet, uint8_t mask=128);
+ void setBytes(size_t bytes);
+ void setTime(time_t sec, uint32_t usec);
+ void setQueryTime(time_t sec, uint32_t usec);
+ void setResponseCode(uint8_t rcode);
+ void addRRsFromPacket(const char* packet, const size_t len);
+ void serialize(std::string& data) const;
+ void setRequestor(const std::string& requestor);
+ void setRequestor(const ComboAddress& requestor);
+ void setResponder(const std::string& responder);
+ void setResponder(const ComboAddress& responder);
+ std::string toDebugString() const;
+
+#ifdef HAVE_PROTOBUF
+ DNSProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes);
+ void update(const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, bool isTCP, uint16_t id);
+ void setUUID(const boost::uuids::uuid& uuid);
+
+protected:
+ PBDNSMessage d_message;
+#endif /* HAVE_PROTOBUF */
+};
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2007 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#include "dns.hh"
+#include <iostream>
+#include <string>
+#include <vector>
+#include <utility>
+#include <sstream>
+#include "qtype.hh"
+#include "misc.hh"
+
+static_assert(sizeof(QType) == 2, "QType is not 2 bytes in size, something is wrong!");
+
+vector<QType::namenum> QType::names;
+// XXX FIXME we need to do something with initializer order here!
+QType::init QType::initializer;
+
+QType::QType()
+{
+ code = 0;
+}
+
+bool QType::isSupportedType() {
+ for(vector<namenum>::iterator pos=names.begin();pos<names.end();++pos)
+ if(pos->second==code)
+ return true;
+ return false;
+}
+
+bool QType::isMetadataType() {
+ if (code == QType::AXFR ||
+ code == QType::MAILA ||
+ code == QType::MAILB ||
+ code == QType::TSIG ||
+ code == QType::IXFR)
+ return true;
+
+ return false;
+}
+
+uint16_t QType::getCode() const
+{
+ return code;
+}
+
+const string QType::getName() const
+{
+ vector<namenum>::iterator pos;
+ for(pos=names.begin();pos<names.end();++pos)
+ if(pos->second==code)
+ return pos->first;
+
+ return "TYPE"+itoa(code);
+}
+
+QType &QType::operator=(uint16_t n)
+{
+ code=n;
+ return *this;
+}
+
+int QType::chartocode(const char *p)
+{
+ string P = toUpper(p);
+ vector<namenum>::iterator pos;
+
+ for(pos=names.begin(); pos < names.end(); ++pos)
+ if(pos->first == P)
+ return pos->second;
+
+ if(*p=='#') {
+ return atoi(p+1);
+ }
+
+ if(boost::starts_with(P, "TYPE"))
+ return atoi(p+4);
+
+ return 0;
+}
+
+QType &QType::operator=(const char *p)
+{
+ code=chartocode(p);
+ return *this;
+}
+
+QType &QType::operator=(const string &s)
+{
+ code=chartocode(s.c_str());
+ return *this;
+}
+
+
+QType::QType(uint16_t n): QType()
+{
+ code=n;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef QTYPE_HH
+#define QTYPE_HH
+// $Id$
+#include <string>
+#include <vector>
+#include "namespaces.hh"
+
+/** The QType class is meant to deal easily with the different kind of resource types, like 'A', 'NS',
+ * 'CNAME' etcetera. These types have both a name and a number. This class can seamlessly move between
+ * them. Use it like this:
+
+\code
+ QType t;
+ t="CNAME";
+ cout<<t.getCode()<<endl; // prints '5'
+ t=6;
+ cout<<t.getName()<<endl; // prints 'SOA'
+\endcode
+
+*/
+
+
+
+class QType
+{
+public:
+ QType(); //!< Naked constructor
+ explicit QType(uint16_t); //!< convert from an integer to a QType
+ QType(const QType& orig) : code(orig.code)
+ {
+ }
+ QType &operator=(uint16_t); //!< Assigns integers to us
+ QType &operator=(const char *); //!< Assings strings to us
+ QType &operator=(const string &); //!< Assings strings to us
+ QType &operator=(const QType&rhs) //!< Assings strings to us
+ {
+ code=rhs.code;
+ return *this;
+ }
+
+ bool operator<(const QType& rhs) const
+ {
+ return code < rhs.code;
+ }
+
+ template<class Archive>
+ void serialize(Archive &ar, const unsigned int version)
+ {
+ ar & code;
+ }
+
+ const string getName() const; //!< Get a string representation of this type
+ uint16_t getCode() const; //!< Get the integer representation of this type
+ bool isSupportedType();
+ bool isMetadataType();
+
+ static int chartocode(const char *p); //!< convert a character string to a code
+ enum typeenum : uint16_t {
+ A=1,
+ NS=2,
+ CNAME=5,
+ SOA=6,
+ MR=9,
+ WKS=11,
+ PTR=12,
+ HINFO=13,
+ MINFO=14,
+ MX=15,
+ TXT=16,
+ RP=17,
+ AFSDB=18,
+ SIG=24,
+ KEY=25,
+ AAAA=28,
+ LOC=29,
+ SRV=33,
+ NAPTR=35,
+ KX=36,
+ CERT=37,
+ A6=38,
+ DNAME=39,
+ OPT=41,
+ DS=43,
+ SSHFP=44,
+ IPSECKEY=45,
+ RRSIG=46,
+ NSEC=47,
+ DNSKEY=48,
+ DHCID=49,
+ NSEC3=50,
+ NSEC3PARAM=51,
+ TLSA=52,
+ RKEY=57,
+ CDS=59,
+ CDNSKEY=60,
+ OPENPGPKEY=61,
+ SPF=99,
+ EUI48=108,
+ EUI64=109,
+ TKEY=249,
+ TSIG=250,
+ IXFR=251,
+ AXFR=252,
+ MAILB=253,
+ MAILA=254,
+ ANY=255,
+ URI=256,
+ CAA=257,
+ DLV=32769,
+ ADDR=65400,
+ ALIAS=65401
+ };
+
+ typedef pair<string,uint16_t> namenum;
+ static vector<namenum> names;
+
+ inline bool operator==(const QType &comp) const {
+ return(comp.code==code);
+ }
+
+ inline bool operator!=(const QType &comp) const {
+ return(comp.code!=code);
+ }
+
+ inline bool operator==(QType::typeenum comp) const {
+ return(comp==code);
+ }
+
+ inline bool operator!=(QType::typeenum comp) const {
+ return(comp!=code);
+ }
+
+ inline bool operator==(uint16_t comp) const {
+ return(comp==code);
+ }
+
+ inline bool operator!=(uint16_t comp) const {
+ return(comp!=code);
+ }
+
+private:
+ static class init {
+ public:
+ void qtype_insert(const char* a, uint16_t num)
+ {
+ names.push_back(make_pair(string(a), num));
+ }
+
+ init()
+ {
+ qtype_insert("A", 1);
+ qtype_insert("NS", 2);
+ qtype_insert("CNAME", 5);
+ qtype_insert("SOA", 6);
+ qtype_insert("MR", 9);
+ qtype_insert("PTR", 12);
+ qtype_insert("HINFO", 13);
+ qtype_insert("MINFO", 14);
+ qtype_insert("MX", 15);
+ qtype_insert("TXT", 16);
+ qtype_insert("RP", 17);
+ qtype_insert("AFSDB", 18);
+ qtype_insert("SIG", 24);
+ qtype_insert("KEY", 25);
+ qtype_insert("AAAA", 28);
+ qtype_insert("LOC", 29);
+ qtype_insert("SRV", 33);
+ qtype_insert("NAPTR", 35);
+ qtype_insert("KX", 36);
+ qtype_insert("CERT", 37);
+ qtype_insert("A6", 38);
+ qtype_insert("DNAME", 39);
+ qtype_insert("OPT", 41);
+ qtype_insert("DS", 43);
+ qtype_insert("SSHFP", 44);
+ qtype_insert("IPSECKEY", 45);
+ qtype_insert("RRSIG", 46);
+ qtype_insert("NSEC", 47);
+ qtype_insert("DNSKEY", 48);
+ qtype_insert("DHCID", 49);
+ qtype_insert("NSEC3", 50);
+ qtype_insert("NSEC3PARAM", 51);
+ qtype_insert("TLSA", 52);
+ qtype_insert("RKEY", 57);
+ qtype_insert("CDS", 59);
+ qtype_insert("CDNSKEY", 60);
+ qtype_insert("OPENPGPKEY", 61);
+ qtype_insert("SPF", 99);
+ qtype_insert("EUI48", 108);
+ qtype_insert("EUI64", 109);
+ qtype_insert("TKEY", 249);
+// qtype_insert("TSIG", 250);
+ qtype_insert("IXFR", 251);
+ qtype_insert("AXFR", 252);
+ qtype_insert("MAILB", 253);
+ qtype_insert("MAILA", 254);
+ qtype_insert("ANY", 255);
+ qtype_insert("URI", 256);
+ qtype_insert("CAA", 257);
+ qtype_insert("DLV", 32769);
+ qtype_insert("ADDR", 65400);
+ qtype_insert("ALIAS", 65401);
+ }
+ } initializer;
+
+ uint16_t code;
+};
+
+struct QClass
+{
+ enum QClassEnum {IN=1, CHAOS=3, NONE=254, ANY=255};
+};
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "misc.hh"
+#include "logger.hh"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include "dns_random.hh"
+
+void seedRandom(const string& source)
+{
+ L<<Logger::Warning<<"Reading random entropy from '"<<source<<"'"<<endl;
+
+ int fd=open(source.c_str(), O_RDONLY);
+ if(fd < 0) {
+ L<<Logger::Error<<"Unable to open source of random '"<<source<<"': "<<stringerror()<<endl;
+ exit(EXIT_FAILURE);
+ }
+ char seed[16];
+ int ret;
+ int pos=0;
+ while(pos!=sizeof(seed)) {
+ ret = read(fd, seed+pos, sizeof(seed)-pos);
+ if(ret < 0) {
+ L<<Logger::Error<<"Unable to read random seed from "<<source<<": "<<stringerror()<<endl;
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+ if(!ret) {
+ L<<Logger::Error<<"Unable to read random seed from "<<source<<": end of file"<<endl;
+ close(fd);
+ exit(EXIT_FAILURE);
+ }
+ pos+=ret;
+ }
+ close(fd);
+ dns_random_init(seed);
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2005 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "rcpgenerator.hh"
+#include "dnsparser.hh"
+#include "misc.hh"
+#include "utility.hh"
+#include <boost/algorithm/string.hpp>
+#include <iostream>
+#include "base32.hh"
+#include "base64.hh"
+#include "namespaces.hh"
+
+RecordTextReader::RecordTextReader(const string& str, const string& zone) : d_string(str), d_zone(zone), d_pos(0), d_end(str.size())
+{
+}
+
+void RecordTextReader::xfr48BitInt(uint64_t &val)
+{
+ xfr64BitInt(val);
+ if (val > 281474976710655LL)
+ throw RecordTextException("Overflow reading 48 bit integer from record content"); // fixme improve
+}
+
+void RecordTextReader::xfr64BitInt(uint64_t &val)
+{
+ skipSpaces();
+
+ if(!isdigit(d_string.at(d_pos)))
+ throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'");
+
+ size_t pos;
+ val=std::stoull(d_string.substr(d_pos), &pos);
+
+ d_pos += pos;
+}
+
+
+void RecordTextReader::xfr32BitInt(uint32_t &val)
+{
+ skipSpaces();
+
+ if(!isdigit(d_string.at(d_pos)))
+ throw RecordTextException("expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'");
+
+ size_t pos;
+ val=pdns_stou(d_string.substr(d_pos), &pos);
+
+ d_pos += pos;
+}
+
+void RecordTextReader::xfrTime(uint32_t &val)
+{
+ struct tm tm;
+ memset(&tm, 0, sizeof(tm));
+
+ uint64_t itmp;
+ xfr64BitInt(itmp);
+
+ ostringstream tmp;
+
+ tmp<<itmp;
+
+ sscanf(tmp.str().c_str(), "%04d%02d%02d" "%02d%02d%02d",
+ &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+ &tm.tm_hour, &tm.tm_min, &tm.tm_sec);
+
+ tm.tm_year-=1900;
+ tm.tm_mon-=1;
+ val=(uint32_t)Utility::timegm(&tm);
+}
+
+void RecordTextReader::xfrIP(uint32_t &val)
+{
+ skipSpaces();
+
+ if(!isdigit(d_string.at(d_pos)))
+ throw RecordTextException("while parsing IP address, expected digits at position "+std::to_string(d_pos)+" in '"+d_string+"'");
+
+ uint32_t octet=0;
+ val=0;
+ char count=0;
+
+ for(;;) {
+ if(d_string.at(d_pos)=='.') {
+ val<<=8;
+ val+=octet;
+ octet=0;
+ count++;
+ if(count > 3)
+ break;
+ }
+ else if(isdigit(d_string.at(d_pos))) {
+ octet*=10;
+ octet+=d_string.at(d_pos) - '0';
+ if(octet > 255)
+ throw RecordTextException("unable to parse IP address");
+ }
+ else if(dns_isspace(d_string.at(d_pos)))
+ break;
+ else {
+ throw RecordTextException(string("unable to parse IP address, strange character: ")+d_string.at(d_pos));
+ }
+ d_pos++;
+ if(d_pos == d_string.length())
+ break;
+ }
+ if(count<=3) {
+ val<<=8;
+ val+=octet;
+ }
+ val=ntohl(val);
+}
+
+
+void RecordTextReader::xfrIP6(std::string &val)
+{
+ struct in6_addr tmpbuf;
+
+ skipSpaces();
+
+ size_t len;
+ // lookup end of value - think of ::ffff encoding too, has dots in it!
+ for(len=0;
+ d_pos+len < d_string.length() && (isxdigit(d_string.at(d_pos+len)) || d_string.at(d_pos+len) == ':' || d_string.at(d_pos+len)=='.');
+ len++);
+
+ if(!len)
+ throw RecordTextException("while parsing IPv6 address, expected xdigits at position "+std::to_string(d_pos)+" in '"+d_string+"'");
+
+ // end of value is here, try parse as IPv6
+ string address=d_string.substr(d_pos, len);
+
+ if (inet_pton(AF_INET6, address.c_str(), &tmpbuf) != 1) {
+ throw RecordTextException("while parsing IPv6 address: '" + address + "' is invalid");
+ }
+
+ val = std::string((char*)tmpbuf.s6_addr, 16);
+
+ d_pos += len;
+}
+
+bool RecordTextReader::eof()
+{
+ return d_pos==d_end;
+}
+
+void RecordTextReader::xfr16BitInt(uint16_t &val)
+{
+ uint32_t tmp;
+ xfr32BitInt(tmp);
+ val=tmp;
+ if(val!=tmp)
+ throw RecordTextException("Overflow reading 16 bit integer from record content"); // fixme improve
+}
+
+void RecordTextReader::xfr8BitInt(uint8_t &val)
+{
+ uint32_t tmp;
+ xfr32BitInt(tmp);
+ val=tmp;
+ if(val!=tmp)
+ throw RecordTextException("Overflow reading 8 bit integer from record content"); // fixme improve
+}
+
+// this code should leave all the escapes around
+void RecordTextReader::xfrName(DNSName& val, bool, bool)
+{
+ skipSpaces();
+ string sval;
+ sval.reserve(d_end - d_pos);
+
+ const char* strptr=d_string.c_str();
+ string::size_type begin_pos = d_pos;
+ while(d_pos < d_end) {
+ if(strptr[d_pos]!='\r' && dns_isspace(strptr[d_pos]))
+ break;
+
+ d_pos++;
+ }
+ sval.append(strptr+begin_pos, strptr+d_pos);
+
+ if(sval.empty())
+ sval=d_zone;
+ else if(!d_zone.empty()) {
+ char last=sval[sval.size()-1];
+
+ if(last =='.')
+ sval.resize(sval.size()-1);
+ else if(last != '.' && !isdigit(last)) // don't add zone to IP address
+ sval+="."+d_zone;
+ }
+ val = DNSName(sval);
+}
+
+static bool isbase64(char c, bool acceptspace)
+{
+ if(dns_isspace(c))
+ return acceptspace;
+ if(c >= '0' && c <= '9')
+ return true;
+ if(c >= 'a' && c <= 'z')
+ return true;
+ if(c >= 'A' && c <= 'Z')
+ return true;
+ if(c=='+' || c=='/' || c=='=')
+ return true;
+ return false;
+}
+
+void RecordTextReader::xfrBlobNoSpaces(string& val, int len) {
+ skipSpaces();
+ int pos=(int)d_pos;
+ const char* strptr=d_string.c_str();
+ while(d_pos < d_end && isbase64(strptr[d_pos], false))
+ d_pos++;
+
+ string tmp;
+ tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
+ boost::erase_all(tmp," ");
+ val.clear();
+ B64Decode(tmp, val);
+
+ if (len>-1 && val.size() != static_cast<size_t>(len))
+ throw RecordTextException("Record length "+std::to_string(val.size()) + " does not match expected length '"+std::to_string(len));
+}
+
+void RecordTextReader::xfrBlob(string& val, int)
+{
+ skipSpaces();
+ int pos=(int)d_pos;
+ const char* strptr=d_string.c_str();
+ while(d_pos < d_end && isbase64(strptr[d_pos], true))
+ d_pos++;
+
+ string tmp;
+ tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
+ boost::erase_all(tmp," ");
+ val.clear();
+ B64Decode(tmp, val);
+}
+
+
+static inline uint8_t hextodec(uint8_t val)
+{
+ if(val >= '0' && val<='9')
+ return val-'0';
+ else if(val >= 'A' && val<='F')
+ return 10+(val-'A');
+ else if(val >= 'a' && val<='f')
+ return 10+(val-'a');
+ else
+ throw RecordTextException("Unknown hexadecimal character '"+std::to_string(val)+"'");
+}
+
+
+void HEXDecode(const char* begin, const char* end, string& out)
+{
+ if(end - begin == 1 && *begin=='-') {
+ out.clear();
+ return;
+ }
+ out.clear();
+ out.reserve((end-begin)/2);
+ uint8_t mode=0, val=0;
+ for(; begin != end; ++begin) {
+ if(!isalnum(*begin))
+ continue;
+ if(mode==0) {
+ val = 16*hextodec(*begin);
+ mode=1;
+ } else {
+ val += hextodec(*begin);
+ out.append(1, (char) val);
+ mode = 0;
+ val = 0;
+ }
+ }
+ if(mode)
+ out.append(1, (char) val);
+
+}
+
+void RecordTextReader::xfrHexBlob(string& val, bool keepReading)
+{
+ skipSpaces();
+ int pos=(int)d_pos;
+ while(d_pos < d_end && (keepReading || !dns_isspace(d_string[d_pos])))
+ d_pos++;
+
+ HEXDecode(d_string.c_str()+pos, d_string.c_str() + d_pos, val);
+}
+
+void RecordTextReader::xfrBase32HexBlob(string& val)
+{
+ skipSpaces();
+ int pos=(int)d_pos;
+ while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
+ d_pos++;
+
+ val=fromBase32Hex(string(d_string.c_str()+pos, d_pos-pos));
+}
+
+
+void RecordTextWriter::xfrBase32HexBlob(const string& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ d_string.append(toUpper(toBase32Hex(val)));
+}
+
+
+void RecordTextReader::xfrText(string& val, bool multi, bool lenField)
+{
+ val.clear();
+ val.reserve(d_end - d_pos);
+
+ while(d_pos != d_end) {
+ if(!val.empty())
+ val.append(1, ' ');
+
+ skipSpaces();
+ if(d_string[d_pos]!='"') { // special case 'plenus' - without quotes
+ string::size_type pos = d_pos;
+ while(pos != d_end && isalnum(d_string[pos]))
+ pos++;
+ if(pos == d_end) {
+ val.append(1, '"');
+ val.append(d_string.c_str() + d_pos, d_end - d_pos);
+ val.append(1, '"');
+ d_pos = d_end;
+ break;
+ }
+ throw RecordTextException("Data field in DNS should start with quote (\") at position "+std::to_string(d_pos)+" of '"+d_string+"'");
+ }
+ val.append(1, '"');
+ while(++d_pos < d_end && d_string[d_pos]!='"') {
+ if(d_string[d_pos]=='\\' && d_pos+1!=d_end) {
+ val.append(1, d_string[d_pos++]);
+ }
+ val.append(1, d_string[d_pos]);
+ }
+ val.append(1,'"');
+ if(d_pos == d_end)
+ throw RecordTextException("Data field in DNS should end on a quote (\") in '"+d_string+"'");
+ d_pos++;
+ if(!multi)
+ break;
+ }
+}
+
+void RecordTextReader::xfrUnquotedText(string& val, bool lenField)
+{
+ val.clear();
+ val.reserve(d_end - d_pos);
+
+ if(!val.empty())
+ val.append(1, ' ');
+
+ skipSpaces();
+ val.append(1, d_string[d_pos]);
+ while(++d_pos < d_end && d_string[d_pos] != ' '){
+ val.append(1, d_string[d_pos]);
+ }
+}
+
+void RecordTextReader::xfrType(uint16_t& val)
+{
+ skipSpaces();
+ int pos=(int)d_pos;
+ while(d_pos < d_end && !dns_isspace(d_string[d_pos]))
+ d_pos++;
+
+ string tmp;
+ tmp.assign(d_string.c_str()+pos, d_string.c_str() + d_pos);
+
+ val=DNSRecordContent::TypeToNumber(tmp);
+}
+
+
+void RecordTextReader::skipSpaces()
+{
+ const char* strptr = d_string.c_str();
+ while(d_pos < d_end && dns_isspace(strptr[d_pos]))
+ d_pos++;
+ if(d_pos == d_end)
+ throw RecordTextException("missing field at the end of record content '"+d_string+"'");
+}
+
+
+RecordTextWriter::RecordTextWriter(string& str, bool noDot) : d_string(str)
+{
+ d_string.clear();
+ d_nodot=noDot;
+}
+
+void RecordTextWriter::xfr48BitInt(const uint64_t& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+ d_string+=std::to_string(val);
+}
+
+
+void RecordTextWriter::xfr32BitInt(const uint32_t& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+ d_string+=std::to_string(val);
+}
+
+void RecordTextWriter::xfrType(const uint16_t& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+ d_string+=DNSRecordContent::NumberToType(val);
+}
+
+// this function is on the fast path for the pdns_recursor
+void RecordTextWriter::xfrIP(const uint32_t& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ char tmp[17];
+ uint32_t ip=val;
+ uint8_t vals[4];
+
+ memcpy(&vals[0], &ip, sizeof(ip));
+
+ char *pos=tmp;
+
+ for(int n=0; n < 4; ++n) {
+ if(vals[n]<10) {
+ *(pos++)=vals[n]+'0';
+ } else if(vals[n] < 100) {
+ *(pos++)=(vals[n]/10) +'0';
+ *(pos++)=(vals[n]%10) +'0';
+ } else {
+ *(pos++)=(vals[n]/100) +'0';
+ vals[n]%=100;
+ *(pos++)=(vals[n]/10) +'0';
+ *(pos++)=(vals[n]%10) +'0';
+ }
+ if(n!=3)
+ *(pos++)='.';
+ }
+ *pos=0;
+ d_string.append(tmp, pos);
+}
+
+void RecordTextWriter::xfrIP6(const std::string& val)
+{
+ char tmpbuf[16];
+ char addrbuf[40];
+
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ val.copy(tmpbuf,16);
+
+ if (inet_ntop(AF_INET6, tmpbuf, addrbuf, sizeof addrbuf) == NULL)
+ throw RecordTextException("Unable to convert to ipv6 address");
+
+ d_string += std::string(addrbuf);
+}
+
+void RecordTextWriter::xfrTime(const uint32_t& val)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ struct tm tm;
+ time_t time=val; // Y2038 bug!
+ gmtime_r(&time, &tm);
+
+ char tmp[16];
+ snprintf(tmp,sizeof(tmp)-1, "%04d%02d%02d" "%02d%02d%02d",
+ tm.tm_year+1900, tm.tm_mon+1, tm.tm_mday,
+ tm.tm_hour, tm.tm_min, tm.tm_sec);
+
+ d_string += tmp;
+}
+
+
+void RecordTextWriter::xfr16BitInt(const uint16_t& val)
+{
+ xfr32BitInt(val);
+}
+
+void RecordTextWriter::xfr8BitInt(const uint8_t& val)
+{
+ xfr32BitInt(val);
+}
+
+// should not mess with the escapes
+void RecordTextWriter::xfrName(const DNSName& val, bool, bool noDot)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ if(d_nodot) {
+ d_string+=val.toStringRootDot();
+ }
+ else
+ {
+ d_string+=val.toString();
+ }
+}
+
+void RecordTextWriter::xfrBlobNoSpaces(const string& val, int size)
+{
+ xfrBlob(val, size);
+}
+
+void RecordTextWriter::xfrBlob(const string& val, int)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ d_string+=Base64Encode(val);
+}
+
+void RecordTextWriter::xfrHexBlob(const string& val, bool)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ if(val.empty()) {
+ d_string.append(1,'-');
+ return;
+ }
+
+ string::size_type limit=val.size();
+ char tmp[5];
+ for(string::size_type n = 0; n < limit; ++n) {
+ snprintf(tmp, sizeof(tmp)-1, "%02x", (unsigned char)val[n]);
+ d_string+=tmp;
+ }
+}
+
+void RecordTextWriter::xfrText(const string& val, bool multi, bool lenField)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+
+ d_string.append(val);
+}
+
+void RecordTextWriter::xfrUnquotedText(const string& val, bool lenField)
+{
+ if(!d_string.empty())
+ d_string.append(1,' ');
+ d_string.append(val);
+}
+
+#ifdef TESTING
+
+int main(int argc, char**argv)
+try
+{
+ RecordTextReader rtr(argv[1], argv[2]);
+
+ unsigned int order, pref;
+ string flags, services, regexp, replacement;
+ string mx;
+
+ rtr.xfrInt(order);
+ rtr.xfrInt(pref);
+ rtr.xfrText(flags);
+ rtr.xfrText(services);
+ rtr.xfrText(regexp);
+ rtr.xfrName(replacement);
+
+ cout<<"order: "<<order<<", pref: "<<pref<<"\n";
+ cout<<"flags: \""<<flags<<"\", services: \""<<services<<"\", regexp: \""<<regexp<<"\", replacement: "<<replacement<<"\n";
+
+ string out;
+ RecordTextWriter rtw(out);
+
+ rtw.xfrInt(order);
+ rtw.xfrInt(pref);
+ rtw.xfrText(flags);
+ rtw.xfrText(services);
+ rtw.xfrText(regexp);
+ rtw.xfrName(replacement);
+
+ cout<<"Regenerated: '"<<out<<"'\n";
+
+}
+catch(std::exception& e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_RCPGENERATOR_HH
+#define PDNS_RCPGENERATOR_HH
+#include <inttypes.h>
+#include <string>
+#include <stdexcept>
+
+#include "namespaces.hh"
+#include "dnsname.hh"
+
+class RecordTextException : public runtime_error
+{
+public:
+ RecordTextException(const string& str) : runtime_error(str)
+ {}
+};
+
+class RecordTextReader
+{
+public:
+ RecordTextReader(const string& str, const string& zone="");
+ void xfr64BitInt(uint64_t& val);
+ void xfr48BitInt(uint64_t& val);
+ void xfr32BitInt(uint32_t& val);
+ void xfr16BitInt(uint16_t& val);
+ void xfr8BitInt(uint8_t& val);
+
+ void xfrType(uint16_t& val);
+ void xfrIP(uint32_t& val);
+ void xfrIP6(std::string& val);
+ void xfrTime(uint32_t& val);
+
+ void xfrName(DNSName& val, bool compress=false, bool noDot=false);
+ void xfrText(string& val, bool multi=false, bool lenField=true);
+ void xfrUnquotedText(string& val, bool lenField=true);
+ void xfrHexBlob(string& val, bool keepReading=false);
+ void xfrBase32HexBlob(string& val);
+
+ void xfrBlobNoSpaces(string& val, int len=-1);
+ void xfrBlob(string& val, int len=-1);
+
+ bool eof();
+private:
+ string d_string;
+ string d_zone;
+ string::size_type d_pos;
+ string::size_type d_end;
+ void skipSpaces();
+};
+
+class RecordTextWriter
+{
+public:
+ RecordTextWriter(string& str, bool noDot=false);
+ void xfr48BitInt(const uint64_t& val);
+ void xfr32BitInt(const uint32_t& val);
+ void xfr16BitInt(const uint16_t& val);
+ void xfr8BitInt(const uint8_t& val);
+ void xfrIP(const uint32_t& val);
+ void xfrIP6(const std::string& val);
+ void xfrTime(const uint32_t& val);
+ void xfrBase32HexBlob(const string& val);
+
+ void xfrType(const uint16_t& val);
+ void xfrName(const DNSName& val, bool compress=false, bool noDot=false);
+ void xfrText(const string& val, bool multi=false, bool lenField=true);
+ void xfrUnquotedText(const string& val, bool lenField=true);
+ void xfrBlobNoSpaces(const string& val, int len=-1);
+ void xfrBlob(const string& val, int len=-1);
+ void xfrHexBlob(const string& val, bool keepReading=false);
+ bool eof() { return true; };
+private:
+ string& d_string;
+ bool d_nodot;
+};
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "sholder.hh"
+#include "sortlist.hh"
+#include "filterpo.hh"
+#include "remote_logger.hh"
+#include "validate.hh"
+
+class LuaConfigItems
+{
+public:
+ LuaConfigItems();
+ SortList sortlist;
+ DNSFilterEngine dfe;
+ map<DNSName,dsmap_t> dsAnchors;
+ map<DNSName,std::string> negAnchors;
+ std::shared_ptr<RemoteLogger> protobufServer{nullptr};
+ uint8_t protobufMaskV4{32};
+ uint8_t protobufMaskV6{128};
+};
+
+extern GlobalStateHolder<LuaConfigItems> g_luaconfs;
+void loadRecursorLuaConfig(const std::string& fname);
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "protobuf.hh"
+
+#include "dnsrecords.hh"
+
+class RecProtoBufMessage: public DNSProtoBufMessage
+{
+public:
+ RecProtoBufMessage(): DNSProtoBufMessage()
+ {
+ }
+
+ RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type): DNSProtoBufMessage(type)
+ {
+ }
+
+#ifdef HAVE_PROTOBUF
+ RecProtoBufMessage(DNSProtoBufMessage::DNSProtoBufMessageType type, const boost::uuids::uuid& uuid, const ComboAddress* requestor, const ComboAddress* responder, const DNSName& domain, int qtype, uint16_t qclass, uint16_t qid, bool isTCP, size_t bytes): DNSProtoBufMessage(type, uuid, requestor, responder, domain, qtype, qclass, qid, isTCP, bytes)
+ {
+ }
+#endif /* HAVE_PROTOBUF */
+
+ void addRRs(const std::vector<DNSRecord>& records);
+ void addRR(const DNSRecord& record);
+ void setAppliedPolicy(const std::string& policy);
+ void setPolicyTags(const std::vector<std::string>& policyTags);
+
+};
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2013 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+
+#include <cstdio>
+#include <signal.h>
+#include <cstring>
+#include <cstdlib>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <iostream>
+#include <string>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <sys/mman.h>
+#include <fcntl.h>
+#include <fstream>
+#include <boost/algorithm/string.hpp>
+#ifdef HAVE_LIBSODIUM
+#include <sodium.h>
+#endif
+#include "opensslsigners.hh"
+
+#include "dns.hh"
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "dnspacket.hh"
+#include "nameserver.hh"
+#include "distributor.hh"
+#include "logger.hh"
+#include "arguments.hh"
+#include "packethandler.hh"
+#include "statbag.hh"
+#include "tcpreceiver.hh"
+#include "misc.hh"
+#include "dynlistener.hh"
+#include "dynhandler.hh"
+#include "communicator.hh"
+#include "dnsproxy.hh"
+#include "utility.hh"
+#include "common_startup.hh"
+#include "dnsrecords.hh"
+#include "version.hh"
+
+time_t s_starttime;
+
+string s_programname="pdns"; // used in packethandler.cc
+
+const char *funnytext=
+"*****************************************************************************\n"\
+"Ok, you just ran pdns_server through 'strings' hoping to find funny messages.\n"\
+"Well, you found one. \n"\
+"Two ions are flying through their particle accelerator, says the one to the\n"
+"other 'I think I've lost an electron!' \n"\
+"So the other one says, 'Are you sure?'. 'YEAH! I'M POSITIVE!'\n"\
+" the pdns crew - pdns@powerdns.com\n"
+"*****************************************************************************\n";
+
+
+// start (sys)logging
+
+/** \var Logger L
+\brief All logging is done via L, a Logger instance
+*/
+
+
+/**
+\file receiver.cc
+\brief The main loop of powerdns
+
+This file is where it all happens - main is here, as are the two pivotal threads qthread() and athread()
+*/
+
+void daemonize(void)
+{
+ if(fork())
+ exit(0); // bye bye
+
+ setsid();
+
+ int i=open("/dev/null",O_RDWR); /* open stdin */
+ if(i < 0)
+ L<<Logger::Critical<<"Unable to open /dev/null: "<<stringerror()<<endl;
+ else {
+ dup2(i,0); /* stdin */
+ dup2(i,1); /* stderr */
+ dup2(i,2); /* stderr */
+ close(i);
+ }
+}
+
+static int cpid;
+static void takedown(int i)
+{
+ if(cpid) {
+ L<<Logger::Error<<"Guardian is killed, taking down children with us"<<endl;
+ kill(cpid,SIGKILL);
+ exit(0);
+ }
+}
+
+static void writePid(void)
+{
+ if(!::arg().mustDo("write-pid"))
+ return;
+
+ string fname=::arg()["socket-dir"];
+ if (::arg()["socket-dir"].empty()) {
+ if (::arg()["chroot"].empty())
+ fname = LOCALSTATEDIR;
+ else
+ fname = ::arg()["chroot"] + "/";
+ } else if (!::arg()["socket-dir"].empty() && !::arg()["chroot"].empty()) {
+ fname = ::arg()["chroot"] + ::arg()["socket-dir"];
+ }
+
+ fname += + "/" + s_programname + ".pid";
+ ofstream of(fname.c_str());
+ if(of)
+ of<<getpid()<<endl;
+ else
+ L<<Logger::Error<<"Writing pid for "<<getpid()<<" to "<<fname<<" failed: "<<strerror(errno)<<endl;
+}
+
+int g_fd1[2], g_fd2[2];
+FILE *g_fp;
+pthread_mutex_t g_guardian_lock = PTHREAD_MUTEX_INITIALIZER;
+
+// The next two methods are not in dynhandler.cc because they use a few items declared in this file.
+static string DLCycleHandler(const vector<string>&parts, pid_t ppid)
+{
+ kill(cpid, SIGKILL); // why?
+ kill(cpid, SIGKILL); // why?
+ sleep(1);
+ return "ok";
+}
+
+static string DLRestHandler(const vector<string>&parts, pid_t ppid)
+{
+ string line;
+
+ for(vector<string>::const_iterator i=parts.begin();i!=parts.end();++i) {
+ if(i!=parts.begin())
+ line.append(1,' ');
+ line.append(*i);
+ }
+ line.append(1,'\n');
+
+ Lock l(&g_guardian_lock);
+
+ try {
+ writen2(g_fd1[1],line.c_str(),line.size()+1);
+ }
+ catch(PDNSException &ae) {
+ return "Error communicating with instance: "+ae.reason;
+ }
+ char mesg[512];
+ string response;
+ while(fgets(mesg,sizeof(mesg),g_fp)) {
+ if(*mesg=='\0')
+ break;
+ response+=mesg;
+ }
+ boost::trim_right(response);
+ return response;
+}
+
+
+
+static int guardian(int argc, char **argv)
+{
+ if(isGuarded(argv))
+ return 0;
+
+ int infd=0, outfd=1;
+
+ DynListener dlg(s_programname);
+ dlg.registerFunc("QUIT",&DLQuitHandler, "quit daemon");
+ dlg.registerFunc("CYCLE",&DLCycleHandler, "restart instance");
+ dlg.registerFunc("PING",&DLPingHandler, "ping guardian");
+ dlg.registerFunc("STATUS",&DLStatusHandler, "get instance status from guardian");
+ dlg.registerRestFunc(&DLRestHandler);
+ dlg.go();
+ string progname=argv[0];
+
+ bool first=true;
+ cpid=0;
+
+ pthread_mutex_lock(&g_guardian_lock);
+
+ for(;;) {
+ int pid;
+ setStatus("Launching child");
+
+ if(pipe(g_fd1)<0 || pipe(g_fd2)<0) {
+ L<<Logger::Critical<<"Unable to open pipe for coprocess: "<<strerror(errno)<<endl;
+ exit(1);
+ }
+
+ if(!(g_fp=fdopen(g_fd2[0],"r"))) {
+ L<<Logger::Critical<<"Unable to associate a file pointer with pipe: "<<stringerror()<<endl;
+ exit(1);
+ }
+ setbuf(g_fp,0); // no buffering please, confuses select
+
+ if(!(pid=fork())) { // child
+ signal(SIGTERM, SIG_DFL);
+
+ signal(SIGHUP, SIG_DFL);
+ signal(SIGUSR1, SIG_DFL);
+ signal(SIGUSR2, SIG_DFL);
+
+ char **const newargv=new char*[argc+2];
+ int n;
+
+ if(::arg()["config-name"]!="") {
+ progname+="-"+::arg()["config-name"];
+ L<<Logger::Error<<"Virtual configuration name: "<<::arg()["config-name"]<<endl;
+ }
+
+ newargv[0]=strdup(const_cast<char *>((progname+"-instance").c_str()));
+ for(n=1;n<argc;n++) {
+ newargv[n]=argv[n];
+ }
+ newargv[n]=0;
+
+ L<<Logger::Error<<"Guardian is launching an instance"<<endl;
+ close(g_fd1[1]);
+ fclose(g_fp); // this closes g_fd2[0] for us
+
+ if(g_fd1[0]!= infd) {
+ dup2(g_fd1[0], infd);
+ close(g_fd1[0]);
+ }
+
+ if(g_fd2[1]!= outfd) {
+ dup2(g_fd2[1], outfd);
+ close(g_fd2[1]);
+ }
+ if(execvp(argv[0], newargv)<0) {
+ L<<Logger::Error<<"Unable to execvp '"<<argv[0]<<"': "<<strerror(errno)<<endl;
+ char **p=newargv;
+ while(*p)
+ L<<Logger::Error<<*p++<<endl;
+
+ exit(1);
+ }
+ L<<Logger::Error<<"execvp returned!!"<<endl;
+ // never reached
+ }
+ else if(pid>0) { // parent
+ close(g_fd1[0]);
+ close(g_fd2[1]);
+
+ if(first) {
+ first=false;
+ signal(SIGTERM, takedown);
+
+ signal(SIGHUP, SIG_IGN);
+ signal(SIGUSR1, SIG_IGN);
+ signal(SIGUSR2, SIG_IGN);
+
+ writePid();
+ }
+ pthread_mutex_unlock(&g_guardian_lock);
+ int status;
+ cpid=pid;
+ for(;;) {
+ int ret=waitpid(pid,&status,WNOHANG);
+
+ if(ret<0) {
+ L<<Logger::Error<<"In guardian loop, waitpid returned error: "<<strerror(errno)<<endl;
+ L<<Logger::Error<<"Dying"<<endl;
+ exit(1);
+ }
+ else if(ret) // something exited
+ break;
+ else { // child is alive
+ // execute some kind of ping here
+ if(DLQuitPlease())
+ takedown(1); // needs a parameter..
+ setStatus("Child running on pid "+itoa(pid));
+ sleep(1);
+ }
+ }
+
+ pthread_mutex_lock(&g_guardian_lock);
+ close(g_fd1[1]);
+ fclose(g_fp);
+ g_fp=0;
+
+ if(WIFEXITED(status)) {
+ int ret=WEXITSTATUS(status);
+
+ if(ret==99) {
+ L<<Logger::Error<<"Child requested a stop, exiting"<<endl;
+ exit(1);
+ }
+ setStatus("Child died with code "+itoa(ret));
+ L<<Logger::Error<<"Our pdns instance exited with code "<<ret<<", respawning"<<endl;
+
+ sleep(1);
+ continue;
+ }
+ if(WIFSIGNALED(status)) {
+ int sig=WTERMSIG(status);
+ setStatus("Child died because of signal "+itoa(sig));
+ L<<Logger::Error<<"Our pdns instance ("<<pid<<") exited after signal "<<sig<<endl;
+#ifdef WCOREDUMP
+ if(WCOREDUMP(status))
+ L<<Logger::Error<<"Dumped core"<<endl;
+#endif
+
+ L<<Logger::Error<<"Respawning"<<endl;
+ sleep(1);
+ continue;
+ }
+ L<<Logger::Error<<"No clue what happened! Respawning"<<endl;
+ }
+ else {
+ L<<Logger::Error<<"Unable to fork: "<<strerror(errno)<<endl;
+ exit(1);
+ }
+ }
+}
+
+static void UNIX_declareArguments()
+{
+ ::arg().set("config-dir","Location of configuration directory (pdns.conf)")=SYSCONFDIR;
+ ::arg().set("config-name","Name of this virtual configuration - will rename the binary image")="";
+ ::arg().set("socket-dir",string("Where the controlsocket will live, ")+LOCALSTATEDIR+" when unset and not chrooted" )="";
+ ::arg().set("module-dir","Default directory for modules")=PKGLIBDIR;
+ ::arg().set("chroot","If set, chroot to this directory for more security")="";
+ ::arg().set("logging-facility","Log under a specific facility")="";
+ ::arg().set("daemon","Operate as a daemon")="no";
+}
+
+static void loadModules()
+{
+ if(!::arg()["load-modules"].empty()) {
+ vector<string>modules;
+
+ stringtok(modules,::arg()["load-modules"],", ");
+
+ for(vector<string>::const_iterator i=modules.begin();i!=modules.end();++i) {
+ bool res;
+ const string &module=*i;
+
+ if(module.find(".")==string::npos)
+ res=UeberBackend::loadmodule(::arg()["module-dir"]+"/lib"+module+"backend.so");
+ else if(module[0]=='/' || (module[0]=='.' && module[1]=='/') || (module[0]=='.' && module[1]=='.')) // absolute or current path
+ res=UeberBackend::loadmodule(module);
+ else
+ res=UeberBackend::loadmodule(::arg()["module-dir"]+"/"+module);
+
+ if(res==false) {
+ L<<Logger::Error<<"Receiver unable to load module "<<module<<endl;
+ exit(1);
+ }
+ }
+ }
+}
+
+#ifdef __GLIBC__
+#include <execinfo.h>
+static void tbhandler(int num)
+{
+ L<<Logger::Critical<<"Got a signal "<<num<<", attempting to print trace: "<<endl;
+ void *array[20]; //only care about last 17 functions (3 taken with tracing support)
+ size_t size;
+ char **strings;
+ size_t i;
+
+ size = backtrace (array, 20);
+ strings = backtrace_symbols (array, size); //Need -rdynamic gcc (linker) flag for this to work
+
+ for (i = 0; i < size; i++) //skip useless functions
+ L<<Logger::Error<<strings[i]<<endl;
+
+
+ signal(SIGABRT, SIG_DFL);
+ abort();//hopefully will give core
+
+}
+#endif
+
+//! The main function of pdns, the pdns process
+int main(int argc, char **argv)
+{
+ versionSetProduct(ProductAuthoritative);
+ reportAllTypes(); // init MOADNSParser
+
+ s_programname="pdns";
+ s_starttime=time(0);
+
+#ifdef __GLIBC__
+ signal(SIGSEGV,tbhandler);
+ signal(SIGFPE,tbhandler);
+ signal(SIGABRT,tbhandler);
+ signal(SIGILL,tbhandler);
+#endif
+
+#if __GNUC__ >= 3
+ std::ios_base::sync_with_stdio(false);
+#endif
+
+ L.toConsole(Logger::Warning);
+ try {
+ declareArguments();
+ UNIX_declareArguments();
+
+ ::arg().laxParse(argc,argv); // do a lax parse
+
+ if(::arg().mustDo("version")) {
+ showProductVersion();
+ showBuildConfiguration();
+ exit(99);
+ }
+
+ if(::arg()["config-name"]!="")
+ s_programname+="-"+::arg()["config-name"];
+
+ (void)theL(s_programname);
+
+ string configname=::arg()["config-dir"]+"/"+s_programname+".conf";
+ cleanSlashes(configname);
+
+ if(!::arg().mustDo("config") && !::arg().mustDo("no-config")) // "config" == print a configuration file
+ ::arg().laxFile(configname.c_str());
+
+ ::arg().laxParse(argc,argv); // reparse so the commandline still wins
+ if(!::arg()["logging-facility"].empty()) {
+ int val=logFacilityToLOG(::arg().asNum("logging-facility") );
+ if(val >= 0)
+ theL().setFacility(val);
+ else
+ L<<Logger::Error<<"Unknown logging facility "<<::arg().asNum("logging-facility") <<endl;
+ }
+
+ L.setLoglevel((Logger::Urgency)(::arg().asNum("loglevel")));
+ L.disableSyslog(::arg().mustDo("disable-syslog"));
+ L.toConsole((Logger::Urgency)(::arg().asNum("loglevel")));
+
+ if(::arg().mustDo("help") || ::arg().mustDo("config")) {
+ ::arg().set("daemon")="no";
+ ::arg().set("guardian")="no";
+ }
+
+ if(::arg().mustDo("guardian") && !isGuarded(argv)) {
+ if(::arg().mustDo("daemon")) {
+ L.toConsole(Logger::Critical);
+ daemonize();
+ }
+ guardian(argc, argv);
+ // never get here, guardian will reinvoke process
+ cerr<<"Um, we did get here!"<<endl;
+ }
+
+
+ // we really need to do work - either standalone or as an instance
+
+#ifdef __GLIBC__
+ if(!::arg().mustDo("traceback-handler")) {
+ L<<Logger::Warning<<"Disabling traceback handler"<<endl;
+ signal(SIGSEGV,SIG_DFL);
+ signal(SIGFPE,SIG_DFL);
+ signal(SIGABRT,SIG_DFL);
+ signal(SIGILL,SIG_DFL);
+ }
+#endif
+
+ seedRandom(::arg()["entropy-source"]);
+
+#ifdef HAVE_LIBSODIUM
+ if (sodium_init() == -1) {
+ cerr<<"Unable to initialize sodium crypto library"<<endl;
+ exit(99);
+ }
+#endif
+
+ openssl_thread_setup();
+ openssl_seed();
+
+ loadModules();
+ BackendMakers().launch(::arg()["launch"]); // vrooooom!
+
+ if(!::arg().getCommands().empty()) {
+ cerr<<"Fatal: non-option on the command line, perhaps a '--setting=123' statement missed the '='?"<<endl;
+ exit(99);
+ }
+
+ if(::arg().mustDo("help")) {
+ cout<<"syntax:"<<endl<<endl;
+ cout<<::arg().helpstring(::arg()["help"])<<endl;
+ exit(0);
+ }
+
+ if(::arg().mustDo("config")) {
+ cout<<::arg().configstring()<<endl;
+ exit(0);
+ }
+
+ if(::arg().mustDo("list-modules")) {
+ auto modules = BackendMakers().getModules();
+ cout<<"Modules available:"<<endl;
+ for(const auto& m : modules)
+ cout<< m <<endl;
+
+ _exit(99);
+ }
+
+ if(!::arg().asNum("local-port")) {
+ L<<Logger::Error<<"Unable to launch, binding to no port or port 0 makes no sense"<<endl;
+ exit(99); // this isn't going to fix itself either
+ }
+ if(!BackendMakers().numLauncheable()) {
+ L<<Logger::Error<<"Unable to launch, no backends configured for querying"<<endl;
+ exit(99); // this isn't going to fix itself either
+ }
+ if(::arg().mustDo("daemon")) {
+ L.toConsole(Logger::None);
+ if(!isGuarded(argv))
+ daemonize();
+ }
+
+ if(isGuarded(argv)) {
+ L<<Logger::Warning<<"This is a guarded instance of pdns"<<endl;
+ dl=new DynListener; // listens on stdin
+ }
+ else {
+ L<<Logger::Warning<<"This is a standalone pdns"<<endl;
+
+ if(::arg().mustDo("control-console"))
+ dl=new DynListener();
+ else
+ dl=new DynListener(s_programname);
+
+ writePid();
+ }
+ DynListener::registerFunc("SHOW",&DLShowHandler, "show a specific statistic or * to get a list", "<statistic>");
+ DynListener::registerFunc("RPING",&DLPingHandler, "ping instance");
+ DynListener::registerFunc("QUIT",&DLRQuitHandler, "quit daemon");
+ DynListener::registerFunc("UPTIME",&DLUptimeHandler, "get instance uptime");
+ DynListener::registerFunc("NOTIFY-HOST",&DLNotifyHostHandler, "notify host for specific domain", "<domain> <host>");
+ DynListener::registerFunc("NOTIFY",&DLNotifyHandler, "queue a notification", "<domain>");
+ DynListener::registerFunc("RELOAD",&DLReloadHandler, "reload all zones");
+ DynListener::registerFunc("REDISCOVER",&DLRediscoverHandler, "discover any new zones");
+ DynListener::registerFunc("VERSION",&DLVersionHandler, "get instance version");
+ DynListener::registerFunc("PURGE",&DLPurgeHandler, "purge entries from packet cache", "[<record>]");
+ DynListener::registerFunc("CCOUNTS",&DLCCHandler, "get cache statistics");
+ DynListener::registerFunc("QTYPES", &DLQTypesHandler, "get QType statistics");
+ DynListener::registerFunc("RESPSIZES", &DLRSizesHandler, "get histogram of response sizes");
+ DynListener::registerFunc("REMOTES", &DLRemotesHandler, "get top remotes");
+ DynListener::registerFunc("SET",&DLSettingsHandler, "set config variables", "<var> <value>");
+ DynListener::registerFunc("RETRIEVE",&DLNotifyRetrieveHandler, "retrieve slave domain", "<domain>");
+ DynListener::registerFunc("CURRENT-CONFIG",&DLCurrentConfigHandler, "retrieve the current configuration");
+ DynListener::registerFunc("LIST-ZONES",&DLListZones, "show list of zones", "[master|slave|native]");
+ DynListener::registerFunc("POLICY",&DLPolicy, "interact with policy engine", "[policy command]");
+ DynListener::registerFunc("TOKEN-LOGIN", &DLTokenLogin, "Login to a PKCS#11 token", "<module> <slot> <pin>");
+
+ if(!::arg()["tcp-control-address"].empty()) {
+ DynListener* dlTCP=new DynListener(ComboAddress(::arg()["tcp-control-address"], ::arg().asNum("tcp-control-port")));
+ dlTCP->go();
+ }
+
+ // reparse, with error checking
+ if(!::arg().mustDo("no-config"))
+ ::arg().file(configname.c_str());
+ ::arg().parse(argc,argv);
+
+ if(::arg()["server-id"].empty()) {
+ char tmp[128];
+ gethostname(tmp, sizeof(tmp)-1);
+ ::arg().set("server-id")=tmp;
+ }
+
+ UeberBackend::go();
+ N=std::make_shared<UDPNameserver>(); // this fails when we are not root, throws exception
+ g_udpReceivers.push_back(N);
+
+ size_t rthreads = ::arg().asNum("receiver-threads", 1);
+ if (rthreads > 1 && N->canReusePort()) {
+ g_udpReceivers.resize(rthreads);
+
+ for (size_t idx = 1; idx < rthreads; idx++) {
+ try {
+ g_udpReceivers[idx] = std::make_shared<UDPNameserver>(true);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Unable to reuse port, falling back to original bind"<<endl;
+ break;
+ }
+ }
+ }
+
+ if(!::arg().mustDo("disable-tcp"))
+ TN=new TCPNameserver;
+ }
+ catch(const ArgException &A) {
+ L<<Logger::Error<<"Fatal error: "<<A.reason<<endl;
+ exit(1);
+ }
+
+ declareStats();
+ DLOG(L<<Logger::Warning<<"Verbose logging in effect"<<endl);
+
+ showProductVersion();
+
+ try {
+ mainthread();
+ }
+ catch(PDNSException &AE) {
+ if(!::arg().mustDo("daemon"))
+ cerr<<"Exiting because: "<<AE.reason<<endl;
+ L<<Logger::Error<<"Exiting because: "<<AE.reason<<endl;
+ }
+ catch(std::exception &e) {
+ if(!::arg().mustDo("daemon"))
+ cerr<<"Exiting because of STL error: "<<e.what()<<endl;
+ L<<Logger::Error<<"Exiting because of STL error: "<<e.what()<<endl;
+ }
+ catch(...) {
+ cerr<<"Uncaught exception of unknown type - sorry"<<endl;
+ }
+
+ exit(1);
+
+}
+
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <iostream>
+
+#include "recpacketcache.hh"
+#include "cachecleaner.hh"
+#include "dns.hh"
+#include "dnsparser.hh"
+#include "namespaces.hh"
+#include "lock.hh"
+#include "dnswriter.hh"
+#include "ednsoptions.hh"
+
+RecursorPacketCache::RecursorPacketCache()
+{
+ d_hits = d_misses = 0;
+}
+
+int RecursorPacketCache::doWipePacketCache(const DNSName& name, uint16_t qtype, bool subtree)
+{
+ int count=0;
+ auto& idx = d_packetCache.get<NameTag>();
+ for(auto iter = idx.lower_bound(name); iter != idx.end(); ) {
+ if(subtree) {
+ if(!iter->d_name.isPartOf(name)) { // this is case insensitive
+ break;
+ }
+ }
+ else {
+ if(iter->d_name != name)
+ break;
+ }
+
+ if(qtype==0xffff || iter->d_type == qtype) {
+ iter=idx.erase(iter);
+ count++;
+ }
+ else
+ ++iter;
+ }
+ return count;
+}
+
+// one day this function could be really fast by doing only a case insensitive compare
+static bool qrMatch(const std::string& query, const std::string& response)
+{
+ uint16_t rqtype, rqclass, qqtype, qqclass;
+ DNSName queryname(query.c_str(), query.length(), sizeof(dnsheader), false, &qqtype, &qqclass, 0);
+ DNSName respname(response.c_str(), response.length(), sizeof(dnsheader), false, &rqtype, &rqclass, 0);
+ // this ignores checking on the EDNS subnet flags!
+ return queryname==respname && rqtype == qqtype && rqclass == qqclass;
+}
+
+uint32_t RecursorPacketCache::canHashPacket(const std::string& origPacket)
+{
+ // return 42; // should still work if you do this!
+ uint32_t ret=0;
+ ret=burtle((const unsigned char*)origPacket.c_str() + 2, 10, ret); // rest of dnsheader, skip id
+ const char* end = origPacket.c_str() + origPacket.size();
+ const char* p = origPacket.c_str() + 12;
+
+ for(; p < end && *p; ++p) { // XXX if you embed a 0 in your qname we'll stop lowercasing there
+ const char l = dns_tolower(*p); // label lengths can safely be lower cased
+ ret=burtle((const unsigned char*)&l, 1, ret);
+ } // XXX the embedded 0 in the qname will break the subnet stripping
+
+ struct dnsheader* dh = (struct dnsheader*)origPacket.c_str();
+ const char* skipBegin = p;
+ const char* skipEnd = p;
+ /* we need at least 1 (final empty label) + 2 (QTYPE) + 2 (QCLASS)
+ + OPT root label (1), type (2), class (2) and ttl (4)
+ + the OPT RR rdlen (2)
+ = 16
+ */
+ if(ntohs(dh->arcount)==1 && (p+16) < end) {
+ char* optionBegin = nullptr;
+ size_t optionLen = 0;
+ /* skip the final empty label (1), the qtype (2), qclass (2) */
+ /* root label (1), type (2), class (2) and ttl (4) */
+ int res = getEDNSOption((char*) p + 14, end - (p + 14), EDNSOptionCode::ECS, &optionBegin, &optionLen);
+ if (res == 0) {
+ skipBegin = optionBegin;
+ skipEnd = optionBegin + optionLen;
+ }
+ }
+ if (skipBegin > p) {
+ //cout << "Hashing from " << (p-origPacket.c_str()) << " for " << skipBegin-p << "bytes, end is at "<< end-origPacket.c_str() << endl;
+ ret = burtle((const unsigned char*)p, skipBegin-p, ret);
+ }
+ if (skipEnd < end) {
+ //cout << "Hashing from " << (skipEnd-origPacket.c_str()) << " for " << end-skipEnd << "bytes, end is at " << end-origPacket.c_str() << endl;
+ ret = burtle((const unsigned char*) skipEnd, end-skipEnd, ret);
+ }
+ return ret;
+}
+
+bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
+ std::string* responsePacket, uint32_t* age)
+{
+ return getResponsePacket(tag, queryPacket, now, responsePacket, age, nullptr);
+}
+
+bool RecursorPacketCache::getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now,
+ std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage)
+{
+ uint32_t h = canHashPacket(queryPacket);
+ auto& idx = d_packetCache.get<HashTag>();
+ auto range = idx.equal_range(tie(tag,h));
+
+ if(range.first == range.second) {
+ d_misses++;
+ return false;
+ }
+
+ for(auto iter = range.first ; iter != range.second ; ++ iter) {
+ // the possibility is VERY real that we get hits that are not right - birthday paradox
+ if(!qrMatch(queryPacket, iter->d_packet))
+ continue;
+ if((uint32_t)now < iter->d_ttd) { // it is right, it is fresh!
+ *age = now - iter->d_creation;
+ *responsePacket = iter->d_packet;
+ responsePacket->replace(0, 2, queryPacket.c_str(), 2);
+
+ string::size_type i=sizeof(dnsheader);
+
+ for(;;) {
+ int labellen = (unsigned char)queryPacket[i];
+ if(!labellen || i + labellen > responsePacket->size()) break;
+ i++;
+ responsePacket->replace(i, labellen, queryPacket, i, labellen);
+ i = i + labellen;
+ }
+
+ d_hits++;
+ moveCacheItemToBack(d_packetCache, iter);
+#ifdef HAVE_PROTOBUF
+ if (protobufMessage) {
+ *protobufMessage = iter->d_protobufMessage;
+ }
+#endif
+
+ return true;
+ }
+ else {
+ moveCacheItemToFront(d_packetCache, iter);
+ d_misses++;
+ break;
+ }
+ }
+
+ return false;
+}
+
+
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl)
+{
+ insertResponsePacket(tag, qname, qtype, queryPacket, responsePacket, now, ttl, nullptr);
+}
+
+void RecursorPacketCache::insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttl, const RecProtoBufMessage* protobufMessage)
+{
+ auto qhash = canHashPacket(queryPacket);
+ auto& idx = d_packetCache.get<HashTag>();
+ auto range = idx.equal_range(tie(tag,qhash));
+ auto iter = range.first;
+
+ for( ; iter != range.second ; ++iter) {
+ if(iter->d_type != qtype)
+ continue;
+ // this only happens on insert which is relatively rare and does not need to be super fast
+ DNSName respname(iter->d_packet.c_str(), iter->d_packet.length(), sizeof(dnsheader), false, 0, 0, 0);
+ if(qname != respname)
+ continue;
+ moveCacheItemToBack(d_packetCache, iter);
+ iter->d_packet = responsePacket;
+ iter->d_ttd = now + ttl;
+ iter->d_creation = now;
+#ifdef HAVE_PROTOBUF
+ if (protobufMessage) {
+ iter->d_protobufMessage = *protobufMessage;
+ }
+#endif
+
+ break;
+ }
+
+ if(iter == range.second) { // nothing to refresh
+ struct Entry e;
+ e.d_packet = responsePacket;
+ e.d_name = qname;
+ e.d_qhash = qhash;
+ e.d_type = qtype;
+ e.d_ttd = now+ttl;
+ e.d_creation = now;
+ e.d_tag = tag;
+#ifdef HAVE_PROTOBUF
+ if (protobufMessage) {
+ e.d_protobufMessage = *protobufMessage;
+ }
+#endif
+ d_packetCache.insert(e);
+ }
+}
+
+uint64_t RecursorPacketCache::size()
+{
+ return d_packetCache.size();
+}
+
+uint64_t RecursorPacketCache::bytes()
+{
+ uint64_t sum=0;
+ for(const auto& e : d_packetCache) {
+ sum += sizeof(e) + e.d_packet.length() + 4;
+ }
+ return sum;
+}
+
+void RecursorPacketCache::doPruneTo(unsigned int maxCached)
+{
+ pruneCollection(d_packetCache, maxCached);
+}
+
+uint64_t RecursorPacketCache::doDump(int fd)
+{
+ FILE* fp=fdopen(dup(fd), "w");
+ if(!fp) { // dup probably failed
+ return 0;
+ }
+ fprintf(fp, "; main packet cache dump from thread follows\n;\n");
+ const auto& sidx=d_packetCache.get<1>();
+
+ uint64_t count=0;
+ time_t now=time(0);
+ for(auto i=sidx.cbegin(); i != sidx.cend(); ++i) {
+ count++;
+ try {
+ fprintf(fp, "%s %d %s ; tag %d\n", i->d_name.toString().c_str(), (int32_t)(i->d_ttd - now), DNSRecordContent::NumberToType(i->d_type).c_str(), i->d_tag);
+ }
+ catch(...) {
+ fprintf(fp, "; error printing '%s'\n", i->d_name.empty() ? "EMPTY" : i->d_name.toString().c_str());
+ }
+ }
+ fclose(fp);
+ return count;
+
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_RECPACKETCACHE_HH
+#define PDNS_RECPACKETCACHE_HH
+#include <string>
+#include <set>
+#include <inttypes.h>
+#include "dns.hh"
+#include "namespaces.hh"
+#include <iostream>
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/multi_index/hashed_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "rec-protobuf.hh"
+
+
+using namespace ::boost::multi_index;
+
+//! Stores whole packets, ready for lobbing back at the client. Not threadsafe.
+/* Note: we store answers as value AND KEY, and with careful work, we make sure that
+ you can use a query as a key too. But query and answer must compare as identical!
+
+ This precludes doing anything smart with EDNS directly from the packet */
+class RecursorPacketCache
+{
+public:
+ RecursorPacketCache();
+ bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age);
+ void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd);
+ bool getResponsePacket(unsigned int tag, const std::string& queryPacket, time_t now, std::string* responsePacket, uint32_t* age, RecProtoBufMessage* protobufMessage);
+ void insertResponsePacket(unsigned int tag, const DNSName& qname, uint16_t qtype, const std::string& queryPacket, const std::string& responsePacket, time_t now, uint32_t ttd, const RecProtoBufMessage* protobufMessage);
+ void doPruneTo(unsigned int maxSize=250000);
+ uint64_t doDump(int fd);
+ int doWipePacketCache(const DNSName& name, uint16_t qtype=0xffff, bool subtree=false);
+
+ void prune();
+ uint64_t d_hits, d_misses;
+ uint64_t size();
+ uint64_t bytes();
+
+private:
+ struct HashTag {};
+ struct NameTag {};
+ struct Entry
+ {
+ mutable uint32_t d_ttd;
+ mutable uint32_t d_creation; // so we can 'age' our packets
+ DNSName d_name;
+ uint16_t d_type;
+ mutable std::string d_packet; // "I know what I am doing"
+#ifdef HAVE_PROTOBUF
+ mutable RecProtoBufMessage d_protobufMessage;
+#endif
+ uint32_t d_qhash;
+ uint32_t d_tag;
+ inline bool operator<(const struct Entry& rhs) const;
+
+ uint32_t getTTD() const
+ {
+ return d_ttd;
+ }
+ };
+ uint32_t canHashPacket(const std::string& origPacket);
+ typedef multi_index_container<
+ Entry,
+ indexed_by <
+ hashed_non_unique<tag<HashTag>, composite_key<Entry, member<Entry,uint32_t,&Entry::d_tag>, member<Entry,uint32_t,&Entry::d_qhash> > >,
+ sequenced<> ,
+ ordered_non_unique<tag<NameTag>, member<Entry,DNSName,&Entry::d_name>, CanonDNSNameCompare >
+ >
+ > packetCache_t;
+
+ packetCache_t d_packetCache;
+};
+
+#endif
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef RECURSOR_CACHE_HH
+#define RECURSOR_CACHE_HH
+#include <string>
+#include <set>
+#include "dns.hh"
+#include "qtype.hh"
+#include "misc.hh"
+#include "dnsname.hh"
+#include <iostream>
+#include "dnsrecords.hh"
+#include <boost/utility.hpp>
+#undef L
+#include <boost/multi_index_container.hpp>
+#include <boost/multi_index/ordered_index.hpp>
+#include <boost/tuple/tuple_comparison.hpp>
+#include <boost/multi_index/key_extractors.hpp>
+#include <boost/multi_index/sequenced_index.hpp>
+#include <boost/version.hpp>
+#include "iputils.hh"
+#undef max
+
+#define L theL()
+#include "namespaces.hh"
+using namespace ::boost::multi_index;
+
+class MemRecursorCache : public boost::noncopyable // : public RecursorCache
+{
+public:
+ MemRecursorCache() : d_cachecachevalid(false)
+ {
+ cacheHits = cacheMisses = 0;
+ }
+ unsigned int size();
+ unsigned int bytes();
+ int get(time_t, const DNSName &qname, const QType& qt, vector<DNSRecord>* res, const ComboAddress& who, vector<std::shared_ptr<RRSIGRecordContent>>* signatures=0);
+
+ void replace(time_t, const DNSName &qname, const QType& qt, const vector<DNSRecord>& content, const vector<shared_ptr<RRSIGRecordContent>>& signatures, bool auth, boost::optional<Netmask> ednsmask=boost::optional<Netmask>());
+ void doPrune(void);
+ void doSlash(int perc);
+ uint64_t doDump(int fd);
+ uint64_t doDumpNSSpeeds(int fd);
+
+ int doWipeCache(const DNSName& name, bool sub, uint16_t qtype=0xffff);
+ bool doAgeCache(time_t now, const DNSName& name, uint16_t qtype, int32_t newTTL);
+ uint64_t cacheHits, cacheMisses;
+
+private:
+
+ struct CacheEntry
+ {
+ CacheEntry(const boost::tuple<DNSName, uint16_t, Netmask>& key, const vector<shared_ptr<DNSRecordContent>>& records, bool auth) :
+ d_qname(key.get<0>()), d_qtype(key.get<1>()), d_auth(auth), d_ttd(0), d_records(records), d_netmask(key.get<2>())
+ {}
+
+ typedef vector<std::shared_ptr<DNSRecordContent>> records_t;
+ vector<std::shared_ptr<RRSIGRecordContent>> d_signatures;
+ uint32_t getTTD() const
+ {
+ return d_ttd;
+ }
+
+ DNSName d_qname;
+ uint16_t d_qtype;
+ bool d_auth;
+ uint32_t d_ttd;
+ records_t d_records;
+ Netmask d_netmask;
+ };
+
+ typedef multi_index_container<
+ CacheEntry,
+ indexed_by <
+ ordered_unique<
+ composite_key<
+ CacheEntry,
+ member<CacheEntry,DNSName,&CacheEntry::d_qname>,
+ member<CacheEntry,uint16_t,&CacheEntry::d_qtype>,
+ member<CacheEntry,Netmask,&CacheEntry::d_netmask>
+ >,
+ composite_key_compare<CanonDNSNameCompare, std::less<uint16_t>, std::less<Netmask> >
+ >,
+ sequenced<>
+ >
+ > cache_t;
+
+ cache_t d_cache;
+ pair<cache_t::iterator, cache_t::iterator> d_cachecache;
+ DNSName d_cachedqname;
+ bool d_cachecachevalid;
+ bool attemptToRefreshNSTTL(const QType& qt, const vector<DNSRecord>& content, const CacheEntry& stored);
+};
+#endif
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation.
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "resolver.hh"
+#include <pthread.h>
+#include <semaphore.h>
+#include <iostream>
+#include <errno.h>
+#include "misc.hh"
+#include <algorithm>
+#include <sstream>
+#include "dnsrecords.hh"
+#include <cstring>
+#include <string>
+#include <vector>
+#include <boost/algorithm/string.hpp>
+#include "dns.hh"
+#include "qtype.hh"
+
+#include "pdnsexception.hh"
+#include "arguments.hh"
+#include "base64.hh"
+#include "dnswriter.hh"
+#include "dnsparser.hh"
+
+
+#include "dns_random.hh"
+#include <poll.h>
+#include "gss_context.hh"
+#include "namespaces.hh"
+
+int makeQuerySocket(const ComboAddress& local, bool udpOrTCP)
+{
+ ComboAddress ourLocal(local);
+
+ int sock=socket(ourLocal.sin4.sin_family, udpOrTCP ? SOCK_DGRAM : SOCK_STREAM, 0);
+ if(sock < 0) {
+ if(errno == EAFNOSUPPORT && local.sin4.sin_family == AF_INET6) {
+ return -1;
+ }
+ unixDie("Creating local resolver socket for "+ourLocal.toString());
+ }
+
+ setCloseOnExec(sock);
+ if(udpOrTCP) {
+ // udp, try hard to bind an unpredictable port
+ int tries=10;
+ while(--tries) {
+ ourLocal.sin4.sin_port = htons(10000+(dns_random(10000)));
+
+ if (::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) >= 0)
+ break;
+ }
+ // cerr<<"bound udp port "<<ourLocal.sin4.sin_port<<", "<<tries<<" tries left"<<endl;
+
+ if(!tries) {
+ closesocket(sock);
+ throw PDNSException("Resolver binding to local UDP socket on "+ourLocal.toString()+": "+stringerror());
+ }
+ }
+ else {
+ // tcp, let the kernel figure out the port
+ // cerr<<"letting kernel pick TCP port"<<endl;
+ ourLocal.sin4.sin_port = 0;
+ if(::bind(sock, (struct sockaddr *)&ourLocal, ourLocal.getSocklen()) < 0)
+ throw PDNSException("Resolver binding to local TCP socket on "+ourLocal.toString()+": "+stringerror());
+ }
+ return sock;
+}
+
+Resolver::Resolver()
+{
+ locals["default4"] = -1;
+ locals["default6"] = -1;
+ try {
+ locals["default4"] = makeQuerySocket(ComboAddress(::arg()["query-local-address"]), true);
+ if(!::arg()["query-local-address6"].empty())
+ locals["default6"] = makeQuerySocket(ComboAddress(::arg()["query-local-address6"]), true);
+ }
+ catch(...) {
+ if(locals["default4"]>=0)
+ close(locals["default4"]);
+ throw;
+ }
+}
+
+Resolver::~Resolver()
+{
+ for(std::map<std::string,int>::iterator iter = locals.begin(); iter != locals.end(); iter++) {
+ if (iter->second >= 0)
+ close(iter->second);
+ }
+}
+
+uint16_t Resolver::sendResolve(const ComboAddress& remote, const ComboAddress& local,
+ const DNSName &domain, int type, bool dnssecOK,
+ const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
+ const string& tsigsecret)
+{
+ uint16_t randomid;
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, domain, type);
+ pw.getHeader()->id = randomid = dns_random(0xffff);
+
+ if(dnssecOK) {
+ pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
+ pw.commit();
+ }
+
+ if(!tsigkeyname.empty()) {
+ // cerr<<"Adding TSIG to notification, key name: '"<<tsigkeyname<<"', algo: '"<<tsigalgorithm<<"', secret: "<<Base64Encode(tsigsecret)<<endl;
+ TSIGRecordContent trc;
+ if (tsigalgorithm == DNSName("hmac-md5"))
+ trc.d_algoName = tsigalgorithm + DNSName("sig-alg.reg.int");
+ else
+ trc.d_algoName = tsigalgorithm;
+ trc.d_time = time(0);
+ trc.d_fudge = 300;
+ trc.d_origID=ntohs(randomid);
+ trc.d_eRcode=0;
+ addTSIG(pw, &trc, tsigkeyname, tsigsecret, "", false);
+ }
+
+ int sock;
+
+ // choose socket based on local
+ if (local.sin4.sin_family == 0) {
+ // up to us.
+ sock = remote.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
+ } else {
+ std::string lstr = local.toString();
+ std::map<std::string, int>::iterator lptr;
+ // see if there is a local
+
+ if ((lptr = locals.find(lstr)) != locals.end()) {
+ sock = lptr->second;
+ } else {
+ // try to make socket
+ sock = makeQuerySocket(local, true);
+ if (sock < 0)
+ throw ResolverException("Unable to create socket to "+remote.toStringWithPort()+": "+stringerror());
+ setNonBlocking( sock );
+ locals[lstr] = sock;
+ }
+ }
+
+ if(sendto(sock, &packet[0], packet.size(), 0, (struct sockaddr*)(&remote), remote.getSocklen()) < 0) {
+ throw ResolverException("Unable to ask query of "+remote.toStringWithPort()+": "+stringerror());
+ }
+ return randomid;
+}
+
+uint16_t Resolver::sendResolve(const ComboAddress& remote, const DNSName &domain,
+ int type, bool dnssecOK,
+ const DNSName& tsigkeyname, const DNSName& tsigalgorithm,
+ const string& tsigsecret)
+{
+ ComboAddress local;
+ local.sin4.sin_family = 0;
+ return this->sendResolve(remote, local, domain, type, dnssecOK, tsigkeyname, tsigalgorithm, tsigsecret);
+}
+
+static int parseResult(MOADNSParser& mdp, const DNSName& origQname, uint16_t origQtype, uint16_t id, Resolver::res_t* result)
+{
+ result->clear();
+
+ if(mdp.d_header.rcode)
+ return mdp.d_header.rcode;
+
+ if(origQname.countLabels()) { // not AXFR
+ if(mdp.d_header.id != id)
+ throw ResolverException("Remote nameserver replied with wrong id");
+ if(mdp.d_header.qdcount != 1)
+ throw ResolverException("resolver: received answer with wrong number of questions ("+itoa(mdp.d_header.qdcount)+")");
+ if(mdp.d_qname != origQname)
+ throw ResolverException(string("resolver: received an answer to another question (")+mdp.d_qname.toString()+"!="+ origQname.toString()+".)");
+ }
+
+ vector<DNSResourceRecord> ret;
+ DNSResourceRecord rr;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ rr.qname = i->first.d_name;
+ rr.qtype = i->first.d_type;
+ rr.ttl = i->first.d_ttl;
+ rr.content = i->first.d_content->getZoneRepresentation(true);
+ result->push_back(rr);
+ }
+
+ return 0;
+}
+
+bool Resolver::tryGetSOASerial(DNSName *domain, uint32_t *theirSerial, uint32_t *theirInception, uint32_t *theirExpire, uint16_t* id)
+{
+ struct pollfd *fds = new struct pollfd[locals.size()];
+ size_t i = 0, k;
+ int sock;
+
+ for(std::map<string,int>::iterator iter=locals.begin(); iter != locals.end(); iter++, i++) {
+ fds[i].fd = iter->second;
+ fds[i].events = POLLIN;
+ }
+
+ if (poll(fds, i, 250) < 1) { // wait for 0.25s
+ delete [] fds;
+ return false;
+ }
+
+ sock = -1;
+
+ // determine who
+ for(k=0;k<i;k++) {
+ if ((fds[k].revents & POLLIN) == POLLIN) {
+ sock = fds[k].fd;
+ break;
+ }
+ }
+
+ delete [] fds;
+
+ if (sock < 0) return false; // false alarm
+
+ int err;
+ ComboAddress fromaddr;
+ socklen_t addrlen=fromaddr.getSocklen();
+ char buf[3000];
+ err = recvfrom(sock, buf, sizeof(buf), 0,(struct sockaddr*)(&fromaddr), &addrlen);
+ if(err < 0) {
+ if(errno == EAGAIN)
+ return false;
+
+ throw ResolverException("recvfrom error waiting for answer: "+stringerror());
+ }
+
+ MOADNSParser mdp(false, (char*)buf, err);
+ *id=mdp.d_header.id;
+ *domain = mdp.d_qname;
+
+ if(mdp.d_answers.empty())
+ throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' produced no results (RCode: " + RCode::to_s(mdp.d_header.rcode) + ")");
+
+ if(mdp.d_qtype != QType::SOA)
+ throw ResolverException("Query to '" + fromaddr.toStringWithPort() + "' for SOA of '" + domain->toString() + "' returned wrong record type");
+
+ *theirInception = *theirExpire = 0;
+ bool gotSOA=false;
+ for(const MOADNSParser::answers_t::value_type& drc : mdp.d_answers) {
+ if(drc.first.d_type == QType::SOA) {
+ shared_ptr<SOARecordContent> src=getRR<SOARecordContent>(drc.first);
+ if (src) {
+ *theirSerial=src->d_st.serial;
+ gotSOA = true;
+ }
+ }
+ if(drc.first.d_type == QType::RRSIG) {
+ shared_ptr<RRSIGRecordContent> rrc=getRR<RRSIGRecordContent>(drc.first);
+ if(rrc && rrc->d_type == QType::SOA) {
+ *theirInception= std::max(*theirInception, rrc->d_siginception);
+ *theirExpire = std::max(*theirExpire, rrc->d_sigexpire);
+ }
+ }
+ }
+ if(!gotSOA)
+ throw ResolverException("Query to '" + fromaddr.toString() + "' for SOA of '" + domain->toString() + "' did not return a SOA");
+ return true;
+}
+
+int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res, const ComboAddress &local)
+{
+ try {
+ ComboAddress to(ipport, 53);
+
+ int id = sendResolve(to, local, domain, type);
+ int sock;
+
+ // choose socket based on local
+ if (local.sin4.sin_family == 0) {
+ // up to us.
+ sock = to.sin4.sin_family == AF_INET ? locals["default4"] : locals["default6"];
+ } else {
+ std::string lstr = local.toString();
+ std::map<std::string, int>::iterator lptr;
+ // see if there is a local
+
+ if ((lptr = locals.find(lstr)) != locals.end()) sock = lptr->second;
+ else throw ResolverException("sendResolve did not create socket for " + lstr);
+ }
+
+ int err=waitForData(sock, 0, 3000000);
+
+ if(!err) {
+ throw ResolverException("Timeout waiting for answer");
+ }
+ if(err < 0)
+ throw ResolverException("Error waiting for answer: "+stringerror());
+
+ ComboAddress from;
+ socklen_t addrlen = sizeof(from);
+ char buffer[3000];
+ int len;
+
+ if((len=recvfrom(sock, buffer, sizeof(buffer), 0,(struct sockaddr*)(&from), &addrlen)) < 0)
+ throw ResolverException("recvfrom error waiting for answer: "+stringerror());
+
+ MOADNSParser mdp(false, buffer, len);
+ return parseResult(mdp, domain, type, id, res);
+ }
+ catch(ResolverException &re) {
+ throw ResolverException(re.reason+" from "+ipport);
+ }
+ return -1;
+}
+
+int Resolver::resolve(const string &ipport, const DNSName &domain, int type, Resolver::res_t* res) {
+ ComboAddress local;
+ local.sin4.sin_family = 0;
+ return resolve(ipport, domain, type, res, local);
+}
+
+void Resolver::getSoaSerial(const string &ipport, const DNSName &domain, uint32_t *serial)
+{
+ vector<DNSResourceRecord> res;
+ int ret = resolve(ipport, domain, QType::SOA, &res);
+
+ if(ret || res.empty())
+ throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced no answers");
+
+ if(res[0].qtype.getCode() != QType::SOA)
+ throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced a "+res[0].qtype.getName()+" record");
+
+ vector<string>parts;
+ stringtok(parts, res[0].content);
+ if(parts.size()<3)
+ throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable response");
+
+ try {
+ *serial=pdns_stou(parts[2]);
+ }
+ catch(const std::out_of_range& oor) {
+ throw ResolverException("Query to '" + ipport + "' for SOA of '" + domain.toString() + "' produced an unparseable serial");
+ }
+}
+
+AXFRRetriever::AXFRRetriever(const ComboAddress& remote,
+ const DNSName& domain,
+ const TSIGTriplet& tt,
+ const ComboAddress* laddr,
+ size_t maxReceivedBytes)
+ : d_tsigVerifier(tt, remote, d_trc), d_receivedBytes(0), d_maxReceivedBytes(maxReceivedBytes)
+{
+ ComboAddress local;
+ if (laddr != NULL) {
+ local = (ComboAddress) (*laddr);
+ } else {
+ if(remote.sin4.sin_family == AF_INET)
+ local=ComboAddress(::arg()["query-local-address"]);
+ else if(!::arg()["query-local-address6"].empty())
+ local=ComboAddress(::arg()["query-local-address6"]);
+ else
+ local=ComboAddress("::");
+ }
+ d_sock = -1;
+ try {
+ d_sock = makeQuerySocket(local, false); // make a TCP socket
+ if (d_sock < 0)
+ throw ResolverException("Error creating socket for AXFR request to "+d_remote.toStringWithPort());
+ d_buf = shared_array<char>(new char[65536]);
+ d_remote = remote; // mostly for error reporting
+ this->connect();
+ d_soacount = 0;
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, domain, QType::AXFR);
+ pw.getHeader()->id = dns_random(0xffff);
+
+ if(!tt.name.empty()) {
+ if (tt.algo == DNSName("hmac-md5"))
+ d_trc.d_algoName = tt.algo + DNSName("sig-alg.reg.int");
+ else
+ d_trc.d_algoName = tt.algo;
+ d_trc.d_time = time(0);
+ d_trc.d_fudge = 300;
+ d_trc.d_origID=ntohs(pw.getHeader()->id);
+ d_trc.d_eRcode=0;
+ addTSIG(pw, &d_trc, tt.name, tt.secret, "", false);
+ }
+
+ uint16_t replen=htons(packet.size());
+ Utility::iovec iov[2];
+ iov[0].iov_base=reinterpret_cast<char*>(&replen);
+ iov[0].iov_len=2;
+ iov[1].iov_base=packet.data();
+ iov[1].iov_len=packet.size();
+
+ int ret=Utility::writev(d_sock, iov, 2);
+ if(ret < 0)
+ throw ResolverException("Error sending question to "+d_remote.toStringWithPort()+": "+stringerror());
+ if(ret != (int)(2+packet.size())) {
+ throw ResolverException("Partial write on AXFR request to "+d_remote.toStringWithPort());
+ }
+
+ int res = waitForData(d_sock, 10, 0);
+
+ if(!res)
+ throw ResolverException("Timeout waiting for answer from "+d_remote.toStringWithPort()+" during AXFR");
+ if(res<0)
+ throw ResolverException("Error waiting for answer from "+d_remote.toStringWithPort()+": "+stringerror());
+ }
+ catch(...) {
+ if(d_sock >= 0)
+ close(d_sock);
+ d_sock = -1;
+ throw;
+ }
+}
+
+AXFRRetriever::~AXFRRetriever()
+{
+ close(d_sock);
+}
+
+
+
+int AXFRRetriever::getChunk(Resolver::res_t &res, vector<DNSRecord>* records) // Implementation is making sure RFC2845 4.4 is followed.
+{
+ if(d_soacount > 1)
+ return false;
+
+ // d_sock is connected and is about to spit out a packet
+ int len=getLength();
+ if(len<0)
+ throw ResolverException("EOF trying to read axfr chunk from remote TCP client");
+
+ if (d_maxReceivedBytes > 0 && (d_maxReceivedBytes - d_receivedBytes) < (size_t) len)
+ throw ResolverException("Reached the maximum number of received bytes during AXFR");
+
+ timeoutReadn(len);
+
+ d_receivedBytes += (uint16_t) len;
+
+ MOADNSParser mdp(false, d_buf.get(), len);
+
+ int err;
+ if(!records)
+ err=parseResult(mdp, DNSName(), 0, 0, &res);
+ else {
+ records->clear();
+ for(const auto& r: mdp.d_answers)
+ records->push_back(r.first);
+ err = mdp.d_header.rcode;
+ }
+
+ if(err)
+ throw ResolverException("AXFR chunk error: " + RCode::to_s(err));
+
+ for(const MOADNSParser::answers_t::value_type& answer : mdp.d_answers)
+ if (answer.first.d_type == QType::SOA)
+ d_soacount++;
+
+ try {
+ d_tsigVerifier.check(std::string(d_buf.get(), len), mdp);
+ }
+ catch(const std::runtime_error& re) {
+ throw ResolverException(re.what());
+ }
+
+ return true;
+}
+
+void AXFRRetriever::timeoutReadn(uint16_t bytes)
+{
+ time_t start=time(0);
+ int n=0;
+ int numread;
+ while(n<bytes) {
+ int res=waitForData(d_sock, 10-(time(0)-start));
+ if(res<0)
+ throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
+ if(!res)
+ throw ResolverException("Timeout while reading data from remote nameserver over TCP");
+
+ numread=recv(d_sock, d_buf.get()+n, bytes-n, 0);
+ if(numread<0)
+ throw ResolverException("Reading data from remote nameserver over TCP: "+stringerror());
+ if(numread==0)
+ throw ResolverException("Remote nameserver closed TCP connection");
+ n+=numread;
+ }
+}
+
+void AXFRRetriever::connect()
+{
+ setNonBlocking( d_sock );
+
+ int err;
+
+ if((err=::connect(d_sock,(struct sockaddr*)&d_remote, d_remote.getSocklen()))<0 && errno!=EINPROGRESS) {
+ try {
+ closesocket(d_sock);
+ }
+ catch(const PDNSException& e) {
+ d_sock=-1;
+ throw ResolverException("Error closing AXFR socket after connect() failed: "+e.reason);
+ }
+
+ throw ResolverException("connect: "+stringerror());
+ }
+
+ if(!err)
+ goto done;
+
+ err=waitForRWData(d_sock, false, 10, 0); // wait for writeability
+
+ if(!err) {
+ try {
+ closesocket(d_sock); // timeout
+ }
+ catch(const PDNSException& e) {
+ d_sock=-1;
+ throw ResolverException("Error closing AXFR socket after timeout: "+e.reason);
+ }
+
+ d_sock=-1;
+ errno=ETIMEDOUT;
+
+ throw ResolverException("Timeout connecting to server");
+ }
+ else if(err < 0) {
+ throw ResolverException("Error connecting: "+string(strerror(err)));
+ }
+ else {
+ Utility::socklen_t len=sizeof(err);
+ if(getsockopt(d_sock, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
+ throw ResolverException("Error connecting: "+stringerror()); // Solaris
+
+ if(err)
+ throw ResolverException("Error connecting: "+string(strerror(err)));
+ }
+
+ done:
+ setBlocking( d_sock );
+ // d_sock now connected
+}
+
+int AXFRRetriever::getLength()
+{
+ timeoutReadn(2);
+ return (unsigned char)d_buf[0]*256+(unsigned char)d_buf[1];
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_RESOLVER_HH
+#define PDNS_RESOLVER_HH
+
+#include <string>
+#include <vector>
+#include <sys/types.h>
+#include "iputils.hh"
+#include <netdb.h>
+#include <unistd.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#undef res_mkquery
+
+#include "pdnsexception.hh"
+#include "dns.hh"
+#include "namespaces.hh"
+#include "dnsrecords.hh"
+#include "dnssecinfra.hh"
+#include "tsigverifier.hh"
+
+class ResolverException : public PDNSException
+{
+public:
+ ResolverException(const string &reason) : PDNSException(reason){}
+};
+
+// make an IPv4 or IPv6 query socket
+int makeQuerySocket(const ComboAddress& local, bool udpOrTCP);
+//! Resolver class. Can be used synchronously and asynchronously, over IPv4 and over IPv6 (simultaneously)
+class Resolver : public boost::noncopyable
+{
+public:
+ Resolver();
+ ~Resolver();
+
+ typedef vector<DNSResourceRecord> res_t;
+ //! synchronously resolve domain|type at IP, store result in result, rcode in ret
+ int resolve(const string &ip, const DNSName &domain, int type, res_t* result, const ComboAddress& local);
+
+ int resolve(const string &ip, const DNSName &domain, int type, res_t* result);
+
+ //! only send out a resolution request
+ uint16_t sendResolve(const ComboAddress& remote, const ComboAddress& local, const DNSName &domain, int type, bool dnssecOk=false,
+ const DNSName& tsigkeyname=DNSName(), const DNSName& tsigalgorithm=DNSName(), const string& tsigsecret="");
+
+ uint16_t sendResolve(const ComboAddress& remote, const DNSName &domain, int type, bool dnssecOk=false,
+ const DNSName& tsigkeyname=DNSName(), const DNSName& tsigalgorithm=DNSName(), const string& tsigsecret="");
+
+ //! see if we got a SOA response from our sendResolve
+ bool tryGetSOASerial(DNSName *theirDomain, uint32_t* theirSerial, uint32_t* theirInception, uint32_t* theirExpire, uint16_t* id);
+
+ //! convenience function that calls resolve above
+ void getSoaSerial(const string &, const DNSName &, uint32_t *);
+
+private:
+ std::map<std::string, int> locals;
+};
+
+class AXFRRetriever : public boost::noncopyable
+{
+ public:
+ AXFRRetriever(const ComboAddress& remote,
+ const DNSName& zone,
+ const TSIGTriplet& tt = TSIGTriplet(),
+ const ComboAddress* laddr = NULL,
+ size_t maxReceivedBytes=0);
+ ~AXFRRetriever();
+ int getChunk(Resolver::res_t &res, vector<DNSRecord>* records=0);
+
+ private:
+ void connect();
+ int getLength();
+ void timeoutReadn(uint16_t bytes);
+
+ shared_array<char> d_buf;
+ string d_domain;
+ int d_sock;
+ int d_soacount;
+ ComboAddress d_remote;
+ TSIGTCPVerifier d_tsigVerifier;
+
+ size_t d_receivedBytes;
+ size_t d_maxReceivedBytes;
+ TSIGRecordContent d_trc;
+};
+
+
+#endif /* PDNS_RESOLVER_HH */
--- /dev/null
+#include "responsestats.hh"
+#include "dnspacket.hh"
+#include "statbag.hh"
+
+extern StatBag S;
+/**
+ * Function that creates all the stats
+ * when udpOrTCP is true, it is udp
+ */
+void ResponseStats::submitResponse(DNSPacket &p, bool udpOrTCP) {
+ const string& buf=p.getString();
+ static AtomicCounter &udpnumanswered=*S.getPointer("udp-answers");
+ static AtomicCounter &udpnumanswered4=*S.getPointer("udp4-answers");
+ static AtomicCounter &udpnumanswered6=*S.getPointer("udp6-answers");
+ static AtomicCounter &udpbytesanswered=*S.getPointer("udp-answers-bytes");
+ static AtomicCounter &udpbytesanswered4=*S.getPointer("udp4-answers-bytes");
+ static AtomicCounter &udpbytesanswered6=*S.getPointer("udp6-answers-bytes");
+ static AtomicCounter &tcpnumanswered=*S.getPointer("tcp-answers");
+ static AtomicCounter &tcpnumanswered4=*S.getPointer("tcp4-answers");
+ static AtomicCounter &tcpnumanswered6=*S.getPointer("tcp6-answers");
+ static AtomicCounter &tcpbytesanswered=*S.getPointer("tcp-answers-bytes");
+ static AtomicCounter &tcpbytesanswered4=*S.getPointer("tcp4-answers-bytes");
+ static AtomicCounter &tcpbytesanswered6=*S.getPointer("tcp6-answers-bytes");
+
+ if(p.d.aa) {
+ if (p.d.rcode==RCode::NXDomain)
+ S.ringAccount("nxdomain-queries",p.qdomain.toLogString()+"/"+p.qtype.getName());
+ } else if (p.isEmpty()) {
+ S.ringAccount("unauth-queries",p.qdomain.toLogString()+"/"+p.qtype.getName());
+ S.ringAccount("remotes-unauth",p.d_remote);
+ }
+
+ if (udpOrTCP) { // udp
+ udpnumanswered++;
+ udpbytesanswered+=buf.length();
+ if(p.d_remote.sin4.sin_family==AF_INET) {
+ udpnumanswered4++;
+ udpbytesanswered4+=buf.length();
+ } else {
+ udpnumanswered6++;
+ udpbytesanswered6+=buf.length();
+ }
+ } else { //tcp
+ tcpnumanswered++;
+ tcpbytesanswered+=buf.length();
+ if(p.d_remote.sin4.sin_family==AF_INET) {
+ tcpnumanswered4++;
+ tcpbytesanswered4+=buf.length();
+ } else {
+ tcpnumanswered6++;
+ tcpbytesanswered6+=buf.length();
+ }
+ }
+
+ submitResponse(p.qtype.getCode(), buf.length(), udpOrTCP);
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "responsestats.hh"
+#include <limits>
+#include "namespaces.hh"
+#include "logger.hh"
+
+#include "dnsparser.hh"
+
+ResponseStats::ResponseStats() : d_qtypecounters(new std::atomic<unsigned long>[65536])
+{
+ d_sizecounters.push_back(make_pair(20,0));
+ d_sizecounters.push_back(make_pair(40,0));
+ d_sizecounters.push_back(make_pair(60,0));
+ d_sizecounters.push_back(make_pair(80,0));
+ d_sizecounters.push_back(make_pair(100,0));
+ d_sizecounters.push_back(make_pair(150,0));
+ for(int n=200; n < 65000 ; n+=200)
+ d_sizecounters.push_back(make_pair(n,0));
+ d_sizecounters.push_back(make_pair(std::numeric_limits<uint16_t>::max(),0));
+}
+
+ResponseStats g_rs;
+
+static bool pcomp(const pair<uint16_t, uint64_t>&a , const pair<uint16_t, uint64_t>&b)
+{
+ return a.first < b.first;
+}
+
+void ResponseStats::submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP)
+{
+ d_qtypecounters[qtype]++;
+ pair<uint16_t, uint64_t> s(respsize, 0);
+ sizecounters_t::iterator iter = std::upper_bound(d_sizecounters.begin(), d_sizecounters.end(), s, pcomp);
+ if(iter!= d_sizecounters.begin())
+ --iter;
+ iter->second++;
+}
+
+map<uint16_t, uint64_t> ResponseStats::getQTypeResponseCounts()
+{
+ map<uint16_t, uint64_t> ret;
+ uint64_t count;
+ for(unsigned int i = 0 ; i < 65535 ; ++i) {
+ count= d_qtypecounters[i];
+ if(count)
+ ret[i]=count;
+ }
+ return ret;
+}
+
+map<uint16_t, uint64_t> ResponseStats::getSizeResponseCounts()
+{
+ map<uint16_t, uint64_t> ret;
+ for(sizecounters_t::const_iterator iter = d_sizecounters.begin();
+ iter != d_sizecounters.end();
+ ++iter) {
+ ret[iter->first]=iter->second;
+ }
+ return ret;
+}
+
+string ResponseStats::getQTypeReport()
+{
+ typedef map<uint16_t, uint64_t> qtypenums_t;
+ qtypenums_t qtypenums = getQTypeResponseCounts();
+ ostringstream os;
+ boost::format fmt("%s\t%d\n");
+ for(const qtypenums_t::value_type& val : qtypenums) {
+ os << (fmt %DNSRecordContent::NumberToType( val.first) % val.second).str();
+ }
+ return os.str();
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "misc.hh"
+#include "dnspacket.hh"
+
+class ResponseStats
+{
+public:
+ ResponseStats();
+
+ void submitResponse(DNSPacket &p, bool udpOrTCP);
+ void submitResponse(uint16_t qtype, uint16_t respsize, bool udpOrTCP);
+ map<uint16_t, uint64_t> getQTypeResponseCounts();
+ map<uint16_t, uint64_t> getSizeResponseCounts();
+ string getQTypeReport();
+
+private:
+ boost::scoped_array<std::atomic<unsigned long>> d_qtypecounters;
+ typedef vector<pair<uint16_t, uint64_t> > sizecounters_t;
+ sizecounters_t d_sizecounters;
+};
+
+extern ResponseStats g_rs;
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packethandler.hh"
+#include "qtype.hh"
+#include "dnspacket.hh"
+#include "packetcache.hh"
+#include "dnsseckeeper.hh"
+#include "base64.hh"
+#include "base32.hh"
+
+#include "misc.hh"
+#include "arguments.hh"
+#include "resolver.hh"
+#include "dns_random.hh"
+#include "backends/gsql/ssql.hh"
+#include "communicator.hh"
+
+extern PacketCache PC;
+extern StatBag S;
+extern CommunicatorClass Communicator;
+
+pthread_mutex_t PacketHandler::s_rfc2136lock=PTHREAD_MUTEX_INITIALIZER;
+
+// Implement section 3.2.1 and 3.2.2 of RFC2136
+int PacketHandler::checkUpdatePrerequisites(const DNSRecord *rr, DomainInfo *di) {
+ if (rr->d_ttl != 0)
+ return RCode::FormErr;
+
+ // 3.2.1 and 3.2.2 check content length.
+ if ( (rr->d_class == QClass::NONE || rr->d_class == QClass::ANY) && rr->d_clen != 0)
+ return RCode::FormErr;
+
+ bool foundRecord=false;
+ DNSResourceRecord rec;
+ di->backend->lookup(QType(QType::ANY), rr->d_name);
+ while(di->backend->get(rec)) {
+ if (!rec.qtype.getCode())
+ continue;
+ if ((rr->d_type != QType::ANY && rec.qtype == rr->d_type) || rr->d_type == QType::ANY)
+ foundRecord=true;
+ }
+
+ // Section 3.2.1
+ if (rr->d_class == QClass::ANY && !foundRecord) {
+ if (rr->d_type == QType::ANY)
+ return RCode::NXDomain;
+ if (rr->d_type != QType::ANY)
+ return RCode::NXRRSet;
+ }
+
+ // Section 3.2.2
+ if (rr->d_class == QClass::NONE && foundRecord) {
+ if (rr->d_type == QType::ANY)
+ return RCode::YXDomain;
+ if (rr->d_type != QType::ANY)
+ return RCode::YXRRSet;
+ }
+
+ return RCode::NoError;
+}
+
+
+// Method implements section 3.4.1 of RFC2136
+int PacketHandler::checkUpdatePrescan(const DNSRecord *rr) {
+ // The RFC stats that d_class != ZCLASS, but we only support the IN class.
+ if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
+ return RCode::FormErr;
+
+ QType qtype = QType(rr->d_type);
+
+ if (! qtype.isSupportedType())
+ return RCode::FormErr;
+
+ if ((rr->d_class == QClass::NONE || rr->d_class == QClass::ANY) && rr->d_ttl != 0)
+ return RCode::FormErr;
+
+ if (rr->d_class == QClass::ANY && rr->d_clen != 0)
+ return RCode::FormErr;
+
+ if (qtype.isMetadataType())
+ return RCode::FormErr;
+
+ if (rr->d_class != QClass::ANY && qtype.getCode() == QType::ANY)
+ return RCode::FormErr;
+
+ return RCode::NoError;
+}
+
+
+// Implements section 3.4.2 of RFC2136
+uint PacketHandler::performUpdate(const string &msgPrefix, const DNSRecord *rr, DomainInfo *di, bool isPresigned, bool* narrow, bool* haveNSEC3, NSEC3PARAMRecordContent *ns3pr, bool *updatedSerial) {
+
+ QType rrType = QType(rr->d_type);
+
+ if (rrType == QType::NSEC || rrType == QType::NSEC3) {
+ L<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<". These are generated records, ignoring!"<<endl;
+ return 0;
+ }
+
+ if (!isPresigned && ((!::arg().mustDo("direct-dnskey") && rrType == QType::DNSKEY) || rrType == QType::RRSIG)) {
+ L<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<" in non-presigned zone, ignoring!"<<endl;
+ return 0;
+ }
+
+ if ((rrType == QType::NSEC3PARAM || rrType == QType::DNSKEY) && rr->d_name != di->zone) {
+ L<<Logger::Warning<<msgPrefix<<"Trying to add/update/delete "<<rr->d_name<<"|"<<rrType.getName()<<", "<<rrType.getName()<<" must be at zone apex, ignoring!"<<endl;
+ return 0;
+ }
+
+
+ uint changedRecords = 0;
+ DNSResourceRecord rec;
+ vector<DNSResourceRecord> rrset, recordsToDelete;
+ set<DNSName> delnonterm, insnonterm; // used to (at the end) fix ENT records.
+
+
+ if (rr->d_class == QClass::IN) { // 3.4.2.2 QClass::IN means insert or update
+ DLOG(L<<msgPrefix<<"Add/Update record (QClass == IN) "<<rr->d_name<<"|"<<rrType.getName()<<endl);
+
+ if (rrType == QType::NSEC3PARAM) {
+ L<<Logger::Notice<<msgPrefix<<"Adding/updating NSEC3PARAM for zone, resetting ordernames."<<endl;
+
+ NSEC3PARAMRecordContent nsec3param(rr->d_content->getZoneRepresentation(), di->zone.toString() /* FIXME400 huh */);
+ *narrow = false; // adding a NSEC3 will cause narrow mode to be dropped, as you cannot specify that in a NSEC3PARAM record
+ d_dk.setNSEC3PARAM(di->zone, nsec3param, (*narrow));
+
+ *haveNSEC3 = d_dk.getNSEC3PARAM(di->zone, ns3pr, narrow);
+
+ vector<DNSResourceRecord> rrs;
+ set<DNSName> qnames, nssets, dssets;
+ di->backend->list(di->zone, di->id);
+ while (di->backend->get(rec)) {
+ qnames.insert(rec.qname);
+ if(rec.qtype.getCode() == QType::NS && rec.qname != di->zone)
+ nssets.insert(rec.qname);
+ if(rec.qtype.getCode() == QType::DS)
+ dssets.insert(rec.qname);
+ }
+
+ DNSName shorter;
+ for(const auto& qname: qnames) {
+ shorter = qname;
+ int ddepth = 0;
+ do {
+ if(qname == di->zone)
+ break;
+ if(nssets.count(shorter))
+ ++ddepth;
+ } while(shorter.chopOff());
+
+ DNSName ordername = DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, qname))) + di->zone;
+ if (! *narrow && (ddepth == 0 || (ddepth == 1 && nssets.count(qname)))) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, ordername, (ddepth == 0 ));
+
+ if (nssets.count(qname)) {
+ if (ns3pr->d_flags)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), false, QType::NS );
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), false, QType::AAAA);
+ }
+ } else {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), (ddepth == 0));
+ }
+ if (ddepth == 1 || dssets.count(qname)) // FIXME400 && ?
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, ordername, false, QType::DS);
+ }
+ return 1;
+ }
+
+
+
+ bool foundRecord = false;
+ di->backend->lookup(rrType, rr->d_name);
+ while (di->backend->get(rec)) {
+ rrset.push_back(rec);
+ foundRecord = true;
+ }
+
+ if (foundRecord) {
+
+ if (rrType == QType::SOA) { // SOA updates require the serial to be higher than the current
+ SOAData sdOld, sdUpdate;
+ DNSResourceRecord *oldRec = &rrset.front();
+ fillSOAData(oldRec->content, sdOld);
+ oldRec->setContent(rr->d_content->getZoneRepresentation());
+ fillSOAData(oldRec->content, sdUpdate);
+ if (rfc1982LessThan(sdOld.serial, sdUpdate.serial)) {
+ di->backend->replaceRRSet(di->id, oldRec->qname, oldRec->qtype, rrset);
+ *updatedSerial = true;
+ changedRecords++;
+ L<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
+ } else {
+ L<<Logger::Notice<<msgPrefix<<"Provided serial ("<<sdUpdate.serial<<") is older than the current serial ("<<sdOld.serial<<"), ignoring SOA update."<<endl;
+ }
+
+ // It's not possible to have multiple CNAME's with the same NAME. So we always update.
+ } else if (rrType == QType::CNAME) {
+ int changedCNames = 0;
+ for (vector<DNSResourceRecord>::iterator i = rrset.begin(); i != rrset.end(); i++) {
+ if (i->ttl != rr->d_ttl || i->content != rr->d_content->getZoneRepresentation()) {
+ i->ttl = rr->d_ttl;
+ i->setContent(rr->d_content->getZoneRepresentation());
+ changedCNames++;
+ }
+ }
+ if (changedCNames > 0) {
+ di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
+ L<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
+ changedRecords += changedCNames;
+ } else {
+ L<<Logger::Notice<<msgPrefix<<"Replace for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but no changes made."<<endl;
+ }
+
+ // In any other case, we must check if the TYPE and RDATA match to provide an update (which effectily means a update of TTL)
+ } else {
+ int updateTTL=0;
+ foundRecord = false;
+ for (vector<DNSResourceRecord>::iterator i = rrset.begin(); i != rrset.end(); i++) {
+ string content = rr->d_content->getZoneRepresentation();
+ if (rrType == i->qtype.getCode() && i->getZoneRepresentation() == content) {
+ foundRecord=true;
+ if (i->ttl != rr->d_ttl) {
+ i->ttl = rr->d_ttl;
+ updateTTL++;
+ }
+ }
+ }
+ if (updateTTL > 0) {
+ di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
+ L<<Logger::Notice<<msgPrefix<<"Replacing record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
+ changedRecords += updateTTL;
+ } else {
+ L<<Logger::Notice<<msgPrefix<<"Replace for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but no changes made."<<endl;
+ }
+ }
+
+ // ReplaceRRSet dumps our ordername and auth flag, so we need to correct it if we have changed records.
+ // We can take the auth flag from the first RR in the set, as the name is different, so should the auth be.
+ if (changedRecords > 0) {
+ bool auth = rrset.front().auth;
+
+ if(*haveNSEC3) {
+ DNSName ordername;
+ if(! *narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, rr->d_name)))+di->zone;
+
+ if (*narrow)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), auth);
+ else
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, ordername, auth);
+ if(!auth || rrType == QType::DS) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::NS);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::AAAA);
+ }
+
+ } else { // NSEC
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, rr->d_name, auth);
+ if(!auth || rrType == QType::DS) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::AAAA);
+ }
+ }
+ }
+
+ } // if (foundRecord)
+
+ // If we haven't found a record that matches, we must add it.
+ if (! foundRecord) {
+ L<<Logger::Notice<<msgPrefix<<"Adding record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
+ delnonterm.insert(rr->d_name); // always remove any ENT's in the place where we're going to add a record.
+ DNSResourceRecord newRec(*rr);
+ newRec.domain_id = di->id;
+ newRec.auth = (rr->d_name == di->zone || rrType.getCode() != QType::NS);
+ di->backend->feedRecord(newRec);
+ changedRecords++;
+
+
+ // because we added a record, we need to fix DNSSEC data.
+ DNSName shorter(rr->d_name);
+ bool auth=newRec.auth;
+ bool fixDS = (rrType == QType::DS);
+
+ if (di->zone != shorter) { // Everything at APEX is auth=1 && no ENT's
+ do {
+
+ if (di->zone == shorter)
+ break;
+
+ bool foundShorter = false;
+ di->backend->lookup(QType(QType::ANY), shorter);
+ while (di->backend->get(rec)) {
+ if (rec.qname == rr->d_name && rec.qtype == QType::DS)
+ fixDS = true;
+ if (shorter != rr->d_name)
+ foundShorter = true;
+ if (rec.qtype == QType::NS) // are we inserting below a delegate?
+ auth=false;
+ }
+
+ if (!foundShorter && auth && shorter != rr->d_name) // haven't found any record at current level, insert ENT.
+ insnonterm.insert(shorter);
+ if (foundShorter)
+ break; // if we find a shorter record, we can stop searching
+ } while(shorter.chopOff());
+ }
+
+ if(*haveNSEC3)
+ {
+ DNSName ordername;
+ if(! *narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, rr->d_name)))+di->zone;
+
+ if (*narrow)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), auth);
+ else
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, ordername, auth);
+
+ if (fixDS)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, ordername, true, QType::DS);
+
+ if(!auth)
+ {
+ if (ns3pr->d_flags)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::NS);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::AAAA);
+ }
+ }
+ else // NSEC
+ {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, rr->d_name, auth);
+ if (fixDS) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, rr->d_name, true, QType::DS);
+ }
+ if(!auth) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), false, QType::AAAA);
+ }
+ }
+
+
+ // If we insert an NS, all the records below it become non auth - so, we're inserting a delegate.
+ // Auth can only be false when the rr->d_name is not the zone
+ if (auth == false && rrType == QType::NS) {
+ DLOG(L<<msgPrefix<<"Going to fix auth flags below "<<rr->d_name<<endl);
+ insnonterm.clear(); // No ENT's are needed below delegates (auth=0)
+ vector<DNSName> qnames;
+ di->backend->listSubZone(rr->d_name, di->id);
+ while(di->backend->get(rec)) {
+ if (rec.qtype.getCode() && rec.qtype.getCode() != QType::DS && rr->d_name != rec.qname) // Skip ENT, DS and our already corrected record.
+ qnames.push_back(rec.qname);
+ }
+ for(vector<DNSName>::const_iterator qname=qnames.begin(); qname != qnames.end(); ++qname) {
+ if(*haveNSEC3) {
+ DNSName ordername;
+ if(! *narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, *qname)))+di->zone;
+
+ if (*narrow)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, rr->d_name, DNSName(), auth); // FIXME400 no *qname here?
+ else
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, *qname, ordername, auth);
+
+ if (ns3pr->d_flags)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, *qname, DNSName(), false, QType::NS);
+ }
+ else // NSEC
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, *qname, *qname, false, QType::NS);
+
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, *qname, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, *qname, DNSName(), false, QType::AAAA);
+ }
+ }
+ }
+ } // rr->d_class == QClass::IN
+
+
+ // Delete records - section 3.4.2.3 and 3.4.2.4 with the exception of the 'always leave 1 NS rule' as that's handled by
+ // the code that calls this performUpdate().
+ if ((rr->d_class == QClass::ANY || rr->d_class == QClass::NONE) && rrType != QType::SOA) { // never delete a SOA.
+ DLOG(L<<msgPrefix<<"Deleting records: "<<rr->d_name<<"; QClasse:"<<rr->d_class<<"; rrType: "<<rrType.getName()<<endl);
+
+ if (rrType == QType::NSEC3PARAM) {
+ L<<Logger::Notice<<msgPrefix<<"Deleting NSEC3PARAM from zone, resetting ordernames."<<endl;
+ if (rr->d_class == QClass::ANY)
+ d_dk.unsetNSEC3PARAM(rr->d_name);
+ else if (rr->d_class == QClass::NONE) {
+ NSEC3PARAMRecordContent nsec3rr(rr->d_content->getZoneRepresentation(), di->zone.toString() /* FIXME400 huh */);
+ if (ns3pr->getZoneRepresentation() == nsec3rr.getZoneRepresentation())
+ d_dk.unsetNSEC3PARAM(rr->d_name);
+ else
+ return 0;
+ } else
+ return 0;
+
+ // We retrieve new values, other RR's in this update package might need it as well.
+ *haveNSEC3 = d_dk.getNSEC3PARAM(di->zone, ns3pr, narrow);
+
+ vector<DNSResourceRecord> rrs;
+ set<DNSName> qnames, nssets, dssets, ents;
+ di->backend->list(di->zone, di->id);
+ while (di->backend->get(rec)) {
+ qnames.insert(rec.qname);
+ if(rec.qtype.getCode() == QType::NS && rec.qname != di->zone)
+ nssets.insert(rec.qname);
+ if(rec.qtype.getCode() == QType::DS)
+ dssets.insert(rec.qname);
+ if(!rec.qtype.getCode())
+ ents.insert(rec.qname);
+ }
+
+ DNSName shorter;
+ string hashed;
+ for(const DNSName& qname : qnames) {
+ shorter = qname;
+ int ddepth = 0;
+ do {
+ if(qname == di->zone)
+ break;
+ if(nssets.count(shorter))
+ ++ddepth;
+ } while(shorter.chopOff());
+
+ if (!ents.count(qname) && (ddepth == 0 || (ddepth == 1 && nssets.count(qname)))) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, qname, (ddepth == 0));
+
+ if (nssets.count(qname)) {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), false, QType::A);
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), false, QType::AAAA);
+ }
+ } else {
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, DNSName(), (ddepth == 0));
+ }
+ if (ddepth == 1 || dssets.count(qname))
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, qname, qname, true, QType::DS);
+ }
+ return 1;
+ } // end of NSEC3PARAM delete block
+
+
+ di->backend->lookup(rrType, rr->d_name);
+ while(di->backend->get(rec)) {
+ if (rr->d_class == QClass::ANY) { // 3.4.2.3
+ if (rec.qname == di->zone && (rec.qtype == QType::NS || rec.qtype == QType::SOA)) // Never delete all SOA and NS's
+ rrset.push_back(rec);
+ else
+ recordsToDelete.push_back(rec);
+ }
+ if (rr->d_class == QClass::NONE) { // 3.4.2.4
+ if (rrType == rec.qtype && rec.getZoneRepresentation() == rr->d_content->getZoneRepresentation())
+ recordsToDelete.push_back(rec);
+ else
+ rrset.push_back(rec);
+ }
+ }
+
+ if (recordsToDelete.size()) {
+ di->backend->replaceRRSet(di->id, rr->d_name, rrType, rrset);
+ L<<Logger::Notice<<msgPrefix<<"Deleting record "<<rr->d_name<<"|"<<rrType.getName()<<endl;
+ changedRecords += recordsToDelete.size();
+
+
+ // If we've removed a delegate, we need to reset ordername/auth for some records.
+ if (rrType == QType::NS && rr->d_name != di->zone) {
+ vector<DNSName> belowOldDelegate, nsRecs, updateAuthFlag;
+ di->backend->listSubZone(rr->d_name, di->id);
+ while (di->backend->get(rec)) {
+ if (rec.qtype.getCode()) // skip ENT records, they are always auth=false
+ belowOldDelegate.push_back(rec.qname);
+ if (rec.qtype.getCode() == QType::NS && rec.qname != rr->d_name)
+ nsRecs.push_back(rec.qname);
+ }
+
+ for(auto &belowOldDel: belowOldDelegate)
+ {
+ bool isBelowDelegate = false;
+ for(const auto & ns: nsRecs) {
+ if (ns.isPartOf(belowOldDel)) {
+ isBelowDelegate=true;
+ break;
+ }
+ }
+ if (!isBelowDelegate)
+ updateAuthFlag.push_back(belowOldDel);
+ }
+
+ for (const auto &changeRec:updateAuthFlag) {
+ if(*haveNSEC3) {
+ DNSName ordername;
+ if(! *narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, changeRec)))+di->zone;
+
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, changeRec, ordername, true);
+ }
+ else // NSEC
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, changeRec, changeRec, true);
+ }
+ }
+
+ // Fix ENT records.
+ // We must check if we have a record below the current level and if we removed the 'last' record
+ // on that level. If so, we must insert an ENT record.
+ // We take extra care here to not 'include' the record that we just deleted. Some backends will still return it as they only reload on a commit.
+ bool foundDeeper = false, foundOtherWithSameName = false;
+ di->backend->listSubZone(rr->d_name, di->id);
+ while (di->backend->get(rec)) {
+ if (rec.qname == rr->d_name && !count(recordsToDelete.begin(), recordsToDelete.end(), rec))
+ foundOtherWithSameName = true;
+ if (rec.qname != rr->d_name && rec.qtype.getCode() != QType::NS) //Skip NS records, as this would be a delegate that we can ignore as this does not require us to create a ENT
+ foundDeeper = true;
+ }
+
+ if (foundDeeper && !foundOtherWithSameName) {
+ insnonterm.insert(rr->d_name);
+ } else if (!foundOtherWithSameName) {
+ // If we didn't have to insert an ENT, we might have deleted a record at very deep level
+ // and we must then clean up the ENT's above the deleted record.
+ DNSName shorter(rr->d_name);
+ while (shorter != di->zone) {
+ shorter.chopOff();
+ bool foundRealRR = false;
+ bool foundEnt = false;
+
+ // The reason for a listSubZone here is because might go up the tree and find the ENT of another branch
+ // consider these non ENT-records:
+ // b.c.d.e.test.com
+ // b.d.e.test.com
+ // if we delete b.c.d.e.test.com, we go up to d.e.test.com and then find b.d.e.test.com because that's below d.e.test.com.
+ // At that point we can stop deleting ENT's because the tree is in tact again.
+ di->backend->listSubZone(shorter, di->id);
+
+ while (di->backend->get(rec)) {
+ if (rec.qtype.getCode())
+ foundRealRR = true;
+ else
+ foundEnt = true;
+ }
+ if (!foundRealRR) {
+ if (foundEnt) // only delete the ENT if we actually found one.
+ delnonterm.insert(shorter);
+ } else
+ break;
+ }
+ }
+ } else { // if (recordsToDelete.size())
+ L<<Logger::Notice<<msgPrefix<<"Deletion for record "<<rr->d_name<<"|"<<rrType.getName()<<" requested, but not found."<<endl;
+ }
+ } // (End of delete block d_class == ANY || d_class == NONE
+
+
+
+ //Insert and delete ENT's
+ if (insnonterm.size() > 0 || delnonterm.size() > 0) {
+ DLOG(L<<msgPrefix<<"Updating ENT records - "<<insnonterm.size()<<"|"<<delnonterm.size()<<endl);
+ di->backend->updateEmptyNonTerminals(di->id, di->zone, insnonterm, delnonterm, false);
+ for (const auto &i: insnonterm) {
+ string hashed;
+ if(*haveNSEC3)
+ {
+ DNSName ordername;
+ if(! *narrow)
+ ordername=DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, i)))+di->zone;
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, i, ordername, true);
+ }
+ }
+ }
+
+ return changedRecords;
+}
+
+int PacketHandler::forwardPacket(const string &msgPrefix, DNSPacket *p, DomainInfo *di) {
+ vector<string> forward;
+ B.getDomainMetadata(p->qdomain, "FORWARD-DNSUPDATE", forward);
+
+ if (forward.size() == 0 && ! ::arg().mustDo("forward-dnsupdate")) {
+ L<<Logger::Notice<<msgPrefix<<"Not configured to forward to master, returning Refused."<<endl;
+ return RCode::Refused;
+ }
+
+ for(vector<string>::const_iterator master=di->masters.begin(); master != di->masters.end(); master++) {
+ L<<Logger::Notice<<msgPrefix<<"Forwarding packet to master "<<*master<<endl;
+ ComboAddress remote;
+ try {
+ remote = ComboAddress(*master, 53);
+ }
+ catch (...) {
+ L<<Logger::Error<<msgPrefix<<"Failed to parse "<<*master<<" as valid remote."<<endl;
+ continue;
+ }
+
+ ComboAddress local;
+ if(remote.sin4.sin_family == AF_INET)
+ local = ComboAddress(::arg()["query-local-address"]);
+ else if(!::arg()["query-local-address6"].empty())
+ local = ComboAddress(::arg()["query-local-address6"]);
+ else
+ local = ComboAddress("::");
+ int sock = makeQuerySocket(local, false); // create TCP socket. RFC2136 section 6.2 seems to be ok with this.
+ if(sock < 0) {
+ L<<Logger::Error<<msgPrefix<<"Error creating socket: "<<stringerror()<<endl;
+ continue;
+ }
+
+ if( connect(sock, (struct sockaddr*)&remote, remote.getSocklen()) < 0 ) {
+ L<<Logger::Error<<msgPrefix<<"Failed to connect to "<<remote.toStringWithPort()<<": "<<stringerror()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after connect() failed: "<<e.reason<<endl;
+ }
+ continue;
+ }
+
+ DNSPacket forwardPacket(*p);
+ forwardPacket.setID(dns_random(0xffff));
+ forwardPacket.setRemote(&remote);
+ uint16_t len=htons(forwardPacket.getString().length());
+ string buffer((const char*)&len, 2);
+ buffer.append(forwardPacket.getString());
+ if(write(sock, buffer.c_str(), buffer.length()) < 0) {
+ L<<Logger::Error<<msgPrefix<<"Unable to forward update message to "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after write() failed: "<<e.reason<<endl;
+ }
+ continue;
+ }
+
+ int res = waitForData(sock, 10, 0);
+ if (!res) {
+ L<<Logger::Error<<msgPrefix<<"Timeout waiting for reply from master at "<<remote.toStringWithPort()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after a timeout occured: "<<e.reason<<endl;
+ }
+ continue;
+ }
+ if (res < 0) {
+ L<<Logger::Error<<msgPrefix<<"Error waiting for answer from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after an error occured: "<<e.reason<<endl;
+ }
+ continue;
+ }
+
+ unsigned char lenBuf[2];
+ ssize_t recvRes;
+ recvRes = recv(sock, &lenBuf, sizeof(lenBuf), 0);
+ if (recvRes < 0 || static_cast<size_t>(recvRes) < sizeof(lenBuf)) {
+ L<<Logger::Error<<msgPrefix<<"Could not receive data (length) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
+ }
+ continue;
+ }
+ size_t packetLen = lenBuf[0]*256+lenBuf[1];
+
+ char buf[packetLen];
+ recvRes = recv(sock, &buf, packetLen, 0);
+ if (recvRes < 0) {
+ L<<Logger::Error<<msgPrefix<<"Could not receive data (dnspacket) from master at "<<remote.toStringWithPort()<<", error:"<<stringerror()<<endl;
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket after recv() failed: "<<e.reason<<endl;
+ }
+ continue;
+ }
+ try {
+ closesocket(sock);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing master forwarding socket: "<<e.reason<<endl;
+ }
+
+ try {
+ MOADNSParser mdp(false, buf, static_cast<unsigned int>(recvRes));
+ L<<Logger::Info<<msgPrefix<<"Forward update message to "<<remote.toStringWithPort()<<", result was RCode "<<mdp.d_header.rcode<<endl;
+ return mdp.d_header.rcode;
+ }
+ catch (...) {
+ L<<Logger::Error<<msgPrefix<<"Failed to parse response packet from master at "<<remote.toStringWithPort()<<endl;
+ continue;
+ }
+ }
+ L<<Logger::Error<<msgPrefix<<"Failed to forward packet to master(s). Returning ServFail."<<endl;
+ return RCode::ServFail;
+
+}
+
+int PacketHandler::processUpdate(DNSPacket *p) {
+ if (! ::arg().mustDo("dnsupdate"))
+ return RCode::Refused;
+
+ string msgPrefix="UPDATE (" + itoa(p->d.id) + ") from " + p->getRemote().toString() + " for " + p->qdomain.toLogString() + ": ";
+ L<<Logger::Info<<msgPrefix<<"Processing started."<<endl;
+
+ // Check permissions - IP based
+ vector<string> allowedRanges;
+ B.getDomainMetadata(p->qdomain, "ALLOW-DNSUPDATE-FROM", allowedRanges);
+ if (! ::arg()["allow-dnsupdate-from"].empty())
+ stringtok(allowedRanges, ::arg()["allow-dnsupdate-from"], ", \t" );
+
+ NetmaskGroup ng;
+ for(vector<string>::const_iterator i=allowedRanges.begin(); i != allowedRanges.end(); i++)
+ ng.addMask(*i);
+
+ if ( ! ng.match(&p->d_remote)) {
+ L<<Logger::Error<<msgPrefix<<"Remote not listed in allow-dnsupdate-from or domainmetadata. Sending REFUSED"<<endl;
+ return RCode::Refused;
+ }
+
+
+ // Check permissions - TSIG based.
+ vector<string> tsigKeys;
+ B.getDomainMetadata(p->qdomain, "TSIG-ALLOW-DNSUPDATE", tsigKeys);
+ if (tsigKeys.size() > 0) {
+ bool validKey = false;
+
+ TSIGRecordContent trc;
+ DNSName inputkey;
+ string message;
+ if (! p->getTSIGDetails(&trc, &inputkey, 0)) {
+ L<<Logger::Error<<msgPrefix<<"TSIG key required, but packet does not contain key. Sending REFUSED"<<endl;
+ return RCode::Refused;
+ }
+
+ if (p->d_tsig_algo == TSIG_GSS) {
+ GssName inputname(p->d_peer_principal); // match against principal since GSS
+ for(vector<string>::const_iterator key=tsigKeys.begin(); key != tsigKeys.end(); key++) {
+ if (inputname.match(*key)) {
+ validKey = true;
+ break;
+ }
+ }
+ } else {
+ for(vector<string>::const_iterator key=tsigKeys.begin(); key != tsigKeys.end(); key++) {
+ if (inputkey == DNSName(*key)) { // because checkForCorrectTSIG has already been performed earlier on, if the names of the ky match with the domain given. THis is valid.
+ validKey=true;
+ break;
+ }
+ }
+ }
+
+ if (!validKey) {
+ L<<Logger::Error<<msgPrefix<<"TSIG key ("<<inputkey<<") required, but no matching key found in domainmetadata, tried "<<tsigKeys.size()<<". Sending REFUSED"<<endl;
+ return RCode::Refused;
+ }
+ }
+
+ if (tsigKeys.size() == 0 && p->d_havetsig)
+ L<<Logger::Warning<<msgPrefix<<"TSIG is provided, but domain is not secured with TSIG. Processing continues"<<endl;
+
+ // RFC2136 uses the same DNS Header and Message as defined in RFC1035.
+ // This means we can use the MOADNSParser to parse the incoming packet. The result is that we have some different
+ // variable names during the use of our MOADNSParser.
+ MOADNSParser mdp(false, p->getString());
+ if (mdp.d_header.qdcount != 1) {
+ L<<Logger::Warning<<msgPrefix<<"Zone Count is not 1, sending FormErr"<<endl;
+ return RCode::FormErr;
+ }
+
+ if (p->qtype.getCode() != QType::SOA) { // RFC2136 2.3 - ZTYPE must be SOA
+ L<<Logger::Warning<<msgPrefix<<"Query ZTYPE is not SOA, sending FormErr"<<endl;
+ return RCode::FormErr;
+ }
+
+ if (p->qclass != QClass::IN) {
+ L<<Logger::Warning<<msgPrefix<<"Class is not IN, sending NotAuth"<<endl;
+ return RCode::NotAuth;
+ }
+
+ DomainInfo di;
+ di.backend=0;
+ if(!B.getDomainInfo(p->qdomain, di) || !di.backend) {
+ L<<Logger::Error<<msgPrefix<<"Can't determine backend for domain '"<<p->qdomain<<"' (or backend does not support DNS update operation)"<<endl;
+ return RCode::NotAuth;
+ }
+
+ if (di.kind == DomainInfo::Slave)
+ return forwardPacket(msgPrefix, p, &di);
+
+ // Check if all the records provided are within the zone
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ // Skip this check for other field types (like the TSIG - which is in the additional section)
+ // For a TSIG, the label is the dnskey, so it does not pass the endOn validation.
+ if (! (rr->d_place == DNSResourceRecord::ANSWER || rr->d_place == DNSResourceRecord::AUTHORITY))
+ continue;
+
+ if (!rr->d_name.isPartOf(di.zone)) {
+ L<<Logger::Error<<msgPrefix<<"Received update/record out of zone, sending NotZone."<<endl;
+ return RCode::NotZone;
+ }
+ }
+
+
+ Lock l(&s_rfc2136lock); //TODO: i think this lock can be per zone, not for everything
+ L<<Logger::Info<<msgPrefix<<"starting transaction."<<endl;
+ if (!di.backend->startTransaction(p->qdomain, -1)) { // Not giving the domain_id means that we do not delete the existing records.
+ L<<Logger::Error<<msgPrefix<<"Backend for domain "<<p->qdomain<<" does not support transaction. Can't do Update packet."<<endl;
+ return RCode::NotImp;
+ }
+
+ // 3.2.1 and 3.2.2 - Prerequisite check
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ if (rr->d_place == DNSResourceRecord::ANSWER) {
+ int res = checkUpdatePrerequisites(rr, &di);
+ if (res>0) {
+ L<<Logger::Error<<msgPrefix<<"Failed PreRequisites check, returning "<<res<<endl;
+ di.backend->abortTransaction();
+ return res;
+ }
+ }
+ }
+
+ // 3.2.3 - Prerequisite check - this is outside of updatePrequisitesCheck because we check an RRSet and not the RR.
+ typedef pair<DNSName, QType> rrSetKey_t;
+ typedef vector<DNSResourceRecord> rrVector_t;
+ typedef std::map<rrSetKey_t, rrVector_t> RRsetMap_t;
+ RRsetMap_t preReqRRsets;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ if (rr->d_place == DNSResourceRecord::ANSWER) {
+ // Last line of 3.2.3
+ if (rr->d_class != QClass::IN && rr->d_class != QClass::NONE && rr->d_class != QClass::ANY)
+ return RCode::FormErr;
+
+ if (rr->d_class == QClass::IN) {
+ rrSetKey_t key = make_pair(rr->d_name, QType(rr->d_type));
+ rrVector_t *vec = &preReqRRsets[key];
+ vec->push_back(DNSResourceRecord(*rr));
+ }
+ }
+ }
+
+ if (preReqRRsets.size() > 0) {
+ RRsetMap_t zoneRRsets;
+ for (RRsetMap_t::iterator preRRSet = preReqRRsets.begin(); preRRSet != preReqRRsets.end(); ++preRRSet) {
+ rrSetKey_t rrSet=preRRSet->first;
+ rrVector_t *vec = &preRRSet->second;
+
+ DNSResourceRecord rec;
+ di.backend->lookup(QType(QType::ANY), rrSet.first);
+ uint16_t foundRR=0, matchRR=0;
+ while (di.backend->get(rec)) {
+ if (rec.qtype == rrSet.second) {
+ foundRR++;
+ for(rrVector_t::iterator rrItem=vec->begin(); rrItem != vec->end(); ++rrItem) {
+ rrItem->ttl = rec.ttl; // The compare one line below also compares TTL, so we make them equal because TTL is not user within prerequisite checks.
+ if (*rrItem == rec)
+ matchRR++;
+ }
+ }
+ }
+ if (matchRR != foundRR || foundRR != vec->size()) {
+ L<<Logger::Error<<msgPrefix<<"Failed PreRequisites check, returning NXRRSet"<<endl;
+ di.backend->abortTransaction();
+ return RCode::NXRRSet;
+ }
+ }
+ }
+
+
+
+ // 3.4 - Prescan & Add/Update/Delete records - is all done within a try block.
+ try {
+ uint changedRecords = 0;
+ // 3.4.1 - Prescan section
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ if (rr->d_place == DNSResourceRecord::AUTHORITY) {
+ int res = checkUpdatePrescan(rr);
+ if (res>0) {
+ L<<Logger::Error<<msgPrefix<<"Failed prescan check, returning "<<res<<endl;
+ di.backend->abortTransaction();
+ return res;
+ }
+ }
+ }
+
+ bool updatedSerial=false;
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow=false;
+ bool haveNSEC3 = d_dk.getNSEC3PARAM(di.zone, &ns3pr, &narrow);
+ bool isPresigned = d_dk.isPresigned(di.zone);
+
+ // 3.4.2 - Perform the updates.
+ // There's a special condition where deleting the last NS record at zone apex is never deleted (3.4.2.4)
+ // This means we must do it outside the normal performUpdate() because that focusses only on a separate RR.
+ vector<const DNSRecord *> nsRRtoDelete;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ if (rr->d_place == DNSResourceRecord::AUTHORITY) {
+ if (rr->d_class == QClass::NONE && rr->d_type == QType::NS && rr->d_name == di.zone)
+ nsRRtoDelete.push_back(rr);
+ else
+ changedRecords += performUpdate(msgPrefix, rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+ }
+ }
+ if (nsRRtoDelete.size()) {
+ vector<DNSResourceRecord> nsRRInZone;
+ DNSResourceRecord rec;
+ di.backend->lookup(QType(QType::NS), di.zone);
+ while (di.backend->get(rec)) {
+ nsRRInZone.push_back(rec);
+ }
+ if (nsRRInZone.size() > nsRRtoDelete.size()) { // only delete if the NS's we delete are less then what we have in the zone (3.4.2.4)
+ for (vector<DNSResourceRecord>::iterator inZone=nsRRInZone.begin(); inZone != nsRRInZone.end(); inZone++) {
+ for (vector<const DNSRecord *>::iterator rr=nsRRtoDelete.begin(); rr != nsRRtoDelete.end(); rr++) {
+ if (inZone->getZoneRepresentation() == (*rr)->d_content->getZoneRepresentation())
+ changedRecords += performUpdate(msgPrefix, *rr, &di, isPresigned, &narrow, &haveNSEC3, &ns3pr, &updatedSerial);
+ }
+ }
+ }
+ }
+
+ // Section 3.6 - Update the SOA serial - outside of performUpdate because we do a SOA update for the complete update message
+ if (changedRecords > 0 && !updatedSerial) {
+ increaseSerial(msgPrefix, &di, haveNSEC3, narrow, &ns3pr);
+ changedRecords++;
+ }
+
+ if (changedRecords > 0) {
+ if (!di.backend->commitTransaction()) {
+ L<<Logger::Error<<msgPrefix<<"Failed to commit updates!"<<endl;
+ return RCode::ServFail;
+ }
+
+ S.deposit("dnsupdate-changes", changedRecords);
+
+ // Purge the records!
+ string zone(di.zone.toString());
+ zone.append("$");
+ PC.purge(zone);
+
+ // Notify slaves
+ if (di.kind == DomainInfo::Master) {
+ vector<string> notify;
+ B.getDomainMetadata(p->qdomain, "NOTIFY-DNSUPDATE", notify);
+ if (!notify.empty() && notify.front() == "1") {
+ Communicator.notifyDomain(di.zone);
+ }
+ }
+
+ L<<Logger::Info<<msgPrefix<<"Update completed, "<<changedRecords<<" changed records committed."<<endl;
+ } else {
+ //No change, no commit, we perform abort() because some backends might like this more.
+ L<<Logger::Info<<msgPrefix<<"Update completed, 0 changes, rolling back."<<endl;
+ di.backend->abortTransaction();
+ }
+ return RCode::NoError; //rfc 2136 3.4.2.5
+ }
+ catch (SSqlException &e) {
+ L<<Logger::Error<<msgPrefix<<"Caught SSqlException: "<<e.txtReason()<<"; Sending ServFail!"<<endl;
+ di.backend->abortTransaction();
+ return RCode::ServFail;
+ }
+ catch (DBException &e) {
+ L<<Logger::Error<<msgPrefix<<"Caught DBException: "<<e.reason<<"; Sending ServFail!"<<endl;
+ di.backend->abortTransaction();
+ return RCode::ServFail;
+ }
+ catch (PDNSException &e) {
+ L<<Logger::Error<<msgPrefix<<"Caught PDNSException: "<<e.reason<<"; Sending ServFail!"<<endl;
+ di.backend->abortTransaction();
+ return RCode::ServFail;
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<msgPrefix<<"Caught std:exception: "<<e.what()<<"; Sending ServFail!"<<endl;
+ di.backend->abortTransaction();
+ return RCode::ServFail;
+ }
+ catch (...) {
+ L<<Logger::Error<<msgPrefix<<"Caught unknown exception when performing update. Sending ServFail!"<<endl;
+ di.backend->abortTransaction();
+ return RCode::ServFail;
+ }
+}
+
+void PacketHandler::increaseSerial(const string &msgPrefix, const DomainInfo *di, bool haveNSEC3, bool narrow, const NSEC3PARAMRecordContent *ns3pr) {
+ DNSResourceRecord rec, newRec;
+ di->backend->lookup(QType(QType::SOA), di->zone);
+ bool foundSOA=false;
+ while (di->backend->get(rec)) {
+ newRec = rec;
+ foundSOA=true;
+ }
+ if (!foundSOA) {
+ throw PDNSException("SOA-Serial update failed because there was no SOA. Wowie.");
+ }
+ SOAData soa2Update;
+ fillSOAData(rec.content, soa2Update);
+ uint32_t oldSerial = soa2Update.serial;
+
+ if (oldSerial == 0) { // using Autoserial, leave the serial alone.
+ L<<Logger::Notice<<msgPrefix<<"AutoSerial being used, not updating SOA serial."<<endl;
+ return;
+ }
+
+ vector<string> soaEdit2136Setting;
+ B.getDomainMetadata(di->zone, "SOA-EDIT-DNSUPDATE", soaEdit2136Setting);
+ string soaEdit2136 = "DEFAULT";
+ string soaEdit;
+ if (!soaEdit2136Setting.empty()) {
+ soaEdit2136 = soaEdit2136Setting[0];
+ if (pdns_iequals(soaEdit2136, "SOA-EDIT") || pdns_iequals(soaEdit2136,"SOA-EDIT-INCREASE") ){
+ string soaEditSetting;
+ d_dk.getSoaEdit(di->zone, soaEditSetting);
+ if (soaEditSetting.empty()) {
+ L<<Logger::Error<<msgPrefix<<"Using "<<soaEdit2136<<" for SOA-EDIT-DNSUPDATE increase on DNS update, but SOA-EDIT is not set for domain \""<< di->zone <<"\". Using DEFAULT for SOA-EDIT-DNSUPDATE"<<endl;
+ soaEdit2136 = "DEFAULT";
+ } else
+ soaEdit = soaEditSetting;
+ }
+ }
+
+ soa2Update.serial = calculateIncreaseSOA(soa2Update, soaEdit2136, soaEdit);
+
+ newRec.content = serializeSOAData(soa2Update);
+ vector<DNSResourceRecord> rrset;
+ rrset.push_back(newRec);
+ di->backend->replaceRRSet(di->id, newRec.qname, newRec.qtype, rrset);
+ L<<Logger::Notice<<msgPrefix<<"Increasing SOA serial ("<<oldSerial<<" -> "<<soa2Update.serial<<")"<<endl;
+
+ //Correct ordername + auth flag
+ if (haveNSEC3 && narrow)
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, newRec.qname, DNSName(), true);
+ else if (haveNSEC3) {
+ DNSName ordername;
+ if (!narrow)
+ ordername = DNSName(toBase32Hex(hashQNameWithSalt(*ns3pr, newRec.qname)))+di->zone;
+
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, newRec.qname, ordername, true);
+ }
+ else // NSEC
+ di->backend->updateDNSSECOrderNameAndAuth(di->id, di->zone, newRec.qname, newRec.qname, true);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#pragma once
+
+static const char*rootDSs[]={"19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5"};
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "base64.hh"
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "base32.hh"
+#include "dnssecinfra.hh"
+
+#include "dns_random.hh"
+#include "gss_context.hh"
+
+StatBag S;
+
+bool validateTSIG(const string& message, const TSIGHashEnum& algo, const DNSName& key, const string& secret, const TSIGRecordContent *trc) {
+ int64_t now = time(0);
+ if(abs(static_cast<int64_t>(trc->d_time) - now) > trc->d_fudge) {
+ cerr<<"TSIG (key '"<<key<<"') time delta "<< abs(static_cast<int64_t>(trc->d_time) - now)<<" > 'fudge' "<<trc->d_fudge<<endl;
+ return false;
+ }
+ if (algo == TSIG_GSS) {
+ // authorization is done later
+ GssContext gssctx(key);
+ if (!gssctx.valid()) {
+ cerr<<"no context"<<endl;
+ return false;
+ }
+ if (!gssctx.verify(message, trc->d_mac)) {
+ cerr<<"invalid mac"<<endl;
+ return false;
+ }
+ return true;
+ }
+ return constantTimeStringEquals(calculateHMAC(secret, message, algo), trc->d_mac);
+}
+
+
+int main(int argc, char** argv)
+try
+{
+ if(argc < 4) {
+ cerr<<"Syntax: saxfr IP-address port zone [showdetails] [showflags] [unhash] [gss:remote-principal] [tsig:keyname:algo:secret]"<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ bool showdetails=false;
+ bool showflags=false;
+ bool unhash=false;
+ bool gss=false;
+ bool tsig=false;
+ TSIGHashEnum tsig_algo;
+ DNSName tsig_key;
+ string tsig_secret;
+ string tsigprevious;
+ string remote_principal;
+
+ if (argc > 4) {
+ for(int i=4; i<argc; i++) {
+ if (strcmp(argv[i], "showdetails") == 0)
+ showdetails=true;
+ if (strcmp(argv[i], "showflags") == 0)
+ showflags=true;
+ if (strcmp(argv[i], "unhash") == 0)
+ unhash=true;
+ if (strncmp(argv[i], "gss:",4) == 0) {
+ gss=true;
+ tsig=true;
+ tsig_algo=TSIG_GSS;
+ remote_principal = string(argv[i]+4);
+ if (remote_principal.empty()) {
+ cerr<<"Remote principal is required"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (strncmp(argv[i], "tsig:",5) == 0) {
+ vector<string> parts;
+ tsig=true;
+ stringtok(parts, argv[i], ":");
+ if (parts.size()!=4) {
+ cerr<<"Invalid syntax for tsig"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if (!getTSIGHashEnum(DNSName(parts[2]), tsig_algo)) {
+ cerr<<"Cannot understand TSIG algorithm '"<<parts[1]<<"'"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ tsig_key = DNSName(parts[1]);
+ if (tsig_key == DNSName()) {
+ cerr<<"Key name must be set for tsig"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if (B64Decode(parts[3], tsig_secret)) {
+ cerr<<"Secret must be base64 encoded"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ if (tsig_secret.size()==0) {
+ cerr<<"Secret must be set for tsig"<<endl;
+ exit(EXIT_FAILURE);
+ }
+ }
+ }
+ }
+
+ reportAllTypes();
+ dns_random_init("0123456789abcdef");
+
+ vector<uint8_t> packet;
+ uint16_t len;
+ ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
+ Socket sock(dest.sin4.sin_family, SOCK_STREAM);
+ sock.connect(dest);
+
+ if (gss) {
+#ifndef ENABLE_GSS_TSIG
+ cerr<<"No GSS support compiled in"<<endl;
+ exit(EXIT_FAILURE);
+#else
+ string input,output;
+ GssContext gssctx;
+ gssctx.generateLabel(argv[3]);
+ gssctx.setPeerPrincipal(remote_principal);
+
+ while(gssctx.init(input, output) && gssctx.valid() == false) {
+ input="";
+ DNSPacketWriter pwtkey(packet, gssctx.getLabel(), QType::TKEY, QClass::ANY);
+ TKEYRecordContent tkrc;
+ tkrc.d_algo = DNSName("gss-tsig.");
+ tkrc.d_inception = time((time_t*)NULL);
+ tkrc.d_expiration = tkrc.d_inception+15;
+ tkrc.d_mode = 3;
+ tkrc.d_error = 0;
+ tkrc.d_keysize = output.size();
+ tkrc.d_key = output;
+ tkrc.d_othersize = 0;
+ pwtkey.getHeader()->id = dns_random(0xffff);
+ pwtkey.startRecord(gssctx.getLabel(), QType::TKEY, 3600, QClass::ANY, DNSResourceRecord::ADDITIONAL, false);
+ tkrc.toPacket(pwtkey);
+ pwtkey.commit();
+ for(const string& msg : gssctx.getErrorStrings()) {
+ cerr<<msg<<endl;
+ }
+
+ len = htons(packet.size());
+ if(sock.write((char *) &len, 2) != 2)
+ throw PDNSException("tcp write failed");
+ sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+ if(sock.read((char *) &len, 2) != 2)
+ throw PDNSException("tcp read failed");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=sock.read(creply+n, len-n);
+ if(numread<0)
+ throw PDNSException("tcp read failed");
+ n+=numread;
+ }
+
+ MOADNSParser mdp(false, string(creply, len));
+ if (mdp.d_header.rcode != 0) {
+ throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
+ }
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if(i->first.d_type != QType::TKEY) continue;
+ // recover TKEY record
+ tkrc = TKEYRecordContent(i->first.d_content->getZoneRepresentation());
+ input = tkrc.d_key;
+ }
+ }
+
+ if (gssctx.valid() == false) {
+ cerr<<"Could not create GSS context"<<endl;
+ exit(EXIT_FAILURE);
+ }
+
+ tsig_key = DNSName(gssctx.getLabel());
+#endif
+ }
+
+ DNSPacketWriter pw(packet, DNSName(argv[3]), 252);
+
+ pw.getHeader()->id = dns_random(0xffff);
+
+ if (tsig) {
+ TSIGRecordContent trc;
+ trc.d_algoName = getTSIGAlgoName(tsig_algo);
+ trc.d_time = time((time_t*)NULL);
+ trc.d_fudge = 300;
+ trc.d_origID=ntohs(pw.getHeader()->id);
+ trc.d_eRcode=0;
+ addTSIG(pw, &trc, tsig_key, tsig_secret, "", false);
+ }
+
+ len = htons(packet.size());
+ if(sock.write((char *) &len, 2) != 2)
+ throw PDNSException("tcp write failed");
+
+ sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+
+ bool isNSEC3 = false;
+ int soacount=0;
+ vector<pair<DNSName,string> > records;
+ set<DNSName> labels;
+ map<string,DNSName> hashes;
+ NSEC3PARAMRecordContent ns3pr;
+
+ while(soacount<2) {
+ TSIGRecordContent trc;
+
+ if(sock.read((char *) &len, 2) != 2)
+ throw PDNSException("tcp read failed");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=sock.read(creply+n, len-n);
+ if(numread<0)
+ throw PDNSException("tcp read failed");
+ n+=numread;
+ }
+
+ string packet = string(creply, len);
+
+ MOADNSParser mdp(false, packet);
+ if (mdp.d_header.rcode != 0) {
+ throw PDNSException(string("Remote server refused: ") + std::to_string(mdp.d_header.rcode));
+ }
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if (i->first.d_type == QType::TSIG) {
+ string message;
+ if (!tsig) {
+ std::cerr<<"Unexpected TSIG signature in data"<<endl;
+ }
+ trc = TSIGRecordContent(i->first.d_content->getZoneRepresentation());
+ continue;
+ }
+ if(i->first.d_type == QType::SOA)
+ {
+ ++soacount;
+ }
+ else if (i->first.d_type == QType::NSEC3PARAM) {
+ ns3pr = NSEC3PARAMRecordContent(i->first.d_content->getZoneRepresentation());
+ isNSEC3 = true;
+ }
+
+ ostringstream o;
+ o<<"\t"<<i->first.d_ttl<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+ if(showdetails)
+ {
+ o<<"\t"<<i->first.d_content->getZoneRepresentation();
+ }
+ else if(i->first.d_type == QType::RRSIG)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...";
+ }
+ else if(i->first.d_type == QType::NSEC3)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ o<<"\t"<<parts[0]<<" ";
+ if (showflags)
+ o<<parts[1];
+ else
+ o<<"[flags]";
+ o<<" "<<parts[2]<<" "<<parts[3]<<" "<<"[next owner]";
+ for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
+ o<<" "<<*iter;
+ }
+ else if(i->first.d_type == QType::DNSKEY)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ o<<"\t"<<parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...";
+ }
+ else
+ {
+ o<<"\t"<<i->first.d_content->getZoneRepresentation();
+ }
+
+ records.push_back(make_pair(i->first.d_name,o.str()));
+
+ DNSName shorter(i->first.d_name);
+ do {
+ labels.insert(shorter);
+ if (shorter == DNSName(argv[3]))
+ break;
+ }while(shorter.chopOff());
+
+ }
+
+ delete[] creply;
+ }
+
+ if (isNSEC3 && unhash)
+ {
+ string hashed;
+ for(const auto &label: labels) {
+ hashed=toBase32Hex(hashQNameWithSalt(ns3pr, label));
+ hashes.insert(pair<string,DNSName>(hashed, label));
+ }
+ }
+
+ for(auto &record: records) {
+ DNSName label /* FIXME400 rename */=record.first;
+ if (isNSEC3 && unhash)
+ {
+ auto i = hashes.find(label.makeRelative(DNSName(argv[3])).toStringNoDot());
+ if (i != hashes.end())
+ label=i->second;
+ }
+ cout<<label.toString()<<record.second<<endl;
+ }
+
+}
+catch(PDNSException &e2) {
+ cerr<<"Fatal: "<<e2.reason<<endl;
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include <boost/array.hpp>
+#include "ednssubnet.hh"
+StatBag S;
+
+bool hidettl=false;
+
+string ttl(uint32_t ttl)
+{
+ if(hidettl)
+ return "[ttl]";
+ else
+ return std::to_string(ttl);
+}
+
+void usage() {
+ cerr<<"sdig"<<endl;
+ cerr<<"Syntax: sdig IP-ADDRESS PORT QUESTION QUESTION-TYPE [dnssec] [recurse] [showflags] [hidesoadetails] [hidettl] [tcp] [ednssubnet SUBNET]"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ bool dnssec=false;
+ bool recurse=false;
+ bool tcp=false;
+ bool showflags=false;
+ bool hidesoadetails=false;
+ boost::optional<Netmask> ednsnm;
+
+
+ for(int i=1; i<argc; i++) {
+ if ((string) argv[i] == "--help") {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+
+ if ((string) argv[i] == "--version") {
+ cerr<<"sdig "<<VERSION<<endl;
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ if(argc < 5) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+ reportAllTypes();
+
+ if (argc > 5) {
+ for(int i=5; i<argc; i++) {
+ if (strcmp(argv[i], "dnssec") == 0)
+ dnssec=true;
+ if (strcmp(argv[i], "recurse") == 0)
+ recurse=true;
+ if (strcmp(argv[i], "showflags") == 0)
+ showflags=true;
+ if (strcmp(argv[i], "hidesoadetails") == 0)
+ hidesoadetails=true;
+ if (strcmp(argv[i], "hidettl") == 0)
+ hidettl=true;
+ if (strcmp(argv[i], "tcp") == 0)
+ tcp=true;
+ if (strcmp(argv[i], "ednssubnet") == 0) {
+ ednsnm=Netmask(argv[++i]);
+ }
+ }
+ }
+
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, DNSName(argv[3]), DNSRecordContent::TypeToNumber(argv[4]));
+
+ if(dnssec || ednsnm || getenv("SDIGBUFSIZE"))
+ {
+ char *sbuf=getenv("SDIGBUFSIZE");
+ int bufsize;
+ if(sbuf)
+ bufsize=atoi(sbuf);
+ else
+ bufsize=2800;
+ DNSPacketWriter::optvect_t opts;
+ if(ednsnm) {
+ EDNSSubnetOpts eo;
+ eo.source = *ednsnm;
+ opts.push_back(make_pair(8, makeEDNSSubnetOptsString(eo)));
+ }
+
+ pw.addOpt(bufsize, 0, dnssec ? EDNSOpts::DNSSECOK : 0, opts);
+ pw.commit();
+ }
+
+ if(recurse)
+ {
+ pw.getHeader()->rd=true;
+ }
+
+ string reply;
+ ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
+
+ if(tcp) {
+ Socket sock(dest.sin4.sin_family, SOCK_STREAM);
+ sock.connect(dest);
+ uint16_t len;
+ len = htons(packet.size());
+ if(sock.write((char *) &len, 2) != 2)
+ throw PDNSException("tcp write failed");
+
+ sock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+
+ if(sock.read((char *) &len, 2) != 2)
+ throw PDNSException("tcp read failed");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=sock.read(creply+n, len-n);
+ if(numread<0)
+ throw PDNSException("tcp read failed");
+ n+=numread;
+ }
+
+ reply=string(creply, len);
+ delete[] creply;
+ }
+ else //udp
+ {
+ Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
+ sock.sendTo(string((char*)&*packet.begin(), (char*)&*packet.end()), dest);
+ int result=waitForData(sock.getHandle(), 10);
+ if(result < 0)
+ throw std::runtime_error("Error waiting for data: "+string(strerror(errno)));
+ if(!result)
+ throw std::runtime_error("Timeout waiting for data");
+ sock.recvFrom(reply, dest);
+ }
+ MOADNSParser mdp(false, reply);
+ cout<<"Reply to question for qname='"<<mdp.d_qname.toString()<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<" ("<<RCode::to_s(mdp.d_header.rcode)<<"), RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ cout<<i->first.d_place-1<<"\t"<<i->first.d_name.toString()<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type);
+ if(i->first.d_type == QType::RRSIG)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ cout<<"\t"<<ttl(i->first.d_ttl)<<"\t"<< parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" "<<parts[3]<<" [expiry] [inception] [keytag] "<<parts[7]<<" ...\n";
+ }
+ else if(!showflags && i->first.d_type == QType::NSEC3)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ cout<<"\t"<<ttl(i->first.d_ttl)<<"\t"<< parts[0]<<" [flags] "<<parts[2]<<" "<<parts[3]<<" "<<parts[4];
+ for(vector<string>::iterator iter = parts.begin()+5; iter != parts.end(); ++iter)
+ cout<<" "<<*iter;
+ cout<<"\n";
+ }
+ else if(i->first.d_type == QType::DNSKEY)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ cout<<"\t"<<ttl(i->first.d_ttl)<<"\t"<< parts[0]<<" "<<parts[1]<<" "<<parts[2]<<" ...\n";
+ }
+ else if (i->first.d_type == QType::SOA && hidesoadetails)
+ {
+ string zoneRep = i->first.d_content->getZoneRepresentation();
+ vector<string> parts;
+ stringtok(parts, zoneRep);
+ cout<<"\t"<<ttl(i->first.d_ttl)<<"\t"<<parts[0]<<" "<<parts[1]<<" [serial] "<<parts[3]<<" "<<parts[4]<<" "<<parts[5]<<" "<<parts[6]<<"\n";
+ }
+ else
+ {
+ cout<<"\t"<<ttl(i->first.d_ttl)<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
+ }
+
+ }
+
+ EDNSOpts edo;
+ if(getEDNSOpts(mdp, &edo)) {
+// cerr<<"Have "<<edo.d_options.size()<<" options!"<<endl;
+ for(vector<pair<uint16_t, string> >::const_iterator iter = edo.d_options.begin();
+ iter != edo.d_options.end();
+ ++iter) {
+ if(iter->first == 5) {// 'EDNS PING'
+ cerr<<"Have ednsping: '"<<iter->second<<"'\n";
+ //if(iter->second == ping)
+ // cerr<<"It is correct!"<<endl;
+ }
+ if(iter->first == 8) {// 'EDNS subnet'
+ EDNSSubnetOpts reso;
+ if(getEDNSSubnetOptsFromString(iter->second, &reso)) {
+ cerr<<"EDNS Subnet response: "<<reso.source.toString()<<", scope: "<<reso.scope.toString()<<", family = "<<reso.scope.getNetwork().sin4.sin_family<<endl;
+ }
+ }
+
+ else {
+ cerr<<"Have unknown option "<<(int)iter->first<<endl;
+ }
+ }
+
+ }
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+catch(PDNSException &e)
+{
+ cerr<<"Fatal: "<<e.reason<<endl;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "secpoll-auth.hh"
+
+#include "logger.hh"
+#include "arguments.hh"
+#include "version.hh"
+#include "dnsparser.hh"
+#include "misc.hh"
+
+#include "sstuff.hh"
+#include "dnswriter.hh"
+#include "dns_random.hh"
+#include "namespaces.hh"
+#include "statbag.hh"
+#include "stubresolver.hh"
+#include <stdint.h>
+#ifndef PACKAGEVERSION
+#define PACKAGEVERSION getPDNSVersion()
+#endif
+
+string g_security_message;
+
+extern StatBag S;
+
+/** Do an actual secpoll for the current version
+ * @param first bool that tells if this is the first secpoll run since startup
+ */
+void doSecPoll(bool first)
+{
+ if(::arg()["security-poll-suffix"].empty())
+ return;
+
+ struct timeval now;
+ gettimeofday(&now, 0);
+
+ string version = "auth-" + string(PACKAGEVERSION);
+ string query = version.substr(0, 63) +".security-status."+::arg()["security-poll-suffix"];
+
+ if(*query.rbegin()!='.')
+ query+='.';
+
+ boost::replace_all(query, "+", "_");
+ boost::replace_all(query, "~", "_");
+
+ vector<DNSResourceRecord> ret;
+
+ int res=stubDoResolve(query, QType::TXT, ret);
+
+ int security_status=0;
+
+ if(!res && !ret.empty()) {
+ string content=ret.begin()->content;
+ if(!content.empty() && content[0]=='"' && content[content.size()-1]=='"') {
+ content=content.substr(1, content.length()-2);
+ }
+
+ pair<string, string> split = splitField(content, ' ');
+
+ security_status = std::stoi(split.first);
+ g_security_message = split.second;
+
+ }
+ else {
+ string pkgv(PACKAGEVERSION);
+ if(pkgv.find("0.0."))
+ L<<Logger::Warning<<"Could not retrieve security status update for '" + pkgv + "' on '"+query+"', RCODE = "<< RCode::to_s(res)<<endl;
+ else
+ L<<Logger::Warning<<"Not validating response for security status update, this a non-release version."<<endl;
+ }
+
+ if(security_status == 1 && first) {
+ L<<Logger::Warning << "Polled security status of version "<<PACKAGEVERSION<<" at startup, no known issues reported: " <<g_security_message<<endl;
+ }
+ if(security_status == 2) {
+ L<<Logger::Error<<"PowerDNS Security Update Recommended: "<<g_security_message<<endl;
+ }
+ else if(security_status == 3) {
+ L<<Logger::Error<<"PowerDNS Security Update Mandatory: "<<g_security_message<<endl;
+ }
+
+ S.set("security-status",security_status);
+
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_SECPOLL_AUTH_HH
+#define PDNS_SECPOLL_AUTH_HH
+#include <time.h>
+#include "namespaces.hh"
+#include "stubresolver.hh"
+
+void doSecPoll(bool first);
+extern std::string g_security_message;
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "mplexer.hh"
+#include "sstuff.hh"
+#include <iostream>
+#include "misc.hh"
+#include "utility.hh"
+
+
+#include "namespaces.hh"
+#include "namespaces.hh"
+
+static FDMultiplexer* make()
+{
+ return new SelectFDMultiplexer();
+}
+
+static struct RegisterOurselves
+{
+ RegisterOurselves() {
+ FDMultiplexer::getMultiplexerMap().insert(make_pair(1, &make));
+ }
+} doIt;
+
+void SelectFDMultiplexer::addFD(callbackmap_t& cbmap, int fd, callbackfunc_t toDo, const boost::any& parameter)
+{
+ Callback cb;
+ cb.d_callback=toDo;
+ cb.d_parameter=parameter;
+ memset(&cb.d_ttd, 0, sizeof(cb.d_ttd));
+ if(cbmap.count(fd))
+ throw FDMultiplexerException("Tried to add fd "+std::to_string(fd)+ " to multiplexer twice");
+ cbmap[fd]=cb;
+}
+
+void SelectFDMultiplexer::removeFD(callbackmap_t& cbmap, int fd)
+{
+ if(d_inrun && d_iter->first==fd) // trying to remove us!
+ d_iter++;
+
+ if(!cbmap.erase(fd))
+ throw FDMultiplexerException("Tried to remove unlisted fd "+std::to_string(fd)+ " from multiplexer");
+}
+
+int SelectFDMultiplexer::run(struct timeval* now)
+{
+ if(d_inrun) {
+ throw FDMultiplexerException("FDMultiplexer::run() is not reentrant!\n");
+ }
+ fd_set readfds, writefds;
+ FD_ZERO(&readfds);
+ FD_ZERO(&writefds);
+
+ int fdmax=0;
+
+ for(callbackmap_t::const_iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end(); ++i) {
+ FD_SET(i->first, &readfds);
+ fdmax=max(i->first, fdmax);
+ }
+
+ for(callbackmap_t::const_iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end(); ++i) {
+ FD_SET(i->first, &writefds);
+ fdmax=max(i->first, fdmax);
+ }
+
+ struct timeval tv={0,500000};
+ int ret=select(fdmax + 1, &readfds, &writefds, 0, &tv);
+ Utility::gettimeofday(now, 0); // MANDATORY!
+
+ if(ret < 0 && errno!=EINTR)
+ throw FDMultiplexerException("select returned error: "+stringerror());
+
+ if(ret < 1) // nothing - thanks AB
+ return 0;
+
+ d_iter=d_readCallbacks.end();
+ d_inrun=true;
+
+ for(callbackmap_t::iterator i=d_readCallbacks.begin(); i != d_readCallbacks.end() && i->first <= fdmax; ) {
+ d_iter=i++;
+
+ if(FD_ISSET(d_iter->first, &readfds)) {
+ d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+ continue; // so we don't refind ourselves as writable
+ }
+ }
+
+ for(callbackmap_t::iterator i=d_writeCallbacks.begin(); i != d_writeCallbacks.end() && i->first <= fdmax; ) {
+ d_iter=i++;
+ if(FD_ISSET(d_iter->first, &writefds)) {
+ d_iter->second.d_callback(d_iter->first, d_iter->second.d_parameter);
+ }
+ }
+
+ d_inrun=false;
+ return 0;
+}
+
+#if 0
+
+void acceptData(int fd, boost::any& parameter)
+{
+ cout<<"Have data on fd "<<fd<<endl;
+ Socket* sock=boost::any_cast<Socket*>(parameter);
+ string packet;
+ IPEndpoint rem;
+ sock->recvFrom(packet, rem);
+ cout<<"Received "<<packet.size()<<" bytes!\n";
+}
+
+
+int main()
+{
+ Socket s(AF_INET, SOCK_DGRAM);
+
+ IPEndpoint loc("0.0.0.0", 2000);
+ s.bind(loc);
+
+ SelectFDMultiplexer sfm;
+
+ sfm.addReadFD(s.getHandle(), &acceptData, &s);
+
+ for(int n=0; n < 100 ; ++n) {
+ sfm.run();
+ }
+ sfm.removeReadFD(s.getHandle());
+ sfm.removeReadFD(s.getHandle());
+}
+#endif
+
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002-2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsseckeeper.hh"
+#include "dnspacket.hh"
+#include "namespaces.hh"
+
+
+uint32_t localtime_format_YYYYMMDDSS(time_t t, uint32_t seq)
+{
+ struct tm tm;
+ localtime_r(&t, &tm);
+ return
+ (uint32_t)(tm.tm_year+1900) * 1000000u
+ + (uint32_t)(tm.tm_mon + 1) * 10000u
+ + (uint32_t)tm.tm_mday * 100u
+ + seq;
+}
+
+bool editSOA(DNSSECKeeper& dk, const DNSName& qname, DNSPacket* dp)
+{
+ vector<DNSResourceRecord>& rrs = dp->getRRS();
+ for(DNSResourceRecord& rr : rrs) {
+ if(rr.qtype.getCode() == QType::SOA && rr.qname == qname) {
+ string kind;
+ dk.getSoaEdit(qname, kind);
+ return editSOARecord(rr, kind, qname);
+ }
+ }
+ return false;
+}
+
+bool editSOARecord(DNSResourceRecord& rr, const string& kind, const DNSName& qname) {
+ if(kind.empty())
+ return false;
+
+ SOAData sd;
+ sd.qname = qname;
+ fillSOAData(rr.content, sd);
+ sd.serial = calculateEditSOA(sd, kind);
+ rr.content = serializeSOAData(sd);
+ return true;
+}
+
+uint32_t calculateEditSOA(SOAData sd, const string& kind) {
+ if(pdns_iequals(kind,"INCEPTION")) {
+ L<<Logger::Warning<<"Deprecation warning: The 'INCEPTION' soa-edit value will be removed in PowerDNS 4.1"<<endl;
+ time_t inception = getStartOfWeek();
+ return localtime_format_YYYYMMDDSS(inception, 1);
+ }
+ else if(pdns_iequals(kind,"INCEPTION-INCREMENT")) {
+ time_t inception = getStartOfWeek();
+ uint32_t inception_serial = localtime_format_YYYYMMDDSS(inception, 1);
+ uint32_t dont_increment_after = localtime_format_YYYYMMDDSS(inception + 2*86400, 99);
+
+ if(sd.serial < inception_serial - 1) { /* less than <inceptionday>00 */
+ return inception_serial; /* return <inceptionday>01 (skipping <inceptionday>00 as possible value) */
+ } else if(sd.serial <= dont_increment_after) { /* >= <inceptionday>00 but <= <inceptionday+2>99 */
+ return (sd.serial + 2); /* "<inceptionday>00" and "<inceptionday>01" are reserved for inception increasing, so increment sd.serial by two */
+ }
+ }
+ else if(pdns_iequals(kind,"INCEPTION-WEEK")) {
+ L<<Logger::Warning<<"Deprecation warning: The 'INCEPTION-WEEK' soa-edit value will be removed in PowerDNS 4.1"<<endl;
+ time_t inception = getStartOfWeek();
+ return ( inception / (7*86400) );
+ }
+ else if(pdns_iequals(kind,"INCREMENT-WEEKS")) {
+ time_t inception = getStartOfWeek();
+ return (sd.serial + (inception / (7*86400)));
+ }
+ else if(pdns_iequals(kind,"EPOCH")) {
+ L<<Logger::Warning<<"Deprecation warning: The 'EPOCH' soa-edit value will be removed in PowerDNS 4.1"<<endl;
+ return time(0);
+ }
+ else if(pdns_iequals(kind,"INCEPTION-EPOCH")) {
+ uint32_t inception = getStartOfWeek();
+ if (sd.serial < inception)
+ return inception;
+ }
+ else if(pdns_iequals(kind,"NONE")) {
+ return sd.serial;
+ }
+ else if(!kind.empty()) {
+ L<<Logger::Warning<<"SOA-EDIT type '"<<kind<<"' for zone "<<sd.qname.toStringNoDot()<<" is unknown."<<endl;
+ }
+ return sd.serial;
+}
+
+// Used for SOA-EDIT-DNSUPDATE and SOA-EDIT-API.
+uint32_t calculateIncreaseSOA(SOAData sd, const string& increaseKind, const string& editKind) {
+ // These only work when SOA-EDIT is set, otherwise fall back to default.
+ if (!editKind.empty()) {
+ if (pdns_iequals(increaseKind, "SOA-EDIT-INCREASE")) {
+ uint32_t new_serial = calculateEditSOA(sd, editKind);
+ if (new_serial <= sd.serial) {
+ new_serial = sd.serial + 1;
+ }
+ return new_serial;
+ }
+ else if (pdns_iequals(increaseKind, "SOA-EDIT")) {
+ return calculateEditSOA(sd, editKind);
+ }
+ }
+
+ if (pdns_iequals(increaseKind, "INCREASE")) {
+ return sd.serial + 1;
+ }
+ else if (pdns_iequals(increaseKind, "EPOCH")) {
+ return time(0);
+ }
+
+ // DEFAULT case
+ time_t now = time(0);
+ struct tm tm;
+ localtime_r(&now, &tm);
+ boost::format fmt("%04d%02d%02d%02d");
+ string newdate = (fmt % (tm.tm_year + 1900) % (tm.tm_mon + 1) % tm.tm_mday % 1).str();
+ uint32_t new_serial = pdns_stou(newdate);
+ if (new_serial <= sd.serial) {
+ new_serial = sd.serial + 1;
+ }
+ return new_serial;
+}
+
+bool increaseSOARecord(DNSResourceRecord& rr, const string& increaseKind, const string& editKind) {
+ if (increaseKind.empty())
+ return false;
+
+ SOAData sd;
+ fillSOAData(rr.content, sd);
+ sd.serial = calculateIncreaseSOA(sd, increaseKind, editKind);
+ rr.content = serializeSOAData(sd);
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef _SHA_HH
+#define _SHA_HH
+
+#include <string>
+#include <stdint.h>
+#include <openssl/sha.h>
+
+inline std::string pdns_sha1sum(const std::string& input)
+{
+ unsigned char result[20] = {0};
+ SHA1(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), result);
+ return std::string(result, result + sizeof result);
+}
+
+inline std::string pdns_sha256sum(const std::string& input)
+{
+ unsigned char result[32] = {0};
+ SHA256(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), result);
+ return std::string(result, result + sizeof result);
+}
+
+inline std::string pdns_sha384sum(const std::string& input)
+{
+ unsigned char result[48] = {0};
+ SHA384(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), result);
+ return std::string(result, result + sizeof result);
+}
+
+inline std::string pdns_sha512sum(const std::string& input)
+{
+ unsigned char result[64] = {0};
+ SHA512(reinterpret_cast<const unsigned char*>(input.c_str()), input.length(), result);
+ return std::string(result, result + sizeof result);
+}
+
+#endif /* sha.hh */
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <memory>
+#include <atomic>
+#include <mutex>
+/** This is sort of a light-weight RCU idea.
+ Suitable for when you frequently consult some "readonly" state, which infrequently
+ gets changed. One way of dealing with this is fully locking access to the state, but
+ this is rather wasteful.
+
+ Instead, in the code below, the frequent users of the state get a "readonly" copy of it,
+ which they can consult. On access, we atomically compare if the local copy is still current
+ with the global one. If it isn't we do the lock thing, and create a new local copy.
+
+ Meanwhile, to upgrade the global state, methods are offered that do appropriate locking
+ and upgrade the 'generation' counter, signaling to the local copies that they need to be
+ refreshed on the next access.
+
+ Two ways to change the global copy are available:
+ getCopy(), which delivers a deep copy of the current state, followed by setState()
+ modify(), which accepts a (lambda)function that modifies the state
+
+ NOTE: The actual destruction of the 'old' state happens when the last local state
+ relinquishes its access to the state.
+
+ "read-only"
+ Sometimes, a 'state' can contain parts that can safely be modified by multiple users, for
+ example, atomic counters. In such cases, it may be useful to explicitly declare such counters
+ as mutable. */
+
+template<typename T> class GlobalStateHolder;
+
+template<typename T>
+class LocalStateHolder
+{
+public:
+ explicit LocalStateHolder(GlobalStateHolder<T>* source) : d_source(source)
+ {}
+
+ const T* operator->() // fast const-only access, but see "read-only" above
+ {
+ if(d_source->getGeneration() != d_generation) {
+ d_source->getState(&d_state, & d_generation);
+ }
+
+ return d_state.get();
+ }
+ const T& operator*() // fast const-only access, but see "read-only" above
+ {
+ return *operator->();
+ }
+
+ void reset()
+ {
+ d_generation=0;
+ d_state.reset();
+ }
+private:
+ std::shared_ptr<T> d_state;
+ unsigned int d_generation{0};
+ const GlobalStateHolder<T>* d_source;
+};
+
+template<typename T>
+class GlobalStateHolder
+{
+public:
+ GlobalStateHolder() : d_state(std::make_shared<T>())
+ {}
+ LocalStateHolder<T> getLocal()
+ {
+ return LocalStateHolder<T>(this);
+ }
+
+ void setState(T state) //!< Safely & slowly change the global state
+ {
+ std::lock_guard<std::mutex> l(d_lock);
+ d_state = std::make_shared<T>(T(state));
+ d_generation++;
+ }
+
+ T getCopy() const //!< Safely & slowly get a copy of the global state
+ {
+ std::lock_guard<std::mutex> l(d_lock);
+ return *d_state;
+ }
+
+ //! Safely & slowly modify the global state
+ template<typename F>
+ void modify(F act) {
+ std::lock_guard<std::mutex> l(d_lock);
+ auto state=*d_state; // and yes, these three steps are necessary, can't ever modify state in place, even when locked!
+ act(state);
+ d_state = std::make_shared<T>(T(state));
+ ++d_generation;
+ }
+
+
+ typedef T value_type;
+private:
+ unsigned int getGeneration() const
+ {
+ return d_generation;
+ }
+ void getState(std::shared_ptr<T>* state, unsigned int* generation) const
+ {
+ std::lock_guard<std::mutex> l(d_lock);
+ *state=d_state;
+ *generation = d_generation;
+ }
+ friend class LocalStateHolder<T>;
+ mutable std::mutex d_lock;
+ std::shared_ptr<T> d_state;
+ std::atomic<unsigned int> d_generation{1};
+};
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "signingpipe.hh"
+#include "misc.hh"
+#include <poll.h>
+
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netinet/tcp.h>
+#include <sched.h>
+
+// deal with partial reads
+namespace {
+int readn(int fd, void* buffer, unsigned int len)
+{
+ unsigned int pos=0;
+ int res;
+ for(;;) {
+ res = read(fd, (char*)buffer + pos, len - pos);
+ if(res == 0) {
+ if(pos)
+ throw runtime_error("Signing Pipe remote shut down in the middle of a message");
+ else {
+ //cerr<<"Got decent EOF on "<<fd<<endl;
+ return 0;
+ }
+ }
+
+ if(res < 0) {
+ if(errno == EAGAIN || errno == EINTR) {
+ if(pos==0)
+ return -1;
+ waitForData(fd, -1);
+ continue;
+ }
+ unixDie("Reading from socket in Signing Pipe loop");
+ }
+
+ pos+=res;
+ if(pos == len)
+ break;
+ }
+ return len;
+}
+}
+
+
+// used to pass information to the new thread
+struct StartHelperStruct
+{
+ StartHelperStruct(ChunkedSigningPipe* csp, int id, int fd) : d_csp(csp), d_id(id), d_fd(fd){}
+ ChunkedSigningPipe* d_csp;
+ int d_id;
+ int d_fd;
+};
+
+// used to launch the new thread
+void* ChunkedSigningPipe::helperWorker(void* p)
+try
+{
+ StartHelperStruct shs=*(StartHelperStruct*)p;
+ delete (StartHelperStruct*)p;
+
+ shs.d_csp->worker(shs.d_id, shs.d_fd);
+ return 0;
+}
+catch(...) {
+ L<<Logger::Error<<"Unknown exception in signing thread occurred"<<endl;
+ return 0;
+}
+
+ChunkedSigningPipe::ChunkedSigningPipe(const DNSName& signerName, bool mustSign, const string& servers, unsigned int workers)
+ : d_signed(0), d_queued(0), d_outstanding(0), d_numworkers(workers), d_submitted(0), d_signer(signerName),
+ d_maxchunkrecords(100), d_tids(d_numworkers), d_mustSign(mustSign), d_final(false)
+{
+ d_rrsetToSign = new rrset_t;
+ d_chunks.push_back(vector<DNSResourceRecord>()); // load an empty chunk
+
+ if(!d_mustSign)
+ return;
+
+ int fds[2];
+
+ for(unsigned int n=0; n < d_numworkers; ++n) {
+ if(socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0)
+ throw runtime_error("Unable to create communication socket in for ChunkedSigningPipe");
+ setCloseOnExec(fds[0]);
+ setCloseOnExec(fds[1]);
+ pthread_create(&d_tids[n], 0, helperWorker, (void*) new StartHelperStruct(this, n, fds[1]));
+ setNonBlocking(fds[0]);
+ d_sockets.push_back(fds[0]);
+ }
+}
+
+ChunkedSigningPipe::~ChunkedSigningPipe()
+{
+ delete d_rrsetToSign;
+ if(!d_mustSign)
+ return;
+ for(int fd : d_sockets) {
+ close(fd); // this will trigger all threads to exit
+ }
+
+ void* res;
+ for(pthread_t& tid : d_tids) {
+ pthread_join(tid, &res);
+ }
+ //cout<<"Did: "<<d_signed<<", records (!= chunks) submitted: "<<d_submitted<<endl;
+}
+
+namespace {
+bool
+dedupLessThan(const DNSResourceRecord& a, const DNSResourceRecord &b)
+{
+ return (tie(a.content, a.ttl) < tie(b.content, b.ttl));
+}
+
+bool dedupEqual(const DNSResourceRecord& a, const DNSResourceRecord &b)
+{
+ return(tie(a.content, a.ttl) == tie(b.content, b.ttl));
+}
+}
+
+void ChunkedSigningPipe::dedupRRSet()
+{
+ // our set contains contains records for one type and one name, but might not be sorted otherwise
+ sort(d_rrsetToSign->begin(), d_rrsetToSign->end(), dedupLessThan);
+ d_rrsetToSign->erase(unique(d_rrsetToSign->begin(), d_rrsetToSign->end(), dedupEqual), d_rrsetToSign->end());
+}
+
+bool ChunkedSigningPipe::submit(const DNSResourceRecord& rr)
+{
+ ++d_submitted;
+ // check if we have a full RRSET to sign
+ if(!d_rrsetToSign->empty() && (d_rrsetToSign->begin()->qtype.getCode() != rr.qtype.getCode() || d_rrsetToSign->begin()->qname != rr.qname))
+ {
+ dedupRRSet();
+ sendRRSetToWorker();
+ }
+ d_rrsetToSign->push_back(rr);
+ return !d_chunks.empty() && d_chunks.front().size() >= d_maxchunkrecords; // "you can send more"
+}
+
+pair<vector<int>, vector<int> > ChunkedSigningPipe::waitForRW(bool rd, bool wr, int seconds)
+{
+ vector<pollfd> pfds;
+
+ for(unsigned int n = 0; n < d_sockets.size(); ++n) {
+ if(d_eof.count(d_sockets[n]))
+ continue;
+ struct pollfd pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = d_sockets[n];
+ if(rd)
+ pfd.events |= POLLIN;
+ if(wr)
+ pfd.events |= POLLOUT;
+ pfds.push_back(pfd);
+ }
+
+ int res = poll(&pfds[0], pfds.size(), (seconds < 0) ? -1 : (seconds * 1000)); // -1 = infinite
+ if(res < 0)
+ unixDie("polling for activity from signers, "+std::to_string(d_sockets.size()));
+ pair<vector<int>, vector<int> > vects;
+ for(unsigned int n = 0; n < pfds.size(); ++n)
+ if(pfds[n].revents & POLLIN)
+ vects.first.push_back(pfds[n].fd);
+ else if(pfds[n].revents & POLLOUT)
+ vects.second.push_back(pfds[n].fd);
+
+ return vects;
+}
+
+void ChunkedSigningPipe::addSignedToChunks(chunk_t* signedChunk)
+{
+ chunk_t::const_iterator from = signedChunk->begin();
+
+ while(from != signedChunk->end()) {
+ chunk_t& fillChunk = d_chunks.back();
+
+ chunk_t::size_type room = d_maxchunkrecords - fillChunk.size();
+
+ unsigned int fit = std::min(room, (chunk_t::size_type)(signedChunk->end() - from));
+
+ d_chunks.back().insert(fillChunk.end(), from , from + fit);
+ from+=fit;
+
+ if(from != signedChunk->end()) // it didn't fit, so add a new chunk
+ d_chunks.push_back(chunk_t());
+ }
+}
+
+void ChunkedSigningPipe::sendRRSetToWorker() // it sounds so socialist!
+{
+ if(!d_mustSign) {
+ addSignedToChunks(d_rrsetToSign);
+ d_rrsetToSign->clear();
+ return;
+ }
+
+ if(d_final && !d_outstanding) // nothing to do!
+ return;
+
+ bool wantRead, wantWrite;
+
+ wantWrite = !d_rrsetToSign->empty();
+ wantRead = d_outstanding || wantWrite; // if we wrote, we want to read
+
+ pair<vector<int>, vector<int> > rwVect;
+
+ rwVect = waitForRW(wantRead, wantWrite, -1); // wait for something to happen
+
+ if(wantWrite && !rwVect.second.empty()) {
+ random_shuffle(rwVect.second.begin(), rwVect.second.end()); // pick random available worker
+ writen2(*rwVect.second.begin(), &d_rrsetToSign, sizeof(d_rrsetToSign));
+ d_rrsetToSign = new rrset_t;
+ d_outstanding++;
+ d_queued++;
+ wantWrite=false;
+ }
+
+ if(wantRead) {
+ while(d_outstanding) {
+ chunk_t* chunk;
+
+ for(int fd : rwVect.first) {
+ if(d_eof.count(fd))
+ continue;
+
+ while(d_outstanding) {
+ int res = readn(fd, &chunk, sizeof(chunk));
+ if(!res) {
+ d_eof.insert(fd);
+ break;
+ }
+ if(res < 0) {
+ if(errno != EAGAIN && errno != EINTR)
+ unixDie("Error reading signed chunk from thread");
+ else
+ break;
+ }
+
+ --d_outstanding;
+
+ addSignedToChunks(chunk);
+
+ delete chunk;
+ }
+ }
+ if(!d_outstanding || !d_final)
+ break;
+ rwVect = waitForRW(1, 0, -1); // wait for something to happen
+ }
+ }
+
+ if(wantWrite) { // our optimization above failed, we now wait synchronously
+ rwVect = waitForRW(0, wantWrite, -1); // wait for something to happen
+ random_shuffle(rwVect.second.begin(), rwVect.second.end()); // pick random available worker
+ writen2(*rwVect.second.begin(), &d_rrsetToSign, sizeof(d_rrsetToSign));
+ d_rrsetToSign = new rrset_t;
+ d_outstanding++;
+ d_queued++;
+ }
+
+}
+
+unsigned int ChunkedSigningPipe::getReady()
+{
+ unsigned int sum=0;
+ for(const std::vector<DNSResourceRecord>& v : d_chunks) {
+ sum += v.size();
+ }
+ return sum;
+}
+void ChunkedSigningPipe::worker(int id, int fd)
+try
+{
+ DNSSECKeeper dk;
+ UeberBackend db("key-only");
+
+ chunk_t* chunk = nullptr;
+ int res;
+ for(;;) {
+ res = readn(fd, &chunk, sizeof(chunk));
+ if(!res)
+ break;
+ if(res < 0)
+ unixDie("reading object pointer to sign from pdns");
+ try {
+ set<DNSName> authSet;
+ authSet.insert(d_signer);
+ addRRSigs(dk, db, authSet, *chunk);
+ ++d_signed;
+
+ writen2(fd, &chunk, sizeof(chunk));
+ chunk = nullptr;
+ }
+ catch(const PDNSException& pe) {
+ delete chunk;
+ throw;
+ }
+ catch(const std::exception& e) {
+ delete chunk;
+ throw;
+ }
+ }
+ close(fd);
+}
+catch(const PDNSException& pe)
+{
+ L<<Logger::Error<<"Signing thread died because of PDNSException: "<<pe.reason<<endl;
+ close(fd);
+}
+catch(const std::exception& e)
+{
+ L<<Logger::Error<<"Signing thread died because of std::exception: "<<e.what()<<endl;
+ close(fd);
+}
+
+void ChunkedSigningPipe::flushToSign()
+{
+ sendRRSetToWorker();
+ d_rrsetToSign->clear();
+}
+
+vector<DNSResourceRecord> ChunkedSigningPipe::getChunk(bool final)
+{
+ if(final && !d_final) {
+ // this means we should keep on reading until d_outstanding == 0
+ d_final = true;
+ flushToSign();
+
+ for(int fd : d_sockets) {
+ shutdown(fd, SHUT_WR); // perhaps this transmits EOF the other side
+ //cerr<<"shutdown of "<<fd<<endl;
+ }
+ }
+ if(d_final)
+ flushToSign(); // should help us wait
+ vector<DNSResourceRecord> front=d_chunks.front();
+ d_chunks.pop_front();
+ if(d_chunks.empty())
+ d_chunks.push_back(vector<DNSResourceRecord>());
+/* if(d_final && front.empty())
+ cerr<<"getChunk returning empty in final"<<endl; */
+ return front;
+}
+
+#if 0
+
+ ServiceTuple st;
+ ComboAddress remote;
+ if(!servers.empty()) {
+ st.port=2000;
+ parseService(servers, st);
+ remote=ComboAddress(st.host, st.port);
+ }
+
+ ///
+ if(!servers.empty()) {
+ fds[0] = socket(AF_INET, SOCK_STREAM, 0);
+ fds[1] = -1;
+
+ if(connect(fds[0], (struct sockaddr*)&remote, remote.getSocklen()) < 0)
+ unixDie("Connecting to signing server");
+ }
+ else {
+/////
+ signal(SIGCHLD, SIG_IGN);
+ if(!fork()) { // child
+ dup2(fds[1], 0);
+ execl("./pdnsutil", "./pdnsutil", "--config-dir=./", "signing-slave", NULL);
+ // helperWorker(new StartHelperStruct(this, n));
+ return;
+ }
+ else
+ close(fds[1]);
+#endif
+
+#if 0
+bool readLStringFromSocket(int fd, string& msg)
+{
+ msg.clear();
+ uint32_t len;
+ if(!readn(fd, &len, sizeof(len)))
+ return false;
+
+ len = ntohl(len);
+
+ scoped_array<char> buf(new char[len]);
+ readn(fd, buf.get(), len);
+
+ msg.assign(buf.get(), len);
+ return true;
+}
+void writeLStringToSocket(int fd, const string& msg)
+{
+ string realmsg;
+ uint32_t len = htonl(msg.length());
+ string tot((char*)&len, 4);
+ tot+=msg;
+
+ writen2(fd, tot.c_str(), tot.length());
+}
+
+#endif
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_SIGNINGPIPE
+#define PDNS_SIGNINGPIPE
+#include <vector>
+#include <pthread.h>
+#include <stdio.h>
+#include "dnsseckeeper.hh"
+#include "dns.hh"
+
+void writeLStringToSocket(int fd, const string& msg);
+bool readLStringFromSocket(int fd, string& msg);
+
+/** input: DNSResourceRecords ordered in qname,qtype (we emit a signature chunk on a break)
+ * output: "chunks" of those very same DNSResourceRecords, interleaved with signatures
+ */
+
+class ChunkedSigningPipe
+{
+public:
+ typedef vector<DNSResourceRecord> rrset_t;
+ typedef rrset_t chunk_t; // for now
+
+ ChunkedSigningPipe(const DNSName& signerName, bool mustSign, /* FIXME servers is unused? */ const string& servers=string(), unsigned int numWorkers=3);
+ ~ChunkedSigningPipe();
+ bool submit(const DNSResourceRecord& rr);
+ chunk_t getChunk(bool final=false);
+
+ std::atomic<unsigned long> d_signed;
+ int d_queued;
+ int d_outstanding;
+ unsigned int getReady();
+private:
+ void flushToSign();
+ void dedupRRSet();
+ void sendRRSetToWorker(); // dispatch RRSET to worker
+ void addSignedToChunks(chunk_t* signedChunk);
+ pair<vector<int>, vector<int> > waitForRW(bool rd, bool wr, int seconds);
+
+ void worker(int n, int fd);
+
+ static void* helperWorker(void* p);
+
+ unsigned int d_numworkers;
+ int d_submitted;
+
+ rrset_t* d_rrsetToSign;
+ std::deque< std::vector<DNSResourceRecord> > d_chunks;
+ DNSName d_signer;
+
+ chunk_t::size_type d_maxchunkrecords;
+
+ std::vector<int> d_sockets;
+ std::set<int> d_eof;
+ vector<pthread_t> d_tids;
+ bool d_mustSign;
+ bool d_final;
+};
+
+#endif
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include <cstdio>
+#include <math.h>
+#include <cstdlib>
+#include <sys/types.h>
+#include <string>
+#include <errno.h>
+#include "dnsrecords.hh"
+
+static unsigned int poweroften[10] = {1, 10, 100, 1000, 10000, 100000,
+ 1000000,10000000,100000000,1000000000};
+
+/* converts ascii size/precision X * 10**Y(cm) to 0xXY. moves pointer.*/
+static uint8_t precsize_aton(const char **strptr)
+{
+ unsigned int mval = 0, cmval = 0;
+ uint8_t retval = 0;
+ const char *cp;
+ int exponent;
+ int mantissa;
+
+ cp = *strptr;
+
+ while (isdigit(*cp))
+ mval = mval * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* centimeters */
+ cp++;
+ if (isdigit(*cp)) {
+ cmval = (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ cmval += (*cp++ - '0');
+ }
+ }
+ }
+ cmval = (mval * 100) + cmval;
+
+ for (exponent = 0; exponent < 9; exponent++)
+ if (cmval < poweroften[exponent+1])
+ break;
+
+ mantissa = cmval / poweroften[exponent];
+ if (mantissa > 9)
+ mantissa = 9;
+
+ retval = (mantissa << 4) | exponent;
+
+ *strptr = cp;
+
+ return (retval);
+}
+
+/* converts ascii lat/lon to unsigned encoded 32-bit number.
+ * moves pointer. */
+static uint32_t
+latlon2ul(const char **latlonstrptr, int *which)
+{
+ const char *cp;
+ uint32_t retval;
+ int deg = 0, min = 0, secs = 0, secsfrac = 0;
+
+ cp = *latlonstrptr;
+
+ while (isdigit(*cp))
+ deg = deg * 10 + (*cp++ - '0');
+
+ while (isspace(*cp))
+ cp++;
+
+ if (!(isdigit(*cp)))
+ goto fndhemi;
+
+ while (isdigit(*cp))
+ min = min * 10 + (*cp++ - '0');
+
+ while (isspace(*cp))
+ cp++;
+
+ if (*cp && !(isdigit(*cp)))
+ goto fndhemi;
+
+ while (isdigit(*cp))
+ secs = secs * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal seconds */
+ cp++;
+ if (isdigit(*cp)) {
+ secsfrac = (*cp++ - '0') * 100;
+ if (isdigit(*cp)) {
+ secsfrac += (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ secsfrac += (*cp++ - '0');
+ }
+ }
+ }
+ }
+
+ while (*cp && !isspace(*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace(*cp))
+ cp++;
+
+ fndhemi:
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'E': case 'e':
+ retval = ((unsigned)1<<31)
+ + (((((deg * 60) + min) * 60) + secs) * 1000)
+ + secsfrac;
+ break;
+ case 'S': case 's':
+ case 'W': case 'w':
+ retval = ((unsigned)1<<31)
+ - (((((deg * 60) + min) * 60) + secs) * 1000)
+ - secsfrac;
+ break;
+ default:
+ retval = 0; /* invalid value -- indicates error */
+ break;
+ }
+
+ switch (*cp) {
+ case 'N': case 'n':
+ case 'S': case 's':
+ *which = 1; /* latitude */
+ break;
+ case 'E': case 'e':
+ case 'W': case 'w':
+ *which = 2; /* longitude */
+ break;
+ default:
+ *which = 0; /* error */
+ break;
+ }
+
+ if (!*cp)
+ return 0;
+
+ cp++; /* skip the hemisphere */
+
+ while (*cp && !isspace(*cp)) /* if any trailing garbage */
+ cp++;
+
+ while (isspace(*cp)) /* move to next field */
+ cp++;
+
+ *latlonstrptr = cp;
+
+ return (retval);
+}
+
+void LOCRecordContent::report(void)
+{
+ regist(1, QType::LOC, &make, &make, "LOC");
+ regist(254, QType::LOC, &make, &make, "LOC");
+}
+
+DNSRecordContent* LOCRecordContent::make(const string& content)
+{
+ return new LOCRecordContent(content);
+}
+
+
+void LOCRecordContent::toPacket(DNSPacketWriter& pw)
+{
+ pw.xfr8BitInt(d_version);
+ pw.xfr8BitInt(d_size);
+ pw.xfr8BitInt(d_horizpre);
+ pw.xfr8BitInt(d_vertpre);
+
+ pw.xfr32BitInt(d_latitude);
+ pw.xfr32BitInt(d_longitude);
+ pw.xfr32BitInt(d_altitude);
+}
+
+LOCRecordContent::DNSRecordContent* LOCRecordContent::make(const DNSRecord &dr, PacketReader& pr)
+{
+ LOCRecordContent* ret=new LOCRecordContent();
+ pr.xfr8BitInt(ret->d_version);
+ pr.xfr8BitInt(ret->d_size);
+ pr.xfr8BitInt(ret->d_horizpre);
+ pr.xfr8BitInt(ret->d_vertpre);
+
+ pr.xfr32BitInt(ret->d_latitude);
+ pr.xfr32BitInt(ret->d_longitude);
+ pr.xfr32BitInt(ret->d_altitude);
+
+ return ret;
+}
+
+LOCRecordContent::LOCRecordContent(const string& content, const string& zone)
+{
+ // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m
+ // convert this to d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude
+ d_version = 0;
+
+ const char *cp, *maxcp;
+
+ uint32_t lltemp1 = 0, lltemp2 = 0;
+ int altmeters = 0, altfrac = 0, altsign = 1;
+ d_horizpre = 0x16; /* default = 1e6 cm = 10000.00m = 10km */
+ d_vertpre = 0x13; /* default = 1e3 cm = 10.00m */
+ d_size = 0x12; /* default = 1e2 cm = 1.00m */
+ int which1 = 0, which2 = 0;
+
+ cp = content.c_str();
+ maxcp = cp + strlen(content.c_str());
+
+ lltemp1 = latlon2ul(&cp, &which1);
+ lltemp2 = latlon2ul(&cp, &which2);
+
+ switch (which1 + which2) {
+ case 3: /* 1 + 2, the only valid combination */
+ if ((which1 == 1) && (which2 == 2)) { /* normal case */
+ d_latitude = lltemp1;
+ d_longitude = lltemp2;
+ } else if ((which1 == 2) && (which2 == 1)) {/*reversed*/
+ d_latitude = lltemp1;
+ d_longitude = lltemp2;
+ } else { /* some kind of brokenness */
+ return;
+ }
+ break;
+ default: /* we didn't get one of each */
+ throw MOADNSException("Error decoding LOC content");
+ }
+
+ /* altitude */
+ if (*cp == '-') {
+ altsign = -1;
+ cp++;
+ }
+
+ if (*cp == '+')
+ cp++;
+
+ while (isdigit(*cp))
+ altmeters = altmeters * 10 + (*cp++ - '0');
+
+ if (*cp == '.') { /* decimal meters */
+ cp++;
+ if (isdigit(*cp)) {
+ altfrac = (*cp++ - '0') * 10;
+ if (isdigit(*cp)) {
+ altfrac += (*cp++ - '0');
+ }
+ }
+ }
+
+ d_altitude = (10000000 + (altsign * (altmeters * 100 + altfrac)));
+
+ while (!isspace(*cp) && (cp < maxcp))
+ /* if trailing garbage or m */
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ d_size = precsize_aton(&cp);
+
+ while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ d_horizpre = precsize_aton(&cp);
+
+ while (!isspace(*cp) && (cp < maxcp))/*if trailing garbage or m*/
+ cp++;
+
+ while (isspace(*cp) && (cp < maxcp))
+ cp++;
+
+ if (cp >= maxcp)
+ goto defaults;
+
+ d_vertpre = precsize_aton(&cp);
+
+ defaults:
+ ;
+}
+
+
+string LOCRecordContent::getZoneRepresentation(bool noDot) const
+{
+ // convert d_version, d_size, d_horiz/vertpre, d_latitude, d_longitude, d_altitude to:
+ // 51 59 00.000 N 5 55 00.000 E 4.00m 1.00m 10000.00m 10.00m
+
+ double latitude= ((int32_t)d_latitude - (1<<31))/3600000.0;
+ double longitude=((int32_t)d_longitude - (1<<31))/3600000.0;
+ double altitude= ((int32_t)d_altitude )/100.0 - 100000;
+
+ double size=0.01*((d_size>>4)&0xf);
+ int count=d_size & 0xf;
+ while(count--)
+ size*=10;
+
+ double horizpre=0.01*((d_horizpre>>4) & 0xf);
+ count=d_horizpre&0xf;
+ while(count--)
+ horizpre*=10;
+
+ double vertpre=0.01*((d_vertpre>>4)&0xf);
+ count=d_vertpre&0xf;
+ while(count--)
+ vertpre*=10;
+
+ double remlat=60.0*(latitude-(int)latitude);
+ double remlong=60.0*(longitude-(int)longitude);
+ char ret[80];
+ snprintf(ret,sizeof(ret)-1,"%d %d %2.03f %c %d %d %2.03f %c %.2fm %.2fm %.2fm %.2fm",
+ abs((int)latitude), abs((int) ((latitude-(int)latitude)*60)),
+ fabs((double)((remlat-(int)remlat)*60.0)),
+ latitude>0 ? 'N' : 'S',
+ abs((int)longitude), abs((int) ((longitude-(int)longitude)*60)),
+ fabs((double)((remlong-(int)remlong)*60.0)),
+ longitude>0 ? 'E' : 'W',
+ altitude, size, horizpre, vertpre);
+
+ return ret;
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002-2016 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation;
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include "dnssecinfra.hh"
+#include "dnsseckeeper.hh"
+#include "base32.hh"
+#include <errno.h>
+#include "communicator.hh"
+#include <set>
+#include <boost/utility.hpp>
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "packethandler.hh"
+#include "resolver.hh"
+#include "logger.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include "packetcache.hh"
+
+#include "base64.hh"
+#include "inflighter.cc"
+#include "lua-auth.hh"
+#include "namespaces.hh"
+#include "common_startup.hh"
+
+#include "ixfr.hh"
+using boost::scoped_ptr;
+
+
+void CommunicatorClass::addSuckRequest(const DNSName &domain, const string &master)
+{
+ Lock l(&d_lock);
+ SuckRequest sr;
+ sr.domain = domain;
+ sr.master = master;
+ pair<UniQueue::iterator, bool> res;
+
+ res=d_suckdomains.push_back(sr);
+ if(res.second) {
+ d_suck_sem.post();
+ }
+
+}
+
+struct ZoneStatus
+{
+ bool isDnssecZone{false};
+ bool isPresigned{false};
+ bool isNSEC3 {false};
+ bool optOutFlag {false};
+ NSEC3PARAMRecordContent ns3pr;
+
+ bool isNarrow{false};
+ unsigned int soa_serial{0};
+ set<DNSName> nsset, qnames, secured;
+ uint32_t domain_id;
+ int numDeltas{0};
+};
+
+
+void CommunicatorClass::ixfrSuck(const DNSName &domain, const TSIGTriplet& tt, const ComboAddress& laddr, const ComboAddress& remote, scoped_ptr<AuthLua>& pdl,
+ ZoneStatus& zs, vector<DNSRecord>* axfr)
+{
+ UeberBackend B; // fresh UeberBackend
+
+ DomainInfo di;
+ di.backend=0;
+ // bool transaction=false;
+ try {
+ DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
+
+ if(!B.getDomainInfo(domain, di) || !di.backend) { // di.backend and B are mostly identical
+ L<<Logger::Error<<"Can't determine backend for domain '"<<domain<<"'"<<endl;
+ return;
+ }
+
+ soatimes st;
+ memset(&st, 0, sizeof(st));
+ st.serial=di.serial;
+
+ DNSRecord dr;
+ dr.d_content = std::make_shared<SOARecordContent>(DNSName("."), DNSName("."), st);
+ auto deltas = getIXFRDeltas(remote, domain, dr, tt, laddr.sin4.sin_family ? &laddr : 0, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
+ zs.numDeltas=deltas.size();
+ // cout<<"Got "<<deltas.size()<<" deltas from serial "<<di.serial<<", applying.."<<endl;
+
+ for(const auto& d : deltas) {
+ const auto& remove = d.first;
+ const auto& add = d.second;
+ // cout<<"Delta sizes: "<<remove.size()<<", "<<add.size()<<endl;
+
+ if(remove.empty()) { // we got passed an AXFR!
+ *axfr = add;
+ return;
+ }
+
+
+ // our hammer is 'replaceRRSet(domain_id, qname, qt, vector<DNSResourceRecord>& rrset)
+ // which thinks in terms of RRSETs
+ // however, IXFR does not, and removes and adds *records* (bummer)
+ // this means that we must group updates by {qname,qtype}, retrieve the RRSET, apply
+ // the add/remove updates, and replaceRRSet the whole thing.
+
+
+ map<pair<DNSName,uint16_t>, pair<vector<DNSRecord>, vector<DNSRecord> > > grouped;
+
+ for(const auto& x: remove)
+ grouped[{x.d_name, x.d_type}].first.push_back(x);
+ for(const auto& x: add)
+ grouped[{x.d_name, x.d_type}].second.push_back(x);
+
+ di.backend->startTransaction(domain, -1);
+ for(const auto g : grouped) {
+ DNSResourceRecord rr;
+ vector<DNSRecord> rrset;
+ B.lookup(QType(g.first.second), g.first.first, 0, di.id);
+ while(B.get(rr)) {
+ rrset.push_back(DNSRecord{rr});
+ }
+ // O(N^2)!
+ rrset.erase(remove_if(rrset.begin(), rrset.end(),
+ [&g](const DNSRecord& dr) {
+ return count(g.second.first.cbegin(),
+ g.second.first.cend(), dr);
+ }), rrset.end());
+ // the DNSRecord== operator compares on name, type, class and lowercase content representation
+
+ for(const auto& x : g.second.second) {
+ rrset.push_back(x);
+ }
+
+ vector<DNSResourceRecord> replacement;
+ for(const auto& x : rrset) {
+ DNSResourceRecord dr(x);
+ dr.qname += domain;
+ dr.domain_id = di.id;
+ if(x.d_type == QType::SOA) {
+ // cout<<"New SOA: "<<x.d_content->getZoneRepresentation()<<endl;
+ auto sr = getRR<SOARecordContent>(x);
+ zs.soa_serial=sr->d_st.serial;
+ }
+
+ replacement.push_back(dr);
+ }
+
+ di.backend->replaceRRSet(di.id, g.first.first+domain, QType(g.first.second), replacement);
+ }
+ di.backend->commitTransaction();
+ }
+ }
+ catch(std::exception& p) {
+ L<<Logger::Error<<"Got exception during IXFR: "<<p.what()<<endl;
+ throw;
+ }
+ catch(PDNSException& p) {
+ L<<Logger::Error<<"Got exception during IXFR: "<<p.reason<<endl;
+ throw;
+ }
+}
+
+
+static bool processRecordForZS(const DNSName& domain, bool& firstNSEC3, DNSResourceRecord& rr, ZoneStatus& zs)
+{
+ switch(rr.qtype.getCode()) {
+ case QType::NSEC3PARAM:
+ zs.ns3pr = NSEC3PARAMRecordContent(rr.content);
+ zs.isDnssecZone = zs.isNSEC3 = true;
+ zs.isNarrow = false;
+ return false;
+ case QType::NSEC3: {
+ NSEC3RecordContent ns3rc(rr.content);
+ if (firstNSEC3) {
+ zs.isDnssecZone = zs.isPresigned = true;
+ firstNSEC3 = false;
+ } else if (zs.optOutFlag != (ns3rc.d_flags & 1))
+ throw PDNSException("Zones with a mixture of Opt-Out NSEC3 RRs and non-Opt-Out NSEC3 RRs are not supported.");
+ zs.optOutFlag = ns3rc.d_flags & 1;
+ if (ns3rc.d_set.count(QType::NS) && !(rr.qname==domain)) {
+ DNSName hashPart = rr.qname.makeRelative(domain);
+ zs.secured.insert(hashPart);
+ }
+ return false;
+ }
+
+ case QType::NSEC:
+ zs.isDnssecZone = zs.isPresigned = true;
+ return false;
+
+ case QType::NS:
+ if(rr.qname!=domain)
+ zs.nsset.insert(rr.qname);
+ break;
+ }
+
+ zs.qnames.insert(rr.qname);
+
+ rr.domain_id=zs.domain_id;
+ return true;
+}
+
+/* So this code does a number of things.
+ 1) It will AXFR a domain from a master
+ The code can retrieve the current serial number in the database itself.
+ It may attempt an IXFR
+ 2) It will filter the zone through a lua *filter* script
+ 3) The code walks through the zone records do determine DNSSEC status (secured, nsec/nsec3, optout)
+ 4) It inserts the zone into the database
+ With the right 'ordername' fields
+ 5) It updates the Empty Non Terminals
+*/
+
+vector<DNSResourceRecord> doAxfr(const ComboAddress& raddr, const DNSName& domain, const TSIGTriplet& tt, const ComboAddress& laddr, scoped_ptr<AuthLua>& pdl, ZoneStatus& zs)
+{
+ vector<DNSResourceRecord> rrs;
+ AXFRRetriever retriever(raddr, domain, tt, (laddr.sin4.sin_family == 0) ? NULL : &laddr, ((size_t) ::arg().asNum("xfr-max-received-mbytes")) * 1024 * 1024);
+ Resolver::res_t recs;
+ bool first=true;
+ bool firstNSEC3{true};
+ bool soa_received {false};
+ while(retriever.getChunk(recs)) {
+ if(first) {
+ L<<Logger::Error<<"AXFR started for '"<<domain<<"'"<<endl;
+ first=false;
+ }
+
+ for(Resolver::res_t::iterator i=recs.begin();i!=recs.end();++i) {
+ i->qname.makeUsLowerCase();
+ if(i->qtype.getCode() == QType::OPT || i->qtype.getCode() == QType::TSIG) // ignore EDNS0 & TSIG
+ continue;
+
+ if(!i->qname.isPartOf(domain)) {
+ L<<Logger::Error<<"Remote "<<raddr.toStringWithPort()<<" tried to sneak in out-of-zone data '"<<i->qname<<"'|"<<i->qtype.getName()<<" during AXFR of zone '"<<domain<<"', ignoring"<<endl;
+ continue;
+ }
+
+ vector<DNSResourceRecord> out;
+ if(!pdl || !pdl->axfrfilter(raddr, domain, *i, out)) {
+ out.push_back(*i); // if axfrfilter didn't do anything, we put our record in 'out' ourselves
+ }
+
+ for(DNSResourceRecord& rr : out) {
+ if(!rr.qname.isPartOf(domain)) {
+ L<<Logger::Error<<"Lua axfrfilter() filter tried to sneak in out-of-zone data '"<<i->qname<<"'|"<<i->qtype.getName()<<" during AXFR of zone '"<<domain<<"', ignoring"<<endl;
+ continue;
+ }
+ if(!processRecordForZS(domain, firstNSEC3, rr, zs))
+ continue;
+ if(rr.qtype.getCode() == QType::SOA) {
+ if(soa_received)
+ continue; //skip the last SOA
+ SOAData sd;
+ fillSOAData(rr.content,sd);
+ zs.soa_serial = sd.serial;
+ soa_received = true;
+ }
+
+ rrs.push_back(rr);
+
+ }
+ }
+ }
+ return rrs;
+}
+
+
+void CommunicatorClass::suck(const DNSName &domain, const string &remote)
+{
+ {
+ Lock l(&d_lock);
+ if(d_inprogress.count(domain)) {
+ return;
+ }
+ d_inprogress.insert(domain);
+ }
+ RemoveSentinel rs(domain, this); // this removes us from d_inprogress when we go out of scope
+
+ L<<Logger::Error<<"Initiating transfer of '"<<domain<<"' from remote '"<<remote<<"'"<<endl;
+ UeberBackend B; // fresh UeberBackend
+
+ DomainInfo di;
+ di.backend=0;
+ bool transaction=false;
+ try {
+ DNSSECKeeper dk (&B); // reuse our UeberBackend copy for DNSSECKeeper
+
+ if(!B.getDomainInfo(domain, di) || !di.backend) { // di.backend and B are mostly identical
+ L<<Logger::Error<<"Can't determine backend for domain '"<<domain<<"'"<<endl;
+ return;
+ }
+ ZoneStatus zs;
+ zs.domain_id=di.id;
+
+ TSIGTriplet tt;
+ if(dk.getTSIGForAccess(domain, remote, &tt.name)) {
+ string tsigsecret64;
+ if(B.getTSIGKey(tt.name, &tt.algo, &tsigsecret64)) {
+ if(B64Decode(tsigsecret64, tt.secret)) {
+ L<<Logger::Error<<"Unable to Base-64 decode TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
+ return;
+ }
+ } else {
+ L<<Logger::Error<<"TSIG key '"<<tt.name<<"' for domain '"<<domain<<"' not found"<<endl;
+ return;
+ }
+ }
+
+
+ scoped_ptr<AuthLua> pdl;
+ vector<string> scripts;
+ string script=::arg()["lua-axfr-script"];
+ if(B.getDomainMetadata(domain, "LUA-AXFR-SCRIPT", scripts) && !scripts.empty()) {
+ if (pdns_iequals(scripts[0], "NONE")) {
+ script.clear();
+ } else {
+ script=scripts[0];
+ }
+ }
+ if(!script.empty()){
+ try {
+ pdl.reset(new AuthLua(script));
+ L<<Logger::Info<<"Loaded Lua script '"<<script<<"' to edit the incoming AXFR of '"<<domain<<"'"<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Failed to load Lua editing script '"<<script<<"' for incoming AXFR of '"<<domain<<"': "<<e.what()<<endl;
+ return;
+ }
+ }
+
+ vector<string> localaddr;
+ ComboAddress laddr;
+ ComboAddress raddr(remote, 53);
+ if(B.getDomainMetadata(domain, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
+ try {
+ laddr = ComboAddress(localaddr[0]);
+ L<<Logger::Info<<"AXFR source for domain '"<<domain<<"' set to "<<localaddr[0]<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Failed to load AXFR source '"<<localaddr[0]<<"' for incoming AXFR of '"<<domain<<"': "<<e.what()<<endl;
+ return;
+ }
+ } else {
+ if(raddr.sin4.sin_family == AF_INET)
+ laddr=ComboAddress(::arg()["query-local-address"]);
+ else if(!::arg()["query-local-address6"].empty())
+ laddr=ComboAddress(::arg()["query-local-address6"]);
+ else
+ laddr.sin4.sin_family = 0;
+ }
+
+ bool hadDnssecZone = false;
+ bool hadPresigned = false;
+ bool hadNSEC3 = false;
+ NSEC3PARAMRecordContent hadNs3pr;
+ bool hadNarrow=false;
+
+
+ vector<DNSResourceRecord> rrs;
+ if(dk.isSecuredZone(domain)) {
+ hadDnssecZone=true;
+ hadPresigned=dk.isPresigned(domain);
+ if (dk.getNSEC3PARAM(domain, &zs.ns3pr, &zs.isNarrow)) {
+ hadNSEC3 = true;
+ hadNs3pr = zs.ns3pr;
+ hadNarrow = zs.isNarrow;
+ }
+ }
+ else if(di.serial) {
+ vector<string> meta;
+ B.getDomainMetadata(domain, "IXFR", meta);
+ if(!meta.empty() && meta[0]=="1") {
+ vector<DNSRecord> axfr;
+ L<<Logger::Warning<<"Starting IXFR of '"<<domain<<"' from remote "<<raddr.toStringWithPort()<<endl;
+ ixfrSuck(domain, tt, laddr, raddr, pdl, zs, &axfr);
+ if(!axfr.empty()) {
+ L<<Logger::Warning<<"IXFR of '"<<domain<<"' from remote '"<<raddr.toStringWithPort()<<"' turned into an AXFR"<<endl;
+ bool firstNSEC3=true;
+ rrs.reserve(axfr.size());
+ for(const auto& dr : axfr) {
+ DNSResourceRecord rr(dr);
+ (rr.qname += domain).makeUsLowerCase();
+ rr.domain_id = zs.domain_id;
+ if(!processRecordForZS(domain, firstNSEC3, rr, zs))
+ continue;
+ if(dr.d_type == QType::SOA) {
+ auto sd = getRR<SOARecordContent>(dr);
+ zs.soa_serial = sd->d_st.serial;
+ }
+ rrs.push_back(rr);
+ }
+ }
+ else {
+ L<<Logger::Warning<<"Done with IXFR of '"<<domain<<"' from remote '"<<remote<<"', got "<<zs.numDeltas<<" delta"<<addS(zs.numDeltas)<<", serial now "<<zs.soa_serial<<endl;
+ return;
+ }
+ }
+ }
+
+ if(rrs.empty()) {
+ L<<Logger::Warning<<"Starting AXFR of '"<<domain<<"' from remote "<<raddr.toStringWithPort()<<endl;
+ rrs = doAxfr(raddr, domain, tt, laddr, pdl, zs);
+ L<<Logger::Warning<<"AXFR of '"<<domain<<"' from remote "<<raddr.toStringWithPort()<<" done"<<endl;
+ }
+
+ if(zs.isNSEC3) {
+ zs.ns3pr.d_flags = zs.optOutFlag ? 1 : 0;
+ }
+
+ if(!zs.isPresigned) {
+ DNSSECKeeper::keyset_t keys = dk.getKeys(domain);
+ if(!keys.empty()) {
+ zs.isDnssecZone = true;
+ zs.isNSEC3 = hadNSEC3;
+ zs.ns3pr = hadNs3pr;
+ zs.optOutFlag = (hadNs3pr.d_flags & 1);
+ zs.isNarrow = hadNarrow;
+ }
+ }
+
+ if(zs.isDnssecZone) {
+ if(!zs.isNSEC3)
+ L<<Logger::Info<<"Adding NSEC ordering information"<<endl;
+ else if(!zs.isNarrow)
+ L<<Logger::Info<<"Adding NSEC3 hashed ordering information for '"<<domain<<"'"<<endl;
+ else
+ L<<Logger::Info<<"Erasing NSEC3 ordering since we are narrow, only setting 'auth' fields"<<endl;
+ }
+
+
+ transaction=di.backend->startTransaction(domain, zs.domain_id);
+ L<<Logger::Error<<"Backend transaction started for '"<<domain<<"' storage"<<endl;
+
+ // update the presigned flag and NSEC3PARAM
+ if (zs.isDnssecZone) {
+ // update presigned if there was a change
+ if (zs.isPresigned && !hadPresigned) {
+ // zone is now presigned
+ dk.setPresigned(domain);
+ } else if (hadPresigned && !zs.isPresigned) {
+ // zone is no longer presigned
+ dk.unsetPresigned(domain);
+ }
+ // update NSEC3PARAM
+ if (zs.isNSEC3) {
+ // zone is NSEC3, only update if there was a change
+ if (!hadNSEC3 || (hadNarrow != zs.isNarrow) ||
+ (zs.ns3pr.d_algorithm != hadNs3pr.d_algorithm) ||
+ (zs.ns3pr.d_flags != hadNs3pr.d_flags) ||
+ (zs.ns3pr.d_iterations != hadNs3pr.d_iterations) ||
+ (zs.ns3pr.d_salt != hadNs3pr.d_salt)) {
+ dk.setNSEC3PARAM(domain, zs.ns3pr, zs.isNarrow);
+ }
+ } else if (hadNSEC3 ) {
+ // zone is no longer NSEC3
+ dk.unsetNSEC3PARAM(domain);
+ }
+ } else if (hadDnssecZone) {
+ // zone is no longer signed
+ if (hadPresigned) {
+ // remove presigned
+ dk.unsetPresigned(domain);
+ }
+ if (hadNSEC3) {
+ // unset NSEC3PARAM
+ dk.unsetNSEC3PARAM(domain);
+ }
+ }
+
+ bool doent=true;
+ uint32_t maxent = ::arg().asNum("max-ent-entries");
+ string ordername;
+ DNSName shorter;
+ set<DNSName> rrterm;
+ map<DNSName,bool> nonterm;
+
+
+ for(DNSResourceRecord& rr : rrs) {
+ if(!zs.isPresigned) {
+ if (rr.qtype.getCode() == QType::RRSIG)
+ continue;
+ if(zs.isDnssecZone && rr.qtype.getCode() == QType::DNSKEY && !::arg().mustDo("direct-dnskey"))
+ continue;
+ }
+
+ // Figure out auth and ents
+ rr.auth=true;
+ shorter=rr.qname;
+ rrterm.clear();
+ do {
+ if(doent) {
+ if (!zs.qnames.count(shorter))
+ rrterm.insert(shorter);
+ }
+ if(zs.nsset.count(shorter) && rr.qtype.getCode() != QType::DS)
+ rr.auth=false;
+
+ if (shorter==domain) // stop at apex
+ break;
+ }while(shorter.chopOff());
+
+ // Insert ents
+ if(doent && !rrterm.empty()) {
+ bool auth;
+ if (!rr.auth && rr.qtype.getCode() == QType::NS) {
+ if (zs.isNSEC3)
+ ordername=toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname));
+ auth=(!zs.isNSEC3 || !zs.optOutFlag || zs.secured.count(DNSName(ordername)));
+ } else
+ auth=rr.auth;
+
+ for(const auto &nt: rrterm){
+ if (!nonterm.count(nt))
+ nonterm.insert(pair<DNSName, bool>(nt, auth));
+ else if (auth)
+ nonterm[nt]=true;
+ }
+
+ if(nonterm.size() > maxent) {
+ L<<Logger::Error<<"AXFR zone "<<domain<<" has too many empty non terminals."<<endl;
+ nonterm.clear();
+ doent=false;
+ }
+ }
+
+ // RRSIG is always auth, even inside a delegation
+ if (rr.qtype.getCode() == QType::RRSIG)
+ rr.auth=true;
+
+ // Add ordername and insert record
+ if (zs.isDnssecZone && rr.qtype.getCode() != QType::RRSIG) {
+ if (zs.isNSEC3) {
+ // NSEC3
+ ordername=toBase32Hex(hashQNameWithSalt(zs.ns3pr, rr.qname));
+ if(!zs.isNarrow && (rr.auth || (rr.qtype.getCode() == QType::NS && (!zs.optOutFlag || zs.secured.count(DNSName(ordername)))))) {
+ di.backend->feedRecord(rr, &ordername);
+ } else
+ di.backend->feedRecord(rr);
+ } else {
+ // NSEC
+ if (rr.auth || rr.qtype.getCode() == QType::NS) {
+ ordername=toLower(labelReverse(makeRelative(rr.qname.toStringNoDot(), domain.toStringNoDot()))); // FIXME400
+ di.backend->feedRecord(rr, &ordername);
+ } else
+ di.backend->feedRecord(rr);
+ }
+ } else
+ di.backend->feedRecord(rr);
+ }
+
+ // Insert empty non-terminals
+ if(doent && !nonterm.empty()) {
+ if (zs.isNSEC3) {
+ di.backend->feedEnts3(zs.domain_id, domain, nonterm, zs.ns3pr, zs.isNarrow);
+ } else
+ di.backend->feedEnts(zs.domain_id, nonterm);
+ }
+
+ di.backend->commitTransaction();
+ transaction = false;
+ di.backend->setFresh(zs.domain_id);
+ PC.purge(domain.toString()+"$");
+
+
+ L<<Logger::Error<<"AXFR done for '"<<domain<<"', zone committed with serial number "<<zs.soa_serial<<endl;
+ if(::arg().mustDo("slave-renotify"))
+ notifyDomain(domain);
+ }
+ catch(DBException &re) {
+ L<<Logger::Error<<"Unable to feed record during incoming AXFR of '" << domain<<"': "<<re.reason<<endl;
+ if(di.backend && transaction) {
+ L<<Logger::Error<<"Aborting possible open transaction for domain '"<<domain<<"' AXFR"<<endl;
+ di.backend->abortTransaction();
+ }
+ }
+ catch(MOADNSException &re) {
+ L<<Logger::Error<<"Unable to parse record during incoming AXFR of '"<<domain<<"' (MOADNSException): "<<re.what()<<endl;
+ if(di.backend && transaction) {
+ L<<Logger::Error<<"Aborting possible open transaction for domain '"<<domain<<"' AXFR"<<endl;
+ di.backend->abortTransaction();
+ }
+ }
+ catch(std::exception &re) {
+ L<<Logger::Error<<"Unable to parse record during incoming AXFR of '"<<domain<<"' (std::exception): "<<re.what()<<endl;
+ if(di.backend && transaction) {
+ L<<Logger::Error<<"Aborting possible open transaction for domain '"<<domain<<"' AXFR"<<endl;
+ di.backend->abortTransaction();
+ }
+ }
+ catch(ResolverException &re) {
+ L<<Logger::Error<<"Unable to AXFR zone '"<<domain<<"' from remote '"<<remote<<"' (resolver): "<<re.reason<<endl;
+ if(di.backend && transaction) {
+ L<<Logger::Error<<"Aborting possible open transaction for domain '"<<domain<<"' AXFR"<<endl;
+ di.backend->abortTransaction();
+ }
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"Unable to AXFR zone '"<<domain<<"' from remote '"<<remote<<"' (PDNSException): "<<ae.reason<<endl;
+ if(di.backend && transaction) {
+ L<<Logger::Error<<"Aborting possible open transaction for domain '"<<domain<<"' AXFR"<<endl;
+ di.backend->abortTransaction();
+ }
+ }
+}
+namespace {
+struct QueryInfo
+{
+ struct timeval query_ttd;
+ uint16_t id;
+};
+
+struct DomainNotificationInfo
+{
+ DomainInfo di;
+ bool dnssecOk;
+ ComboAddress localaddr;
+ DNSName tsigkeyname, tsigalgname;
+ string tsigsecret;
+};
+}
+
+
+struct SlaveSenderReceiver
+{
+ typedef pair<DNSName, uint16_t> Identifier;
+
+ struct Answer {
+ uint32_t theirSerial;
+ uint32_t theirInception;
+ uint32_t theirExpire;
+ };
+
+ map<uint32_t, Answer> d_freshness;
+
+ SlaveSenderReceiver()
+ {
+ }
+
+ void deliverTimeout(const Identifier& i)
+ {
+ }
+
+ Identifier send(DomainNotificationInfo& dni)
+ {
+ random_shuffle(dni.di.masters.begin(), dni.di.masters.end());
+ try {
+ ComboAddress remote(*dni.di.masters.begin());
+ if (dni.localaddr.sin4.sin_family == 0) {
+ return make_pair(dni.di.zone,
+ d_resolver.sendResolve(ComboAddress(*dni.di.masters.begin(), 53),
+ dni.di.zone,
+ QType::SOA,
+ dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
+ );
+ } else {
+ return make_pair(dni.di.zone,
+ d_resolver.sendResolve(ComboAddress(*dni.di.masters.begin(), 53), dni.localaddr,
+ dni.di.zone,
+ QType::SOA,
+ dni.dnssecOk, dni.tsigkeyname, dni.tsigalgname, dni.tsigsecret)
+ );
+ }
+ }
+ catch(PDNSException& e) {
+ throw runtime_error("While attempting to query freshness of '"+dni.di.zone.toString()+"': "+e.reason);
+ }
+ }
+
+ bool receive(Identifier& id, Answer& a)
+ {
+ if(d_resolver.tryGetSOASerial(&id.first, &a.theirSerial, &a.theirInception, &a.theirExpire, &id.second)) {
+ return 1;
+ }
+ return 0;
+ }
+
+ void deliverAnswer(DomainNotificationInfo& dni, const Answer& a, unsigned int usec)
+ {
+ d_freshness[dni.di.id]=a;
+ }
+
+ Resolver d_resolver;
+};
+
+void CommunicatorClass::addSlaveCheckRequest(const DomainInfo& di, const ComboAddress& remote)
+{
+ Lock l(&d_lock);
+ DomainInfo ours = di;
+ ours.backend = 0;
+ d_tocheck.insert(ours);
+ d_any_sem.post(); // kick the loop!
+}
+
+void CommunicatorClass::addTrySuperMasterRequest(DNSPacket *p)
+{
+ Lock l(&d_lock);
+ DNSPacket ours = *p;
+ d_potentialsupermasters.push_back(ours);
+ d_any_sem.post(); // kick the loop!
+}
+
+void CommunicatorClass::slaveRefresh(PacketHandler *P)
+{
+ // not unless we are slave
+ if (!::arg().mustDo("slave")) return;
+
+ UeberBackend *B=P->getBackend();
+ vector<DomainInfo> rdomains;
+ vector<DomainNotificationInfo> sdomains;
+ vector<DNSPacket> trysuperdomains;
+
+ {
+ Lock l(&d_lock);
+ rdomains.insert(rdomains.end(), d_tocheck.begin(), d_tocheck.end());
+ d_tocheck.clear();
+ trysuperdomains.insert(trysuperdomains.end(), d_potentialsupermasters.begin(), d_potentialsupermasters.end());
+ d_potentialsupermasters.clear();
+ }
+
+ for(DNSPacket& dp : trysuperdomains) {
+ // get the TSIG key name
+ TSIGRecordContent trc;
+ DNSName tsigkeyname;
+ string message;
+ dp.getTSIGDetails(&trc, &tsigkeyname, &message);
+ int res;
+ res=P->trySuperMasterSynchronous(&dp, tsigkeyname);
+ if(res>=0) {
+ DNSPacket *r=dp.replyPacket();
+ r->setRcode(res);
+ r->setOpcode(Opcode::Notify);
+ N->send(r);
+ delete r;
+ }
+ }
+ if(rdomains.empty()) { // if we have priority domains, check them first
+ B->getUnfreshSlaveInfos(&rdomains);
+ }
+ DNSSECKeeper dk(B); // NOW HEAR THIS! This DK uses our B backend, so no interleaved access!
+ {
+ Lock l(&d_lock);
+ domains_by_name_t& nameindex=boost::multi_index::get<IDTag>(d_suckdomains);
+
+ for(DomainInfo& di : rdomains) {
+ std::vector<std::string> localaddr;
+ SuckRequest sr;
+ sr.domain=di.zone;
+ if(di.masters.empty()) // slave domains w/o masters are ignored
+ continue;
+ // remove unfresh domains already queued for AXFR, no sense polling them again
+ sr.master=*di.masters.begin();
+ if(nameindex.count(sr)) { // this does NOT however protect us against AXFRs already in progress!
+ continue;
+ }
+ if(d_inprogress.count(sr.domain)) // this does
+ continue;
+
+ DomainNotificationInfo dni;
+ dni.di=di;
+ dni.dnssecOk = dk.doesDNSSEC();
+
+ if(dk.getTSIGForAccess(di.zone, sr.master, &dni.tsigkeyname)) {
+ string secret64;
+ B->getTSIGKey(dni.tsigkeyname, &dni.tsigalgname, &secret64);
+ B64Decode(secret64, dni.tsigsecret);
+ }
+
+ localaddr.clear();
+ // check for AXFR-SOURCE
+ if(B->getDomainMetadata(di.zone, "AXFR-SOURCE", localaddr) && !localaddr.empty()) {
+ try {
+ dni.localaddr = ComboAddress(localaddr[0]);
+ L<<Logger::Info<<"Freshness check source (AXFR-SOURCE) for domain '"<<di.zone<<"' set to "<<localaddr[0]<<endl;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"Failed to load freshness check source '"<<localaddr[0]<<"' for '"<<di.zone<<"': "<<e.what()<<endl;
+ return;
+ }
+ } else {
+ dni.localaddr.sin4.sin_family = 0;
+ }
+
+ sdomains.push_back(dni);
+ }
+ }
+ if(sdomains.empty())
+ {
+ if(d_slaveschanged) {
+ Lock l(&d_lock);
+ L<<Logger::Warning<<"No new unfresh slave domains, "<<d_suckdomains.size()<<" queued for AXFR already, "<<d_inprogress.size()<<" in progress"<<endl;
+ }
+ d_slaveschanged = !rdomains.empty();
+ return;
+ }
+ else {
+ Lock l(&d_lock);
+ L<<Logger::Warning<<sdomains.size()<<" slave domain"<<(sdomains.size()>1 ? "s" : "")<<" need"<<
+ (sdomains.size()>1 ? "" : "s")<<
+ " checking, "<<d_suckdomains.size()<<" queued for AXFR"<<endl;
+ }
+
+ SlaveSenderReceiver ssr;
+
+ Inflighter<vector<DomainNotificationInfo>, SlaveSenderReceiver> ifl(sdomains, ssr);
+
+ ifl.d_maxInFlight = 200;
+
+ for(;;) {
+ try {
+ ifl.run();
+ break;
+ }
+ catch(std::exception& e) {
+ L<<Logger::Error<<"While checking domain freshness: " << e.what()<<endl;
+ }
+ catch(PDNSException &re) {
+ L<<Logger::Error<<"While checking domain freshness: " << re.reason<<endl;
+ }
+ }
+ L<<Logger::Warning<<"Received serial number updates for "<<ssr.d_freshness.size()<<" zone"<<addS(ssr.d_freshness.size())<<", had "<<ifl.getTimeouts()<<" timeout"<<addS(ifl.getTimeouts())<<endl;
+
+ typedef DomainNotificationInfo val_t;
+ unsigned int now = time(0);
+ for(val_t& val : sdomains) {
+ DomainInfo& di(val.di);
+ // might've come from the packethandler
+ if(!di.backend && !B->getDomainInfo(di.zone, di)) {
+ L<<Logger::Warning<<"Ignore domain "<< di.zone<<" since it has been removed from our backend"<<endl;
+ continue;
+ }
+
+ if(!ssr.d_freshness.count(di.id)) // what does this mean? XXX
+ continue;
+ uint32_t theirserial = ssr.d_freshness[di.id].theirSerial, ourserial = di.serial;
+
+ if(rfc1982LessThan(theirserial, ourserial) && ourserial != 0 && !::arg().mustDo("axfr-lower-serial")) {
+ L<<Logger::Error<<"Domain '"<<di.zone<<"' more recent than master, our serial " << ourserial << " > their serial "<< theirserial << endl;
+ di.backend->setFresh(di.id);
+ }
+ else if(theirserial == ourserial) {
+ uint32_t maxExpire=0, maxInception=0;
+ if(dk.isPresigned(di.zone)) {
+ B->lookup(QType(QType::RRSIG), di.zone); // can't use DK before we are done with this lookup!
+ DNSResourceRecord rr;
+ while(B->get(rr)) {
+ RRSIGRecordContent rrc(rr.content);
+ if(rrc.d_type == QType::SOA) {
+ maxInception = std::max(maxInception, rrc.d_siginception);
+ maxExpire = std::max(maxExpire, rrc.d_sigexpire);
+ }
+ }
+ }
+ if(! maxInception && ! ssr.d_freshness[di.id].theirInception) {
+ L<<Logger::Info<<"Domain '"<< di.zone<<"' is fresh (no DNSSEC)"<<endl;
+ di.backend->setFresh(di.id);
+ }
+ else if(maxInception == ssr.d_freshness[di.id].theirInception && maxExpire == ssr.d_freshness[di.id].theirExpire) {
+ L<<Logger::Info<<"Domain '"<< di.zone<<"' is fresh and SOA RRSIGs match"<<endl;
+ di.backend->setFresh(di.id);
+ }
+ else if(maxExpire >= now && ! ssr.d_freshness[di.id].theirInception ) {
+ L<<Logger::Info<<"Domain '"<< di.zone<<"' is fresh, master is no longer signed but (some) signatures are still vallid"<<endl;
+ di.backend->setFresh(di.id);
+ }
+ else if(maxInception && ! ssr.d_freshness[di.id].theirInception ) {
+ L<<Logger::Warning<<"Domain '"<< di.zone<<"' is stale, master is no longer signed and all signatures have expired"<<endl;
+ addSuckRequest(di.zone, *di.masters.begin());
+ }
+ else if(dk.doesDNSSEC() && ! maxInception && ssr.d_freshness[di.id].theirInception) {
+ L<<Logger::Warning<<"Domain '"<< di.zone<<"' is stale, master has signed"<<endl;
+ addSuckRequest(di.zone, *di.masters.begin());
+ }
+ else {
+ L<<Logger::Warning<<"Domain '"<< di.zone<<"' is fresh, but RRSIGs differ, so DNSSEC is stale"<<endl;
+ addSuckRequest(di.zone, *di.masters.begin());
+ }
+ }
+ else {
+ L<<Logger::Warning<<"Domain '"<< di.zone<<"' is stale, master serial "<<theirserial<<", our serial "<< ourserial <<endl;
+ addSuckRequest(di.zone, *di.masters.begin());
+ }
+ }
+}
+
+// stub for PowerDNSLua linking
+int directResolve(const std::string& qname, const QType& qtype, int qclass, vector<DNSResourceRecord>& ret)
+{
+ return -1;
+}
+
+
--- /dev/null
+extern "C" {
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <sodium.h>
+}
+#include "dnssecinfra.hh"
+
+class SodiumED25519DNSCryptoKeyEngine : public DNSCryptoKeyEngine
+{
+public:
+ explicit SodiumED25519DNSCryptoKeyEngine(unsigned int algo) : DNSCryptoKeyEngine(algo)
+ {}
+ string getName() const override { return "Sodium ED25519"; }
+ void create(unsigned int bits) override;
+ storvector_t convertToISCVector() const override;
+ std::string getPubKeyHash() const override;
+ std::string sign(const std::string& msg) const override;
+ bool verify(const std::string& msg, const std::string& signature) const override;
+ std::string getPublicKeyString() const override;
+ int getBits() const override;
+ void fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap) override;
+ void fromPublicKeyString(const std::string& content) override;
+ void fromPEMString(DNSKEYRecordContent& drc, const std::string& raw) override
+ {}
+
+ static std::shared_ptr<DNSCryptoKeyEngine> maker(unsigned int algorithm)
+ {
+ return std::make_shared<SodiumED25519DNSCryptoKeyEngine>(algorithm);
+ }
+
+private:
+ unsigned char d_pubkey[crypto_sign_ed25519_PUBLICKEYBYTES];
+ unsigned char d_seckey[crypto_sign_ed25519_SECRETKEYBYTES];
+};
+
+void SodiumED25519DNSCryptoKeyEngine::create(unsigned int bits)
+{
+ if(bits != crypto_sign_ed25519_SEEDBYTES * 8) {
+ throw runtime_error("Unsupported key length of "+std::to_string(bits)+" bits requested, SodiumED25519 class");
+ }
+ crypto_sign_ed25519_keypair(d_pubkey, d_seckey);
+}
+
+int SodiumED25519DNSCryptoKeyEngine::getBits() const
+{
+ return crypto_sign_ed25519_SEEDBYTES * 8;
+}
+
+DNSCryptoKeyEngine::storvector_t SodiumED25519DNSCryptoKeyEngine::convertToISCVector() const
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=
+ */
+
+ storvector_t storvector;
+ string algorithm = "15 (ED25519)";
+
+ storvector.push_back(make_pair("Algorithm", algorithm));
+
+ vector<unsigned char> buffer;
+ storvector.push_back(make_pair("PrivateKey", string((char*)d_seckey, crypto_sign_ed25519_SEEDBYTES)));
+ return storvector;
+}
+
+void SodiumED25519DNSCryptoKeyEngine::fromISCMap(DNSKEYRecordContent& drc, std::map<std::string, std::string>& stormap )
+{
+ /*
+ Private-key-format: v1.2
+ Algorithm: 15 (ED25519)
+ PrivateKey: GU6SnQ/Ou+xC5RumuIUIuJZteXT2z0O/ok1s38Et6mQ=
+ */
+
+ drc.d_algorithm = pdns_stou(stormap["algorithm"]);
+ string privateKey = stormap["privatekey"];
+
+ if (privateKey.length() != crypto_sign_ed25519_SEEDBYTES)
+ throw runtime_error("Seed size mismatch in ISCMap, SodiumED25519 class");
+
+ std::unique_ptr<unsigned char[]> seed(new unsigned char[crypto_sign_ed25519_SEEDBYTES]);
+
+ memcpy(seed.get(), privateKey.c_str(), crypto_sign_ed25519_SEEDBYTES);
+ crypto_sign_ed25519_seed_keypair(d_pubkey, d_seckey, seed.get());
+}
+
+std::string SodiumED25519DNSCryptoKeyEngine::getPubKeyHash() const
+{
+ return this->getPublicKeyString();
+}
+
+std::string SodiumED25519DNSCryptoKeyEngine::getPublicKeyString() const
+{
+ return string((char*)d_pubkey, crypto_sign_ed25519_PUBLICKEYBYTES);
+}
+
+void SodiumED25519DNSCryptoKeyEngine::fromPublicKeyString(const std::string& input)
+{
+ if (input.length() != crypto_sign_ed25519_PUBLICKEYBYTES)
+ throw runtime_error("Public key size mismatch, SodiumED25519 class");
+
+ memcpy(d_pubkey, input.c_str(), crypto_sign_ed25519_PUBLICKEYBYTES);
+}
+
+std::string SodiumED25519DNSCryptoKeyEngine::sign(const std::string& msg) const
+{
+ unsigned long long smlen = msg.length() + crypto_sign_ed25519_BYTES;
+ std::unique_ptr<unsigned char[]> sm(new unsigned char[smlen]);
+
+ crypto_sign_ed25519(sm.get(), &smlen, (const unsigned char*)msg.c_str(), msg.length(), d_seckey);
+
+ return string((const char*)sm.get(), crypto_sign_ed25519_BYTES);
+}
+
+bool SodiumED25519DNSCryptoKeyEngine::verify(const std::string& msg, const std::string& signature) const
+{
+ if (signature.length() != crypto_sign_ed25519_BYTES)
+ return false;
+
+ unsigned long long smlen = msg.length() + crypto_sign_ed25519_BYTES;
+ std::unique_ptr<unsigned char[]> sm(new unsigned char[smlen]);
+
+ memcpy(sm.get(), signature.c_str(), crypto_sign_ed25519_BYTES);
+ memcpy(sm.get() + crypto_sign_ed25519_BYTES, msg.c_str(), msg.length());
+
+ std::unique_ptr<unsigned char[]> m(new unsigned char[smlen]);
+
+ return crypto_sign_ed25519_open(m.get(), &smlen, sm.get(), smlen, d_pubkey) == 0;
+}
+
+namespace {
+struct LoaderSodiumStruct
+{
+ LoaderSodiumStruct()
+ {
+ DNSCryptoKeyEngine::report(15, &SodiumED25519DNSCryptoKeyEngine::maker);
+ }
+} loadersodium;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "iputils.hh"
+#include "dnsrecords.hh"
+
+struct SortListOrder
+{
+ NetmaskTree<int> d_orders;
+};
+
+
+struct SortListOrderCmp
+{
+ SortListOrderCmp(SortListOrder slo) : d_slo(slo) {}
+ bool operator()(const ComboAddress& a, const ComboAddress& b) const;
+ bool operator()(const DNSRecord& a, const DNSRecord& b) const;
+ const SortListOrder d_slo;
+};
+
+class SortList {
+public:
+ void clear();
+ void addEntry(const Netmask& covers, const Netmask& answermask, int order=-1);
+ int getMaxOrder(const Netmask& formask) const;
+ std::unique_ptr<SortListOrderCmp> getOrderCmp(const ComboAddress& who) const;
+private:
+
+ NetmaskTree<SortListOrder> d_sortlist;
+};
--- /dev/null
+#include "config.h"
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include <boost/format.hpp>
+#ifndef RECURSOR
+#include "statbag.hh"
+#include "base64.hh"
+StatBag S;
+#endif
+
+volatile bool g_ret; // make sure the optimizer does not get too smart
+uint64_t g_totalRuns;
+
+volatile bool g_stop;
+
+void alarmHandler(int)
+{
+ g_stop=true;
+}
+
+template<typename C> void doRun(const C& cmd, int mseconds=100)
+{
+ struct itimerval it;
+ it.it_value.tv_sec=mseconds/1000;
+ it.it_value.tv_usec = 1000* (mseconds%1000);
+ it.it_interval.tv_sec=0;
+ it.it_interval.tv_usec=0;
+
+ signal(SIGVTALRM, alarmHandler);
+ setitimer(ITIMER_VIRTUAL, &it, 0);
+
+ unsigned int runs=0;
+ g_stop=false;
+ CPUTime dt;
+ dt.start();
+ while(runs++, !g_stop) {
+ cmd();
+ }
+ double delta=dt.ndiff()/1000000000.0;
+ boost::format fmt("'%s' %.02f seconds: %.1f runs/s, %.02f usec/run");
+
+ cerr<< (fmt % cmd.getName() % delta % (runs/delta) % (delta* 1000000.0/runs)) << endl;
+ g_totalRuns += runs;
+}
+
+struct ARecordTest
+{
+ explicit ARecordTest(int records) : d_records(records) {}
+
+ string getName() const
+ {
+ return (boost::format("%d a records") % d_records).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::A);
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(DNSName("outpost.ds9a.nl"), QType::A);
+ ARecordContent arc("1.2.3.4");
+ arc.toPacket(pw);
+ }
+ pw.commit();
+ }
+ int d_records;
+};
+
+
+struct MakeStringFromCharStarTest
+{
+ MakeStringFromCharStarTest() : d_size(0){}
+ string getName() const
+ {
+ return (boost::format("make a std::string")).str();
+ }
+
+ void operator()() const
+ {
+ string name("outpost.ds9a.nl");
+ d_size += name.length();
+
+ }
+ mutable int d_size;
+};
+
+
+struct GetTimeTest
+{
+ string getName() const
+ {
+ return "gettimeofday-test";
+ }
+
+ void operator()() const
+ {
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ }
+};
+
+pthread_mutex_t s_testlock=PTHREAD_MUTEX_INITIALIZER;
+
+struct GetLockUncontendedTest
+{
+ string getName() const
+ {
+ return "getlock-uncontended-test";
+ }
+
+ void operator()() const
+ {
+ pthread_mutex_lock(&s_testlock);
+ pthread_mutex_unlock(&s_testlock);
+ }
+};
+
+
+struct StaticMemberTest
+{
+ string getName() const
+ {
+ return "static-member-test";
+ }
+
+ void operator()() const
+ {
+ static string* s_ptr;
+ if(!s_ptr)
+ s_ptr = new string();
+ }
+};
+
+struct StringtokTest
+{
+ string getName() const
+ {
+ return "stringtok";
+ }
+
+ void operator()() const
+ {
+ string str("the quick brown fox jumped");
+ vector<string> parts;
+ stringtok(parts, str);
+ }
+};
+
+struct VStringtokTest
+{
+ string getName() const
+ {
+ return "vstringtok";
+ }
+
+ void operator()() const
+ {
+ string str("the quick brown fox jumped");
+ vector<pair<unsigned int, unsigned> > parts;
+ vstringtok(parts, str);
+ }
+};
+
+struct StringAppendTest
+{
+ string getName() const
+ {
+ return "stringappend";
+ }
+
+ void operator()() const
+ {
+ string str;
+ static char i;
+ for(int n=0; n < 1000; ++n)
+ str.append(1, i);
+ i++;
+ }
+};
+
+
+struct MakeARecordTest
+{
+ string getName() const
+ {
+ return (boost::format("make a-record")).str();
+ }
+
+ void operator()() const
+ {
+ static string src("1.2.3.4");
+ ARecordContent arc(src);
+ //ARecordContent arc(0x01020304);
+
+ }
+};
+
+struct MakeARecordTestMM
+{
+ string getName() const
+ {
+ return (boost::format("make a-record (mm)")).str();
+ }
+
+ void operator()() const
+ {
+ DNSRecordContent*drc = DNSRecordContent::mastermake(QType::A, 1,
+ "1.2.3.4");
+ delete drc;
+ }
+};
+
+
+struct A2RecordTest
+{
+ explicit A2RecordTest(int records) : d_records(records) {}
+
+ string getName() const
+ {
+ return (boost::format("%d a records") % d_records).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::A);
+ ARecordContent arc("1.2.3.4");
+ DNSName name("outpost.ds9a.nl");
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(name, QType::A);
+
+ arc.toPacket(pw);
+ }
+ pw.commit();
+ }
+ int d_records;
+};
+
+
+struct TXTRecordTest
+{
+ explicit TXTRecordTest(int records) : d_records(records) {}
+
+ string getName() const
+ {
+ return (boost::format("%d TXT records") % d_records).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::TXT);
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(DNSName("outpost.ds9a.nl"), QType::TXT);
+ TXTRecordContent arc("\"een leuk verhaaltje in een TXT\"");
+ arc.toPacket(pw);
+ }
+ pw.commit();
+ }
+ int d_records;
+};
+
+
+struct GenericRecordTest
+{
+ explicit GenericRecordTest(int records, uint16_t type, const std::string& content)
+ : d_records(records), d_type(type), d_content(content) {}
+
+ string getName() const
+ {
+ return (boost::format("%d %s records") % d_records %
+ DNSRecordContent::NumberToType(d_type)).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), d_type);
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(DNSName("outpost.ds9a.nl"), d_type);
+ DNSRecordContent*drc = DNSRecordContent::mastermake(d_type, 1,
+ d_content);
+ drc->toPacket(pw);
+ delete drc;
+ }
+ pw.commit();
+ }
+ int d_records;
+ uint16_t d_type;
+ string d_content;
+};
+
+
+struct AAAARecordTest
+{
+ explicit AAAARecordTest(int records) : d_records(records) {}
+
+ string getName() const
+ {
+ return (boost::format("%d aaaa records (mm)") % d_records).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::AAAA);
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(DNSName("outpost.ds9a.nl"), QType::AAAA);
+ DNSRecordContent*drc = DNSRecordContent::mastermake(QType::AAAA, 1, "fe80::21d:92ff:fe6d:8441");
+ drc->toPacket(pw);
+ delete drc;
+ }
+ pw.commit();
+ }
+ int d_records;
+};
+
+struct SOARecordTest
+{
+ explicit SOARecordTest(int records) : d_records(records) {}
+
+ string getName() const
+ {
+ return (boost::format("%d soa records (mm)") % d_records).str();
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::SOA);
+
+ for(int records = 0; records < d_records; records++) {
+ pw.startRecord(DNSName("outpost.ds9a.nl"), QType::SOA);
+ DNSRecordContent*drc = DNSRecordContent::mastermake(QType::SOA, 1, "a0.org.afilias-nst.info. noc.afilias-nst.info. 2008758137 1800 900 604800 86400");
+ drc->toPacket(pw);
+ delete drc;
+ }
+ pw.commit();
+ }
+ int d_records;
+};
+
+vector<uint8_t> makeEmptyQuery()
+{
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::SOA);
+ return packet;
+}
+
+vector<uint8_t> makeTypicalReferral()
+{
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("outpost.ds9a.nl"), QType::A);
+
+ pw.startRecord(DNSName("ds9a.nl"), QType::NS, 3600, 1, DNSResourceRecord::AUTHORITY);
+ DNSRecordContent* drc = DNSRecordContent::mastermake(QType::NS, 1, "ns1.ds9a.nl");
+ drc->toPacket(pw);
+ delete drc;
+
+ pw.startRecord(DNSName("ds9a.nl"), QType::NS, 3600, 1, DNSResourceRecord::AUTHORITY);
+ drc = DNSRecordContent::mastermake(QType::NS, 1, "ns2.ds9a.nl");
+ drc->toPacket(pw);
+ delete drc;
+
+
+ pw.startRecord(DNSName("ns1.ds9a.nl"), QType::A, 3600, 1, DNSResourceRecord::ADDITIONAL);
+ drc = DNSRecordContent::mastermake(QType::A, 1, "1.2.3.4");
+ drc->toPacket(pw);
+ delete drc;
+
+ pw.startRecord(DNSName("ns2.ds9a.nl"), QType::A, 3600, 1, DNSResourceRecord::ADDITIONAL);
+ drc = DNSRecordContent::mastermake(QType::A, 1, "4.3.2.1");
+ drc->toPacket(pw);
+ delete drc;
+
+ pw.commit();
+ return packet;
+}
+
+struct StackMallocTest
+{
+ string getName() const
+ {
+ return "stack allocation";
+ }
+
+ void operator()() const
+ {
+ char *buffer= new char[200000];
+ delete[] buffer;
+ }
+
+};
+
+
+struct EmptyQueryTest
+{
+ string getName() const
+ {
+ return "write empty query";
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet=makeEmptyQuery();
+ }
+
+};
+
+struct TypicalRefTest
+{
+ string getName() const
+ {
+ return "write typical referral";
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> packet=makeTypicalReferral();
+ }
+
+};
+
+struct TCacheComp
+{
+ bool operator()(const pair<string, QType>& a, const pair<string, QType>& b) const
+ {
+ int cmp=strcasecmp(a.first.c_str(), b.first.c_str());
+ if(cmp < 0)
+ return true;
+ if(cmp > 0)
+ return false;
+
+ return a.second < b.second;
+ }
+};
+
+struct NegCacheEntry
+{
+ DNSName d_name;
+ QType d_qtype;
+ DNSName d_qname;
+ uint32_t d_ttd;
+};
+
+struct timeval d_now;
+
+
+
+struct ParsePacketTest
+{
+ explicit ParsePacketTest(const vector<uint8_t>& packet, const std::string& name)
+ : d_packet(packet), d_name(name)
+ {}
+
+ string getName() const
+ {
+ return "parse '"+d_name+"'";
+ }
+
+ void operator()() const
+ {
+ MOADNSParser mdp(false, (const char*)&*d_packet.begin(), d_packet.size());
+ typedef map<pair<DNSName, QType>, set<DNSResourceRecord>, TCacheComp > tcache_t;
+ tcache_t tcache;
+
+ struct {
+ vector<DNSResourceRecord> d_result;
+ bool d_aabit;
+ int d_rcode;
+ } lwr;
+ DNSResourceRecord rr;
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ DNSResourceRecord rr;
+ rr.qtype=i->first.d_type;
+ rr.qname=i->first.d_name;
+
+ rr.ttl=i->first.d_ttl;
+ rr.content=i->first.d_content->getZoneRepresentation(); // this should be the serialised form
+ rr.d_place=(DNSResourceRecord::Place) i->first.d_place;
+ lwr.d_result.push_back(rr);
+ }
+
+
+ }
+ const vector<uint8_t>& d_packet;
+ std::string d_name;
+};
+
+struct ParsePacketBareTest
+{
+ explicit ParsePacketBareTest(const vector<uint8_t>& packet, const std::string& name)
+ : d_packet(packet), d_name(name)
+ {}
+
+ string getName() const
+ {
+ return "parse '"+d_name+"' bare";
+ }
+
+ void operator()() const
+ {
+ MOADNSParser mdp(false, (const char*)&*d_packet.begin(), d_packet.size());
+ }
+ const vector<uint8_t>& d_packet;
+ std::string d_name;
+};
+
+
+struct SimpleCompressTest
+{
+ explicit SimpleCompressTest(const std::string& name)
+ : d_name(name)
+ {}
+
+ string getName() const
+ {
+ return "compress '"+d_name+"'";
+ }
+
+ void operator()() const
+ {
+ simpleCompress(d_name);
+ }
+ std::string d_name;
+};
+
+struct VectorExpandTest
+{
+ string getName() const
+ {
+ return "vector expand";
+ }
+
+ void operator()() const
+ {
+ vector<uint8_t> d_record;
+ d_record.resize(12);
+
+ string out="\x03www\x04ds9a\x02nl";
+ string::size_type len = d_record.size();
+ d_record.resize(len + out.length());
+ memcpy(&d_record[len], out.c_str(), out.length());
+ }
+
+};
+
+struct DNSNameParseTest
+{
+ string getName() const
+ {
+ return "DNSName parse";
+ }
+
+ void operator()() const
+ {
+ DNSName name("www.powerdns.com");
+ }
+
+};
+
+struct DNSNameRootTest
+{
+ string getName() const
+ {
+ return "DNSName root";
+ }
+
+ void operator()() const
+ {
+ DNSName name(".");
+ }
+
+};
+
+
+
+struct IEqualsTest
+{
+ string getName() const
+ {
+ return "iequals test";
+ }
+
+ void operator()() const
+ {
+ static string a("www.ds9a.nl"), b("www.lwn.net");
+ g_ret = boost::iequals(a, b);
+ }
+
+};
+
+struct MyIEqualsTest
+{
+ string getName() const
+ {
+ return "pdns_iequals test";
+ }
+
+ void operator()() const
+ {
+ static string a("www.ds9a.nl"), b("www.lwn.net");
+ g_ret = pdns_iequals(a, b);
+ }
+
+};
+
+
+struct StrcasecmpTest
+{
+ string getName() const
+ {
+ return "strcasecmp test";
+ }
+
+ void operator()() const
+ {
+ static string a("www.ds9a.nl"), b("www.lwn.net");
+ g_ret = strcasecmp(a.c_str(), b.c_str());
+ }
+};
+
+
+struct Base64EncodeTest
+{
+ string getName() const
+ {
+ return "Bas64Encode test";
+ }
+
+ void operator()() const
+ {
+ static string a("dq4KydZjmcoQQ45VYBP2EDR8FqKaMul0eSHBt7Xx5F7A4HFtabXEzDLD01bnSiGK");
+ Base64Encode(a);
+ }
+};
+
+
+struct B64DecodeTest
+{
+ string getName() const
+ {
+ return "B64Decode test";
+ }
+
+ void operator()() const
+ {
+ static string a("ZHE0S3lkWmptY29RUTQ1VllCUDJFRFI4RnFLYU11bDBlU0hCdDdYeDVGN0E0SEZ0YWJYRXpETEQwMWJuU2lHSw=="), b;
+ g_ret = B64Decode(a,b);
+ }
+};
+
+
+struct NOPTest
+{
+ string getName() const
+ {
+ return "null test";
+ }
+
+ void operator()() const
+ {
+ }
+
+};
+
+
+
+int main(int argc, char** argv)
+try
+{
+ reportAllTypes();
+
+ doRun(NOPTest());
+
+ doRun(IEqualsTest());
+ doRun(MyIEqualsTest());
+ doRun(StrcasecmpTest());
+ doRun(Base64EncodeTest());
+ doRun(B64DecodeTest());
+
+ doRun(StackMallocTest());
+
+ doRun(EmptyQueryTest());
+ doRun(TypicalRefTest());
+
+
+ auto packet = makeEmptyQuery();
+ doRun(ParsePacketTest(packet, "empty-query"));
+
+ packet = makeTypicalReferral();
+ cerr<<"typical referral size: "<<packet.size()<<endl;
+ doRun(ParsePacketBareTest(packet, "typical-referral"));
+
+ doRun(ParsePacketTest(packet, "typical-referral"));
+
+ doRun(SimpleCompressTest("www.france.ds9a.nl"));
+
+
+ doRun(VectorExpandTest());
+
+ doRun(GetTimeTest());
+
+ doRun(GetLockUncontendedTest());
+ doRun(StaticMemberTest());
+
+ doRun(ARecordTest(1));
+ doRun(ARecordTest(2));
+ doRun(ARecordTest(4));
+ doRun(ARecordTest(64));
+
+ doRun(A2RecordTest(1));
+ doRun(A2RecordTest(2));
+ doRun(A2RecordTest(4));
+ doRun(A2RecordTest(64));
+
+ doRun(MakeStringFromCharStarTest());
+ doRun(MakeARecordTest());
+ doRun(MakeARecordTestMM());
+
+ doRun(AAAARecordTest(1));
+ doRun(AAAARecordTest(2));
+ doRun(AAAARecordTest(4));
+ doRun(AAAARecordTest(64));
+
+ doRun(TXTRecordTest(1));
+ doRun(TXTRecordTest(2));
+ doRun(TXTRecordTest(4));
+ doRun(TXTRecordTest(64));
+
+ doRun(GenericRecordTest(1, QType::NS, "powerdnssec1.ds9a.nl"));
+ doRun(GenericRecordTest(2, QType::NS, "powerdnssec1.ds9a.nl"));
+ doRun(GenericRecordTest(4, QType::NS, "powerdnssec1.ds9a.nl"));
+ doRun(GenericRecordTest(64, QType::NS, "powerdnssec1.ds9a.nl"));
+
+
+
+ doRun(SOARecordTest(1));
+ doRun(SOARecordTest(2));
+ doRun(SOARecordTest(4));
+ doRun(SOARecordTest(64));
+
+ doRun(StringtokTest());
+ doRun(VStringtokTest());
+ doRun(StringAppendTest());
+
+ doRun(DNSNameParseTest());
+ doRun(DNSNameRootTest());
+
+ cerr<<"Total runs: " << g_totalRuns<<endl;
+
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+
--- /dev/null
+/* SQLite backend for PowerDNS
+ * Copyright (C) 2003, Michel Stol <michel@powerdns.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.
+ *
+ * Additionally, the license of this program contains a special
+ * exception which allows to distribute the program in binary form when
+ * it is linked against OpenSSL.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <string>
+#include <sstream>
+#include "ssqlite3.hh"
+#include <iostream>
+#include <fstream>
+#include "pdns/logger.hh"
+#include "misc.hh"
+#include "utility.hh"
+#include <unistd.h>
+
+/*
+** Set all the parameters in the compiled SQL statement to NULL.
+*
+* copied from sqlite 3.3.6 // cmouse
+*/
+int pdns_sqlite3_clear_bindings(sqlite3_stmt *pStmt){
+ int i;
+ int rc = SQLITE_OK;
+ for(i=1; rc==SQLITE_OK && i<=sqlite3_bind_parameter_count(pStmt); i++){
+ rc = sqlite3_bind_null(pStmt, i);
+ }
+ return rc;
+}
+
+class SSQLite3Statement: public SSqlStatement
+{
+public:
+ SSQLite3Statement(SSQLite3 *db, bool dolog, const string& query) : d_prepared(false)
+ {
+ this->d_query = query;
+ this->d_dolog = dolog;
+ d_stmt = NULL;
+ d_rc = 0;
+ d_db = db;
+ }
+
+ int name2idx(const string& name) {
+ string zName = string(":")+name;
+ prepareStatement();
+ return sqlite3_bind_parameter_index(d_stmt, zName.c_str());
+ // XXX: support @ and $?
+ }
+
+ SSqlStatement* bind(const string& name, bool value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int(d_stmt, idx, value ? 1 : 0); }; return this; }
+ SSqlStatement* bind(const string& name, int value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int(d_stmt, idx, value); }; return this; }
+ SSqlStatement* bind(const string& name, uint32_t value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; }
+ SSqlStatement* bind(const string& name, long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; }
+ SSqlStatement* bind(const string& name, unsigned long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; }
+ SSqlStatement* bind(const string& name, long long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; };
+ SSqlStatement* bind(const string& name, unsigned long long value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_int64(d_stmt, idx, value); }; return this; }
+ SSqlStatement* bind(const string& name, const std::string& value) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_text(d_stmt, idx, value.c_str(), value.size(), SQLITE_TRANSIENT); }; return this; }
+ SSqlStatement* bindNull(const string& name) { int idx = name2idx(name); if (idx>0) { sqlite3_bind_null(d_stmt, idx); }; return this; }
+
+ SSqlStatement* execute() {
+ prepareStatement();
+ if (d_dolog)
+ L<<Logger::Warning<< "Query: " << d_query << endl;
+ int attempts = d_db->inTransaction(); // try only once
+ while(attempts < 2 && (d_rc = sqlite3_step(d_stmt)) == SQLITE_BUSY) attempts++;
+
+ if (d_rc != SQLITE_ROW && d_rc != SQLITE_DONE) {
+ // failed.
+ releaseStatement();
+ if (d_rc == SQLITE_CANTOPEN)
+ throw SSqlException(string("CANTOPEN error in sqlite3, often caused by unwritable sqlite3 db *directory*: ")+string(sqlite3_errmsg(d_db->db())));
+ throw SSqlException(string("Error while retrieving SQLite query results: ")+string(sqlite3_errmsg(d_db->db())));
+ }
+ return this;
+ }
+ bool hasNextRow() { return d_rc == SQLITE_ROW; }
+
+ SSqlStatement* nextRow(row_t& row) {
+ row.clear();
+ int numCols = sqlite3_column_count(d_stmt);
+ row.reserve(numCols); // preallocate memory
+ // Another row received, process it.
+ for ( int i=0; i<numCols; i++)
+ {
+ if (sqlite3_column_type(d_stmt,i) == SQLITE_NULL) {
+ row.push_back("");
+ } else {
+ const char *pData = (const char*) sqlite3_column_text(d_stmt, i);
+ row.push_back(string(pData, sqlite3_column_bytes(d_stmt, i)));
+ }
+ }
+ d_rc = sqlite3_step(d_stmt);
+ return this;
+ }
+
+ SSqlStatement* getResult(result_t& result) {
+ result.clear();
+ while(hasNextRow()) {
+ row_t row;
+ nextRow(row);
+ result.push_back(row);
+ }
+ return this;
+ }
+
+ SSqlStatement* reset() {
+ sqlite3_reset(d_stmt);
+#if SQLITE_VERSION_NUMBER >= 3003009
+ sqlite3_clear_bindings(d_stmt);
+#else
+ pdns_sqlite3_clear_bindings(d_stmt);
+#endif
+ return this;
+ }
+
+ ~SSQLite3Statement() {
+ // deallocate if necessary
+ releaseStatement();
+ }
+
+ const string& getQuery() { return d_query; };
+private:
+ string d_query;
+ sqlite3_stmt* d_stmt;
+ SSQLite3* d_db;
+ int d_rc;
+ bool d_dolog;
+ bool d_prepared;
+
+ void prepareStatement() {
+ const char *pTail;
+
+ if (d_prepared) return;
+#if SQLITE_VERSION_NUMBER >= 3003009
+ if (sqlite3_prepare_v2(d_db->db(), d_query.c_str(), -1, &d_stmt, &pTail ) != SQLITE_OK)
+#else
+ if (sqlite3_prepare(d_db->db(), d_query.c_str(), -1, &d_stmt, &pTail ) != SQLITE_OK)
+#endif
+ {
+ releaseStatement();
+ throw SSqlException(string("Unable to compile SQLite statement : '")+d_query+"': "+sqlite3_errmsg(d_db->db()));
+ }
+ if (pTail && strlen(pTail)>0)
+ L<<Logger::Warning<<"Sqlite3 command partially processed. Unprocessed part: "<<pTail<<endl;
+ d_prepared = true;
+ }
+
+ void releaseStatement() {
+ if (d_stmt)
+ sqlite3_finalize(d_stmt);
+ d_stmt = NULL;
+ d_prepared = false;
+ }
+};
+
+// Constructor.
+SSQLite3::SSQLite3( const std::string & database, bool creat )
+{
+ if (access( database.c_str(), F_OK ) == -1){
+ if (!creat)
+ throw sPerrorException( "SQLite database '"+database+"' does not exist yet" );
+ } else {
+ if (creat)
+ throw sPerrorException( "SQLite database '"+database+"' already exists" );
+ }
+
+ if ( sqlite3_open( database.c_str(), &m_pDB)!=SQLITE_OK )
+ throw sPerrorException( "Could not connect to the SQLite database '" + database + "'" );
+ m_dolog = 0;
+ m_in_transaction = false;
+ sqlite3_busy_handler(m_pDB, busyHandler, 0);
+}
+
+void SSQLite3::setLog(bool state)
+{
+ m_dolog=state;
+}
+
+// Destructor.
+SSQLite3::~SSQLite3()
+{
+ int ret;
+ for(int n = 0; n < 2 ; ++n) {
+ if((ret =sqlite3_close( m_pDB )) != SQLITE_OK) {
+ if(n || ret != SQLITE_BUSY) { // if we have SQLITE_BUSY, and a working m_Pstmt, try finalize
+ cerr<<"Unable to close down sqlite connection: "<<ret<<endl;
+ abort();
+ }
+ }
+ else
+ break;
+ }
+}
+
+SSqlStatement* SSQLite3::prepare(const string& query, int nparams __attribute__((unused))) {
+ return new SSQLite3Statement(this, m_dolog, query);
+}
+
+void SSQLite3::execute(const string& query) {
+ char *errmsg;
+ int rc;
+ if (sqlite3_exec(m_pDB, query.c_str(), NULL, NULL, &errmsg) == SQLITE_BUSY) {
+ if (m_in_transaction) {
+ throw("Failed to execute query: " + string(errmsg));
+ } else {
+ if ((rc = sqlite3_exec(m_pDB, query.c_str(), NULL, NULL, &errmsg) != SQLITE_OK) && rc != SQLITE_DONE && rc != SQLITE_ROW)
+ throw("Failed to execute query: " + string(errmsg));
+ }
+ }
+}
+
+int SSQLite3::busyHandler(void*, int)
+{
+ Utility::usleep(1000);
+ return 1;
+}
+
+void SSQLite3::startTransaction() {
+ execute("begin");
+ m_in_transaction = true;
+}
+
+void SSQLite3::rollback() {
+ execute("rollback");
+ m_in_transaction = false;
+}
+
+void SSQLite3::commit() {
+ execute("commit");
+ m_in_transaction = false;
+}
+
+// Constructs a SSqlException object.
+SSqlException SSQLite3::sPerrorException( const std::string & reason )
+{
+ return SSqlException( reason );
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SSQLITE3_HH
+#define SSQLITE3_HH
+
+#include <sqlite3.h>
+#include "pdns/backends/gsql/ssql.hh"
+
+class SSQLite3 : public SSql
+{
+private:
+ //! Pointer to the SQLite database instance.
+ sqlite3 *m_pDB;
+
+ bool m_dolog;
+ bool m_in_transaction;
+ static int busyHandler(void*, int);
+protected:
+public:
+ //! Constructor.
+ SSQLite3( const std::string & database, bool creat=false );
+
+ //! Destructor.
+ ~SSQLite3();
+
+ SSqlStatement* prepare(const string& query, int nparams);
+ void execute(const string& query);
+ void setLog(bool state);
+
+ void startTransaction();
+ void commit();
+ void rollback();
+
+ sqlite3 *db() { return this->m_pDB; };
+
+ bool inTransaction() { return m_in_transaction; };
+
+ //! Used to create an backend specific exception message.
+ SSqlException sPerrorException( const std::string & reason );
+};
+
+#endif // SSQLITE3_HH
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef SSTUFF_HH
+#define SSTUFF_HH
+
+#include <string>
+#include <sstream>
+#include <iostream>
+#include "iputils.hh"
+#include <errno.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/select.h>
+#include <fcntl.h>
+#include <stdexcept>
+
+#include <boost/utility.hpp>
+#include <csignal>
+#include "namespaces.hh"
+#include "namespaces.hh"
+
+
+class NetworkError : public runtime_error
+{
+public:
+ NetworkError(const string& why="Network Error") : runtime_error(why.c_str())
+ {}
+ NetworkError(const char *why="Network Error") : runtime_error(why)
+ {}
+};
+
+
+typedef int ProtocolType; //!< Supported protocol types
+
+//! Representation of a Socket and many of the Berkeley functions available
+class Socket : public boost::noncopyable
+{
+ Socket(int fd)
+ {
+ d_socket = fd;
+ d_buflen=4096;
+ d_buffer=new char[d_buflen];
+ }
+
+public:
+ //! Construct a socket of specified address family and socket type.
+ Socket(int af, int st, ProtocolType pt=0)
+ {
+ if((d_socket=socket(af,st, pt))<0)
+ throw NetworkError(strerror(errno));
+ setCloseOnExec(d_socket);
+
+ d_buflen=4096;
+ d_buffer=new char[d_buflen];
+ }
+
+ ~Socket()
+ {
+ try {
+ closesocket(d_socket);
+ }
+ catch(const PDNSException& e) {
+ }
+
+ delete[] d_buffer;
+ }
+
+ //! If the socket is capable of doing so, this function will wait for a connection
+ Socket *accept()
+ {
+ struct sockaddr_in remote;
+ socklen_t remlen=sizeof(remote);
+ memset(&remote, 0, sizeof(remote));
+ int s=::accept(d_socket,(sockaddr *)&remote, &remlen);
+ if(s<0) {
+ if(errno==EAGAIN)
+ return 0;
+
+ throw NetworkError("Accepting a connection: "+string(strerror(errno)));
+ }
+
+ return new Socket(s);
+ }
+
+ //! Get remote address
+ bool getRemote(ComboAddress &remote) {
+ socklen_t remotelen=sizeof(remote);
+ return (getpeername(d_socket, (struct sockaddr *)&remote, &remotelen) >= 0);
+ }
+
+ //! Check remote address aganst netmaskgroup ng
+ bool acl(NetmaskGroup &ng)
+ {
+ ComboAddress remote;
+ if (getRemote(remote))
+ return ng.match((ComboAddress *) &remote);
+
+ return false;
+ }
+
+ //! Set the socket to non-blocking
+ void setNonBlocking()
+ {
+ ::setNonBlocking(d_socket);
+ }
+ //! Set the socket to blocking
+ void setBlocking()
+ {
+ ::setBlocking(d_socket);
+ }
+
+ void setReuseAddr()
+ {
+ int tmp = 1;
+ if (setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&tmp, static_cast<unsigned>(sizeof tmp))<0)
+ throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
+ }
+
+ //! Bind the socket to a specified endpoint
+ void bind(const ComboAddress &local)
+ {
+ int tmp=1;
+ if(setsockopt(d_socket, SOL_SOCKET, SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0)
+ throw NetworkError(string("Setsockopt failed: ")+strerror(errno));
+
+ if(::bind(d_socket,(struct sockaddr *)&local, local.getSocklen())<0)
+ throw NetworkError("While binding: "+string(strerror(errno)));
+ }
+
+#if 0
+ //! Bind the socket to a specified endpoint
+ void bind(const ComboAddress &ep)
+ {
+ ComboAddress local;
+ memset(reinterpret_cast<char *>(&local),0,sizeof(local));
+ local.sin_family=d_family;
+ local.sin_addr.s_addr=ep.address.byte;
+ local.sin_port=htons(ep.port);
+
+ bind(local);
+ }
+#endif
+ //! Connect the socket to a specified endpoint
+ void connect(const ComboAddress &ep, int timeout=0)
+ {
+ if(::connect(d_socket,(struct sockaddr *)&ep, ep.getSocklen()) < 0) {
+ if(errno == EINPROGRESS) {
+ if (timeout > 0) {
+ /* if a timeout is provided, we wait until the connection has been established */
+ int res = waitForRWData(d_socket, false, timeout, 0);
+ if (res == 0) {
+ throw NetworkError("timeout while connecting to "+ep.toStringWithPort());
+ } else if (res < 0) {
+ throw NetworkError("while waiting to connect to "+ep.toStringWithPort()+": "+string(strerror(errno)));
+ }
+ }
+ }
+ else {
+ throw NetworkError("While connecting to "+ep.toStringWithPort()+": "+string(strerror(errno)));
+ }
+ }
+ }
+
+
+ //! For datagram sockets, receive a datagram and learn where it came from
+ /** For datagram sockets, receive a datagram and learn where it came from
+ \param dgram Will be filled with the datagram
+ \param ep Will be filled with the origin of the datagram */
+ void recvFrom(string &dgram, ComboAddress &ep)
+ {
+ socklen_t remlen=sizeof(ep);
+ ssize_t bytes;
+ if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&ep , &remlen)) <0)
+ throw NetworkError("After recvfrom: "+string(strerror(errno)));
+
+ dgram.assign(d_buffer,bytes);
+ }
+
+ bool recvFromAsync(string &dgram, ComboAddress &ep)
+ {
+ struct sockaddr_in remote;
+ socklen_t remlen=sizeof(remote);
+ ssize_t bytes;
+ if((bytes=recvfrom(d_socket, d_buffer, d_buflen, 0, (sockaddr *)&remote, &remlen))<0) {
+ if(errno!=EAGAIN) {
+ throw NetworkError("After async recvfrom: "+string(strerror(errno)));
+ }
+ else {
+ return false;
+ }
+ }
+ dgram.assign(d_buffer,bytes);
+ return true;
+ }
+
+
+ //! For datagram sockets, send a datagram to a destination
+ void sendTo(const char* msg, size_t len, const ComboAddress &ep)
+ {
+ if(sendto(d_socket, msg, len, 0, (sockaddr *)&ep, ep.getSocklen())<0)
+ throw NetworkError("After sendto: "+string(strerror(errno)));
+ }
+
+ //! For connected datagram sockets, send a datagram
+ void send(const std::string& msg)
+ {
+ if(::send(d_socket, msg.c_str(), msg.size(), 0)<0)
+ throw NetworkError("After send: "+string(strerror(errno)));
+ }
+
+
+ /** For datagram sockets, send a datagram to a destination
+ \param dgram The datagram
+ \param ep The intended destination of the datagram */
+ void sendTo(const string &dgram, const ComboAddress &ep)
+ {
+ sendTo(dgram.c_str(), dgram.length(), ep);
+ }
+
+
+ //! Write this data to the socket, taking care that all bytes are written out
+ void writen(const string &data)
+ {
+ if(data.empty())
+ return;
+
+ size_t toWrite=data.length();
+ ssize_t res;
+ const char *ptr=data.c_str();
+
+ do {
+ res=::send(d_socket, ptr, toWrite, 0);
+ if(res<0)
+ throw NetworkError("Writing to a socket: "+string(strerror(errno)));
+ if(!res)
+ throw NetworkError("EOF on socket");
+ toWrite-=(size_t)res;
+ ptr+=(size_t)res;
+ }while(toWrite);
+
+ }
+
+ //! tries to write toWrite bytes from ptr to the socket
+ /** tries to write toWrite bytes from ptr to the socket, but does not make sure they al get written out
+ \param ptr Location to write from
+ \param toWrite number of bytes to try
+ */
+ size_t tryWrite(const char *ptr, size_t toWrite)
+ {
+ ssize_t res;
+ res=::send(d_socket,ptr,toWrite,0);
+ if(res==0)
+ throw NetworkError("EOF on writing to a socket");
+
+ if(res>0)
+ return res;
+
+ if(errno==EAGAIN)
+ return 0;
+
+ throw NetworkError("Writing to a socket: "+string(strerror(errno)));
+ }
+
+ //! Writes toWrite bytes from ptr to the socket
+ /** Writes toWrite bytes from ptr to the socket. Returns how many bytes were written */
+ size_t write(const char *ptr, size_t toWrite)
+ {
+ ssize_t res;
+ res=::send(d_socket,ptr,toWrite,0);
+ if(res<0) {
+ throw NetworkError("Writing to a socket: "+string(strerror(errno)));
+ }
+ return res;
+ }
+
+ void writenWithTimeout(const void *buffer, size_t n, int timeout)
+ {
+ size_t bytes=n;
+ const char *ptr = (char*)buffer;
+ ssize_t ret;
+ while(bytes) {
+ ret=::write(d_socket, ptr, bytes);
+ if(ret < 0) {
+ if(errno==EAGAIN) {
+ ret=waitForRWData(d_socket, false, timeout, 0);
+ if(ret < 0)
+ throw NetworkError("Waiting for data write");
+ if(!ret)
+ throw NetworkError("Timeout writing data");
+ continue;
+ }
+ else
+ throw NetworkError("Writing data: "+stringerror());
+ }
+ if(!ret) {
+ throw NetworkError("Did not fulfill TCP write due to EOF");
+ }
+
+ ptr += (size_t) ret;
+ bytes -= (size_t) ret;
+ }
+ }
+
+ //! reads one character from the socket
+ int getChar()
+ {
+ char c;
+
+ ssize_t res=::recv(d_socket,&c,1,0);
+ if(res)
+ return c;
+ return -1;
+ }
+
+ void getline(string &data)
+ {
+ data="";
+ int c;
+ while((c=getChar())!=-1) {
+ data+=(char)c;
+ if(c=='\n')
+ break;
+ }
+ }
+
+ //! Reads a block of data from the socket to a string
+ void read(string &data)
+ {
+ ssize_t res=::recv(d_socket,d_buffer,d_buflen,0);
+ if(res<0)
+ throw NetworkError("Reading from a socket: "+string(strerror(errno)));
+ data.assign(d_buffer,res);
+ }
+
+ //! Reads a block of data from the socket to a block of memory
+ size_t read(char *buffer, size_t bytes)
+ {
+ ssize_t res=::recv(d_socket,buffer,bytes,0);
+ if(res<0)
+ throw NetworkError("Reading from a socket: "+string(strerror(errno)));
+ return (size_t) res;
+ }
+
+ ssize_t readWithTimeout(char* buffer, size_t n, int timeout)
+ {
+ int err = waitForRWData(d_socket, true, timeout, 0);
+
+ if(err == 0)
+ throw NetworkError("timeout reading");
+ if(err < 0)
+ throw NetworkError("nonblocking read failed: "+string(strerror(errno)));
+
+ return read(buffer, n);
+ }
+
+ //! Sets the socket to listen with a default listen backlog of 10 bytes
+ void listen(unsigned int length=10)
+ {
+ if(::listen(d_socket,length)<0)
+ throw NetworkError("Setting socket to listen: "+string(strerror(errno)));
+ }
+
+ //! Returns the internal file descriptor of the socket
+ int getHandle() const
+ {
+ return d_socket;
+ }
+
+private:
+ char *d_buffer;
+ int d_socket;
+ size_t d_buflen;
+};
+
+
+#endif
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "statbag.hh"
+#include "pdnsexception.hh"
+#include <iostream>
+#include <sstream>
+#include <algorithm>
+#include "arguments.hh"
+#include "lock.hh"
+#include "iputils.hh"
+
+
+#include "namespaces.hh"
+
+StatBag::StatBag()
+{
+ d_doRings=false;
+}
+
+void StatBag::exists(const string &key)
+{
+ if(!d_keyDescrips.count(key))
+ {
+ throw PDNSException("Trying to deposit into unknown StatBag key '"+key+"'");
+ }
+}
+
+string StatBag::directory()
+{
+ string dir;
+ ostringstream o;
+
+ for(map<string, AtomicCounter *>::const_iterator i=d_stats.begin();
+ i!=d_stats.end();
+ i++)
+ {
+ o<<i->first<<"="<<*(i->second)<<",";
+ }
+
+
+ for(const funcstats_t::value_type& val : d_funcstats) {
+ o << val.first<<"="<<val.second(val.first)<<",";
+ }
+ dir=o.str();
+ return dir;
+}
+
+
+vector<string>StatBag::getEntries()
+{
+ vector<string> ret;
+
+ for(map<string, AtomicCounter *>::const_iterator i=d_stats.begin();
+ i!=d_stats.end();
+ i++)
+ ret.push_back(i->first);
+
+ for(const funcstats_t::value_type& val : d_funcstats) {
+ ret.push_back(val.first);
+ }
+
+
+ return ret;
+
+}
+
+string StatBag::getDescrip(const string &item)
+{
+ exists(item);
+ return d_keyDescrips[item];
+}
+
+void StatBag::declare(const string &key, const string &descrip)
+{
+ AtomicCounter *i=new AtomicCounter(0);
+ d_stats[key]=i;
+ d_keyDescrips[key]=descrip;
+}
+
+void StatBag::declare(const string &key, const string &descrip, StatBag::func_t func)
+{
+
+ d_funcstats[key]=func;
+ d_keyDescrips[key]=descrip;
+}
+
+
+void StatBag::set(const string &key, unsigned long value)
+{
+ exists(key);
+ d_stats[key]->store(value);
+}
+
+unsigned long StatBag::read(const string &key)
+{
+ exists(key);
+ funcstats_t::const_iterator iter = d_funcstats.find(key);
+ if(iter != d_funcstats.end())
+ return iter->second(iter->first);
+ return *d_stats[key];
+}
+
+unsigned long StatBag::readZero(const string &key)
+{
+ exists(key);
+ unsigned long tmp=*d_stats[key];
+ d_stats[key]=0;
+ return tmp;
+}
+
+
+string StatBag::getValueStr(const string &key)
+{
+ ostringstream o;
+ o<<read(key);
+ return o.str();
+}
+
+string StatBag::getValueStrZero(const string &key)
+{
+ ostringstream o;
+ o<<readZero(key);
+ return o.str();
+}
+
+AtomicCounter *StatBag::getPointer(const string &key)
+{
+ exists(key);
+ return d_stats[key];
+}
+
+StatBag::~StatBag()
+{
+ for(map<string, AtomicCounter *>::const_iterator i=d_stats.begin();
+ i!=d_stats.end();
+ i++)
+ {
+ delete i->second;
+ }
+
+}
+
+template<typename T, typename Comp>
+StatRing<T,Comp>::StatRing(unsigned int size)
+{
+ d_items.set_capacity(size);
+ pthread_mutex_init(&d_lock, 0);
+}
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::account(const T& t)
+{
+ Lock l(&d_lock);
+ d_items.push_back(t);
+}
+
+template<typename T, typename Comp>
+unsigned int StatRing<T,Comp>::getSize()
+{
+ Lock l(&d_lock);
+ return d_items.capacity();
+}
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::resize(unsigned int newsize)
+{
+ Lock l(&d_lock);
+ d_items.set_capacity(newsize);
+}
+
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::setHelp(const string &str)
+{
+ d_help=str;
+}
+
+template<typename T, typename Comp>
+string StatRing<T,Comp>::getHelp()
+{
+ return d_help;
+}
+
+
+template<typename T, typename Comp>
+vector<pair<T, unsigned int> >StatRing<T,Comp>::get() const
+{
+ Lock l(&d_lock);
+ map<T,unsigned int, Comp> res;
+ for(typename boost::circular_buffer<T>::const_iterator i=d_items.begin();i!=d_items.end();++i) {
+ res[*i]++;
+ }
+
+ vector<pair<T ,unsigned int> > tmp;
+ for(typename map<T, unsigned int>::const_iterator i=res.begin();i!=res.end();++i)
+ tmp.push_back(*i);
+
+ sort(tmp.begin(),tmp.end(),popisort);
+
+ return tmp;
+}
+
+void StatBag::declareRing(const string &name, const string &help, unsigned int size)
+{
+ d_rings[name]=StatRing<string>(size);
+ d_rings[name].setHelp(help);
+}
+
+void StatBag::declareComboRing(const string &name, const string &help, unsigned int size)
+{
+ d_comborings[name]=StatRing<SComboAddress>(size);
+ d_comborings[name].setHelp(help);
+}
+
+
+vector<pair<string, unsigned int> > StatBag::getRing(const string &name)
+{
+ if(d_rings.count(name))
+ return d_rings[name].get();
+ else {
+ typedef pair<SComboAddress, unsigned int> stor_t;
+ vector<stor_t> raw =d_comborings[name].get();
+ vector<pair<string, unsigned int> > ret;
+ for(const stor_t& stor : raw) {
+ ret.push_back(make_pair(stor.first.ca.toString(), stor.second));
+ }
+ return ret;
+ }
+
+}
+
+template<typename T, typename Comp>
+void StatRing<T,Comp>::reset()
+{
+ Lock l(&d_lock);
+ d_items.clear();
+}
+
+void StatBag::resetRing(const string &name)
+{
+ if(d_rings.count(name))
+ d_rings[name].reset();
+ else
+ d_comborings[name].reset();
+}
+
+void StatBag::resizeRing(const string &name, unsigned int newsize)
+{
+ if(d_rings.count(name))
+ d_rings[name].resize(newsize);
+ else
+ d_comborings[name].resize(newsize);
+}
+
+
+unsigned int StatBag::getRingSize(const string &name)
+{
+ if(d_rings.count(name))
+ return d_rings[name].getSize();
+ else
+ return d_comborings[name].getSize();
+}
+
+string StatBag::getRingTitle(const string &name)
+{
+ if(d_rings.count(name))
+ return d_rings[name].getHelp();
+ else
+ return d_comborings[name].getHelp();
+}
+
+vector<string>StatBag::listRings()
+{
+ vector<string> ret;
+ for(map<string,StatRing<string> >::const_iterator i=d_rings.begin();i!=d_rings.end();++i)
+ ret.push_back(i->first);
+ for(map<string,StatRing<SComboAddress> >::const_iterator i=d_comborings.begin();i!=d_comborings.end();++i)
+ ret.push_back(i->first);
+
+ return ret;
+}
+
+bool StatBag::ringExists(const string &name)
+{
+ return d_rings.count(name) || d_comborings.count(name);
+}
+
+template class StatRing<std::string>;
+template class StatRing<SComboAddress>;
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef STATBAG_HH
+#define STATBAG_HH
+#include <pthread.h>
+#include <map>
+#include <functional>
+#include <string>
+#include <vector>
+#include "lock.hh"
+#include "namespaces.hh"
+#include "iputils.hh"
+#include <boost/circular_buffer.hpp>
+
+
+
+template<typename T, typename Comp=std::less<T> >
+class StatRing
+{
+public:
+ StatRing(unsigned int size=10000);
+ void account(const T &item);
+
+ unsigned int getSize();
+ void resize(unsigned int newsize);
+ void reset();
+ void setHelp(const string &str);
+ string getHelp();
+
+ vector<pair<T, unsigned int> > get() const;
+private:
+ static bool popisort(const pair<T,int> &a, const pair<T,int> &b)
+ {
+ return (a.second > b.second);
+ }
+
+ boost::circular_buffer<T> d_items;
+ mutable pthread_mutex_t d_lock;
+ string d_help;
+};
+
+
+//! use this to gather and query statistics
+class StatBag
+{
+ map<string, AtomicCounter *> d_stats;
+ map<string, string> d_keyDescrips;
+ map<string,StatRing<string> >d_rings;
+ map<string,StatRing<SComboAddress> >d_comborings;
+ typedef boost::function<uint64_t(const std::string&)> func_t;
+ typedef map<string, func_t> funcstats_t;
+ funcstats_t d_funcstats;
+ bool d_doRings;
+
+public:
+ StatBag(); //!< Naked constructor. You need to declare keys before this class becomes useful
+ ~StatBag();
+ void declare(const string &key, const string &descrip=""); //!< Before you can store or access a key, you need to declare it
+ void declare(const string &key, const string &descrip, func_t func); //!< Before you can store or access a key, you need to declare it
+
+ void declareRing(const string &name, const string &title, unsigned int size=10000);
+ void declareComboRing(const string &name, const string &help, unsigned int size=10000);
+ vector<pair<string, unsigned int> >getRing(const string &name);
+ string getRingTitle(const string &name);
+ void ringAccount(const char* name, const string &item)
+ {
+ if(d_doRings) {
+ if(!d_rings.count(name))
+ throw runtime_error("Attempting to account to non-existent ring '"+std::string(name)+"'");
+
+ d_rings[name].account(item);
+ }
+ }
+ void ringAccount(const char* name, const ComboAddress &item)
+ {
+ if(d_doRings) {
+ if(!d_comborings.count(name))
+ throw runtime_error("Attempting to account to non-existent comboring '"+std::string(name)+"'");
+ d_comborings[name].account(item);
+ }
+ }
+
+ void doRings()
+ {
+ d_doRings=true;
+ }
+
+ vector<string>listRings();
+ bool ringExists(const string &name);
+ void resetRing(const string &name);
+ void resizeRing(const string &name, unsigned int newsize);
+ unsigned int getRingSize(const string &name);
+
+ string directory(); //!< Returns a list of all data stored
+ vector<string> getEntries(); //!< returns a vector with datums (items)
+ string getDescrip(const string &item); //!< Returns the description of this datum/item
+ void exists(const string &key); //!< call this function to throw an exception in case a key does not exist
+ inline void deposit(const string &key, int value); //!< increment the statistics behind this key by value amount
+ inline void inc(const string &key); //!< increase this key's value by one
+ void set(const string &key, unsigned long value); //!< set this key's value
+ unsigned long read(const string &key); //!< read the value behind this key
+ unsigned long readZero(const string &key); //!< read the value behind this key, and zero it afterwards
+ AtomicCounter *getPointer(const string &key); //!< get a direct pointer to the value behind a key. Use this for high performance increments
+ string getValueStr(const string &key); //!< read a value behind a key, and return it as a string
+ string getValueStrZero(const string &key); //!< read a value behind a key, and return it as a string, and zero afterwards
+};
+
+inline void StatBag::deposit(const string &key, int value)
+{
+ exists(key);
+
+ *d_stats[key]+=value;
+}
+
+inline void StatBag::inc(const string &key)
+{
+ deposit(key,1);
+}
+
+
+#endif /* STATBAG_HH */
--- /dev/null
+#include "statnode.hh"
+
+StatNode::Stat StatNode::print(int depth, Stat newstat, bool silent) const
+{
+ if(!silent) {
+ cout<<string(depth, ' ');
+ cout<<name<<": "<<endl;
+ }
+ Stat childstat;
+ childstat.queries += s.queries;
+ childstat.noerrors += s.noerrors;
+ childstat.nxdomains += s.nxdomains;
+ childstat.servfails += s.servfails;
+ childstat.drops += s.drops;
+ if(children.size()>1024 && !silent) {
+ cout<<string(depth, ' ')<<name<<": too many to print"<<endl;
+ }
+ for(const children_t::value_type& child : children) {
+ childstat=child.second.print(depth+8, childstat, silent || children.size()>1024);
+ }
+ if(!silent || children.size()>1)
+ cout<<string(depth, ' ')<<childstat.queries<<" queries, " <<
+ childstat.noerrors<<" noerrors, "<<
+ childstat.nxdomains<<" nxdomains, "<<
+ childstat.servfails<<" servfails, "<<
+ childstat.drops<<" drops"<<endl;
+
+ newstat+=childstat;
+
+ return newstat;
+}
+
+
+void StatNode::visit(visitor_t visitor, Stat &newstat, int depth) const
+{
+ Stat childstat;
+ childstat.queries += s.queries;
+ childstat.noerrors += s.noerrors;
+ childstat.nxdomains += s.nxdomains;
+ childstat.servfails += s.servfails;
+ childstat.drops += s.drops;
+ childstat.remotes = s.remotes;
+
+ Stat selfstat(childstat);
+
+
+ for(const children_t::value_type& child : children) {
+ child.second.visit(visitor, childstat, depth+8);
+ }
+
+ visitor(this, selfstat, childstat);
+
+ newstat+=childstat;
+}
+
+
+void StatNode::submit(const DNSName& domain, int rcode, const ComboAddress& remote)
+{
+ // cerr<<"FIRST submit called on '"<<domain<<"'"<<endl;
+ vector<string> tmp = domain.getRawLabels();
+ if(tmp.empty())
+ return;
+
+ deque<string> parts;
+ for(auto const i : tmp) {
+ parts.push_back(i);
+ }
+ children[parts.back()].submit(parts, "", rcode, remote);
+}
+
+/* www.powerdns.com. ->
+ . <- fullnames
+ com.
+ powerdns.com
+ www.powerdns.com.
+*/
+
+void StatNode::submit(deque<string>& labels, const std::string& domain, int rcode, const ComboAddress& remote)
+{
+ if(labels.empty())
+ return;
+ // cerr<<"Submit called for domain='"<<domain<<"': ";
+ // for(const std::string& n : labels)
+ // cerr<<n<<".";
+ // cerr<<endl;
+ if(name.empty()) {
+
+ name=labels.back();
+ // cerr<<"Set short name to '"<<name<<"'"<<endl;
+ }
+ else
+ ; // cerr<<"Short name was already set to '"<<name<<"'"<<endl;
+
+ if(labels.size()==1) {
+ fullname=name+"."+domain;
+ // cerr<<"Hit the end, set our fullname to '"<<fullname<<"'"<<endl<<endl;
+ s.queries++;
+ if(rcode<0)
+ s.drops++;
+ else if(rcode==0)
+ s.noerrors++;
+ else if(rcode==2)
+ s.servfails++;
+ else if(rcode==3)
+ s.nxdomains++;
+ s.remotes[remote]++;
+ }
+ else {
+ fullname=name+"."+domain;
+ // cerr<<"Not yet end, set our fullname to '"<<fullname<<"', recursing"<<endl;
+ labels.pop_back();
+ children[labels.back()].submit(labels, fullname, rcode, remote);
+ }
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "dnsname.hh"
+#include <deque>
+#include <map>
+#include "iputils.hh"
+
+class StatNode
+{
+public:
+ void submit(const DNSName& domain, int rcode, const ComboAddress& remote);
+ void submit(std::deque<std::string>& labels, const std::string& domain, int rcode, const ComboAddress& remote);
+
+ std::string name;
+ std::string fullname;
+ struct Stat
+ {
+ Stat() : queries(0), noerrors(0), nxdomains(0), servfails(0), drops(0){}
+ int queries, noerrors, nxdomains, servfails, drops;
+
+ Stat& operator+=(const Stat& rhs) {
+ queries+=rhs.queries;
+ noerrors+=rhs.noerrors;
+ nxdomains+=rhs.nxdomains;
+ servfails+=rhs.servfails;
+ drops+=rhs.drops;
+
+ for(const remotes_t::value_type& rem : rhs.remotes) {
+ remotes[rem.first]+=rem.second;
+ }
+ return *this;
+ }
+typedef std::map<ComboAddress,int,ComboAddress::addressOnlyLessThan> remotes_t;
+ remotes_t remotes;
+ };
+
+ Stat s;
+ Stat print(int depth=0, Stat newstat=Stat(), bool silent=false) const;
+ typedef boost::function<void(const StatNode*, const Stat& selfstat, const Stat& childstat)> visitor_t;
+ void visit(visitor_t visitor, Stat& newstat, int depth=0) const;
+ typedef std::map<std::string,StatNode, CIStringCompare> children_t;
+ children_t children;
+
+};
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "arguments.hh"
+#include "dnsrecords.hh"
+#include "dns_random.hh"
+#include "stubresolver.hh"
+#include "statbag.hh"
+
+StatBag S;
+
+ArgvMap &arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+void usage() {
+ cerr<<"stubquery"<<endl;
+ cerr<<"Syntax: stubquery QUESTION [QUESTION-TYPE]"<<endl;
+}
+
+int main(int argc, char** argv)
+try
+{
+ DNSName qname;
+ QType qtype;
+
+ for(int i=1; i<argc; i++) {
+ if ((string) argv[i] == "--help") {
+ usage();
+ exit(EXIT_SUCCESS);
+ }
+
+ if ((string) argv[i] == "--version") {
+ cerr<<"stubquery "<<VERSION<<endl;
+ exit(EXIT_SUCCESS);
+ }
+ }
+
+ if(argc < 2) {
+ usage();
+ exit(EXIT_FAILURE);
+ }
+
+ ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
+
+ reportAllTypes();
+ dns_random_init("0123456789abcdef");
+ stubParseResolveConf();
+
+ vector<DNSResourceRecord> ret;
+
+ int res=stubDoResolve(argv[1], DNSRecordContent::TypeToNumber(argv[2]), ret);
+
+ cout<<"res: "<<res<<endl;
+ for(const auto& r : ret) {
+ cout<<r.getZoneRepresentation()<<endl;
+ }
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+catch(PDNSException &e)
+{
+ cerr<<"Fatal: "<<e.reason<<endl;
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "logger.hh"
+#include "arguments.hh"
+#include "version.hh"
+#include "misc.hh"
+
+#include "sstuff.hh"
+#include "dnswriter.hh"
+#include "dns_random.hh"
+#include "namespaces.hh"
+#include "statbag.hh"
+#include "stubresolver.hh"
+
+// s_stubresolvers contains the ComboAddresses that are used by
+// stubDoResolve
+static vector<ComboAddress> s_stubresolvers;
+
+/** Parse /etc/resolv.conf and add the nameservers to the vector
+ * s_stubresolvers.
+ */
+void stubParseResolveConf()
+{
+ ifstream ifs("/etc/resolv.conf");
+ if(!ifs)
+ return;
+
+ string line;
+ while(std::getline(ifs, line)) {
+ boost::trim_right_if(line, is_any_of(" \r\n\x1a"));
+ boost::trim_left(line); // leading spaces, let's be nice
+
+ string::size_type tpos = line.find_first_of(";#");
+ if(tpos != string::npos)
+ line.resize(tpos);
+
+ if(boost::starts_with(line, "nameserver ") || boost::starts_with(line, "nameserver\t")) {
+ vector<string> parts;
+ stringtok(parts, line, " \t,"); // be REALLY nice
+ for(vector<string>::const_iterator iter = parts.begin()+1; iter != parts.end(); ++iter) {
+ try {
+ s_stubresolvers.push_back(ComboAddress(*iter, 53));
+ }
+ catch(...)
+ {
+ }
+ }
+ }
+ }
+
+ if(::arg().mustDo("recursor"))
+ s_stubresolvers.push_back(ComboAddress(::arg()["recursor"], 53));
+
+ // Last resort, add 127.0.0.1
+ if(s_stubresolvers.empty()) {
+ s_stubresolvers.push_back(ComboAddress("127.0.0.1", 53));
+ }
+}
+
+// s_stubresolvers contains the ComboAddresses that are used to resolve the
+int stubDoResolve(const string& qname, uint16_t qtype, vector<DNSResourceRecord>& ret)
+{
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, DNSName(qname), qtype);
+ pw.getHeader()->id=dns_random(0xffff);
+ pw.getHeader()->rd=1;
+ if (s_stubresolvers.empty()) {
+ L<<Logger::Warning<<"No recursors set, stub resolving (including secpoll and ALIAS) impossible."<<endl;
+ return RCode::ServFail;
+ }
+
+ string msg ="Doing stub resolving, using resolvers: ";
+ for (const auto& server : s_stubresolvers) {
+ msg += server.toString() + ", ";
+ }
+ L<<Logger::Debug<<msg.substr(0, msg.length() - 2)<<endl;
+
+ for(ComboAddress& dest : s_stubresolvers) {
+ Socket sock(dest.sin4.sin_family, SOCK_DGRAM);
+ sock.setNonBlocking();
+ sock.sendTo(string(packet.begin(), packet.end()), dest);
+
+ string reply;
+
+ waitForData(sock.getHandle(), 2, 0);
+ try {
+ retry:
+ sock.recvFrom(reply, dest);
+ if(reply.size() > sizeof(struct dnsheader)) {
+ struct dnsheader d;
+ memcpy(&d, reply.c_str(), sizeof(d));
+ if(d.id != pw.getHeader()->id)
+ goto retry;
+ }
+ }
+ catch(...) {
+ continue;
+ }
+ MOADNSParser mdp(false, reply);
+ if(mdp.d_header.rcode == RCode::ServFail)
+ continue;
+
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ if(i->first.d_place == 1 && i->first.d_type==qtype) {
+ DNSResourceRecord rr;
+ rr.qname = i->first.d_name;
+ rr.qtype = QType(i->first.d_type);
+ rr.content = i->first.d_content->getZoneRepresentation();
+ rr.ttl=i->first.d_ttl;
+ ret.push_back(rr);
+ }
+ }
+ L<<Logger::Debug<<"Question got answered by "<<dest.toString()<<endl;
+ return mdp.d_header.rcode;
+ }
+ return RCode::ServFail;
+}
\ No newline at end of file
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+#include "namespaces.hh"
+#include "dnsparser.hh"
+
+void stubParseResolveConf();
+int stubDoResolve(const string& qname, uint16_t qtype, vector<DNSResourceRecord>& ret);
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002-2012 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packetcache.hh"
+#include "utility.hh"
+#include "dnssecinfra.hh"
+#include "dnsseckeeper.hh"
+#include <cstdio>
+#include "base32.hh"
+#include <cstring>
+#include <cstdlib>
+#include <sys/types.h>
+#include <iostream>
+#include <string>
+#include "tcpreceiver.hh"
+#include "sstuff.hh"
+
+#include <errno.h>
+#include <signal.h>
+#include "base64.hh"
+#include "ueberbackend.hh"
+#include "dnspacket.hh"
+#include "nameserver.hh"
+#include "distributor.hh"
+#include "lock.hh"
+#include "logger.hh"
+#include "arguments.hh"
+
+#include "common_startup.hh"
+#include "packethandler.hh"
+#include "statbag.hh"
+#include "resolver.hh"
+#include "communicator.hh"
+#include "namespaces.hh"
+#include "signingpipe.hh"
+#include "stubresolver.hh"
+extern PacketCache PC;
+extern StatBag S;
+
+/**
+\file tcpreceiver.cc
+\brief This file implements the tcpreceiver that receives and answers questions over TCP/IP
+*/
+
+pthread_mutex_t TCPNameserver::s_plock = PTHREAD_MUTEX_INITIALIZER;
+Semaphore *TCPNameserver::d_connectionroom_sem;
+PacketHandler *TCPNameserver::s_P;
+NetmaskGroup TCPNameserver::d_ng;
+
+void TCPNameserver::go()
+{
+ L<<Logger::Error<<"Creating backend connection for TCP"<<endl;
+ s_P=0;
+ try {
+ s_P=new PacketHandler;
+ }
+ catch(PDNSException &ae) {
+ L<<Logger::Error<<"TCP server is unable to launch backends - will try again when questions come in: "<<ae.reason<<endl;
+ }
+ pthread_create(&d_tid, 0, launcher, static_cast<void *>(this));
+}
+
+void *TCPNameserver::launcher(void *data)
+{
+ static_cast<TCPNameserver *>(data)->thread();
+ return 0;
+}
+
+// throws PDNSException if things didn't go according to plan, returns 0 if really 0 bytes were read
+int readnWithTimeout(int fd, void* buffer, unsigned int n, bool throwOnEOF=true)
+{
+ unsigned int bytes=n;
+ char *ptr = (char*)buffer;
+ int ret;
+ while(bytes) {
+ ret=read(fd, ptr, bytes);
+ if(ret < 0) {
+ if(errno==EAGAIN) {
+ ret=waitForData(fd, 5);
+ if(ret < 0)
+ throw NetworkError("Waiting for data read");
+ if(!ret)
+ throw NetworkError("Timeout reading data");
+ continue;
+ }
+ else
+ throw NetworkError("Reading data: "+stringerror());
+ }
+ if(!ret) {
+ if(!throwOnEOF && n == bytes)
+ return 0;
+ else
+ throw NetworkError("Did not fulfill read from TCP due to EOF");
+ }
+
+ ptr += ret;
+ bytes -= ret;
+ }
+ return n;
+}
+
+// ditto
+void writenWithTimeout(int fd, const void *buffer, unsigned int n)
+{
+ unsigned int bytes=n;
+ const char *ptr = (char*)buffer;
+ int ret;
+ while(bytes) {
+ ret=write(fd, ptr, bytes);
+ if(ret < 0) {
+ if(errno==EAGAIN) {
+ ret=waitForRWData(fd, false, 5, 0);
+ if(ret < 0)
+ throw NetworkError("Waiting for data write");
+ if(!ret)
+ throw NetworkError("Timeout writing data");
+ continue;
+ }
+ else
+ throw NetworkError("Writing data: "+stringerror());
+ }
+ if(!ret) {
+ throw NetworkError("Did not fulfill TCP write due to EOF");
+ }
+
+ ptr += ret;
+ bytes -= ret;
+ }
+}
+
+void connectWithTimeout(int fd, struct sockaddr* remote, size_t socklen)
+{
+ int err;
+ Utility::socklen_t len=sizeof(err);
+
+ if((err=connect(fd, remote, socklen))<0 && errno!=EINPROGRESS)
+ throw NetworkError("connect: "+stringerror());
+
+ if(!err)
+ goto done;
+
+ err=waitForRWData(fd, false, 5, 0);
+ if(err == 0)
+ throw NetworkError("Timeout connecting to remote");
+ if(err < 0)
+ throw NetworkError("Error connecting to remote");
+
+ if(getsockopt(fd, SOL_SOCKET,SO_ERROR,(char *)&err,&len)<0)
+ throw NetworkError("Error connecting to remote: "+stringerror()); // Solaris
+
+ if(err)
+ throw NetworkError("Error connecting to remote: "+string(strerror(err)));
+
+ done:
+ ;
+}
+
+void TCPNameserver::sendPacket(shared_ptr<DNSPacket> p, int outsock)
+{
+ g_rs.submitResponse(*p, false);
+
+ uint16_t len=htons(p->getString().length());
+ string buffer((const char*)&len, 2);
+ buffer.append(p->getString());
+ writenWithTimeout(outsock, buffer.c_str(), buffer.length());
+}
+
+
+void TCPNameserver::getQuestion(int fd, char *mesg, int pktlen, const ComboAddress &remote)
+try
+{
+ readnWithTimeout(fd, mesg, pktlen);
+}
+catch(NetworkError& ae) {
+ throw NetworkError("Error reading DNS data from TCP client "+remote.toString()+": "+ae.what());
+}
+
+static void proxyQuestion(shared_ptr<DNSPacket> packet)
+{
+ int sock=socket(AF_INET, SOCK_STREAM, 0);
+
+ setCloseOnExec(sock);
+ if(sock < 0)
+ throw NetworkError("Error making TCP connection socket to recursor: "+stringerror());
+
+ setNonBlocking(sock);
+ ServiceTuple st;
+ st.port=53;
+ parseService(::arg()["recursor"],st);
+
+ try {
+ ComboAddress recursor(st.host, st.port);
+ connectWithTimeout(sock, (struct sockaddr*)&recursor, recursor.getSocklen());
+ const string &buffer=packet->getString();
+
+ uint16_t len=htons(buffer.length()), slen;
+
+ writenWithTimeout(sock, &len, 2);
+ writenWithTimeout(sock, buffer.c_str(), buffer.length());
+
+ readnWithTimeout(sock, &len, 2);
+ len=ntohs(len);
+
+ char answer[len];
+ readnWithTimeout(sock, answer, len);
+
+ slen=htons(len);
+ writenWithTimeout(packet->getSocket(), &slen, 2);
+
+ writenWithTimeout(packet->getSocket(), answer, len);
+ }
+ catch(NetworkError& ae) {
+ close(sock);
+ throw NetworkError("While proxying a question to recursor "+st.host+": " +ae.what());
+ }
+ close(sock);
+ return;
+}
+
+
+static void incTCPAnswerCount(const ComboAddress& remote)
+{
+ S.inc("tcp-answers");
+ if(remote.sin4.sin_family == AF_INET6)
+ S.inc("tcp6-answers");
+ else
+ S.inc("tcp4-answers");
+}
+void *TCPNameserver::doConnection(void *data)
+{
+ shared_ptr<DNSPacket> packet;
+ // Fix gcc-4.0 error (on AMD64)
+ int fd=(int)(long)data; // gotta love C (generates a harmless warning on opteron)
+ ComboAddress remote;
+ socklen_t remotelen=sizeof(remote);
+
+ pthread_detach(pthread_self());
+ if(getpeername(fd, (struct sockaddr *)&remote, &remotelen) < 0) {
+ L<<Logger::Warning<<"Received question from socket which had no remote address, dropping ("<<stringerror()<<")"<<endl;
+ d_connectionroom_sem->post();
+ try {
+ closesocket(fd);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
+ }
+ return 0;
+ }
+
+ setNonBlocking(fd);
+ try {
+ int mesgsize=65535;
+ scoped_array<char> mesg(new char[mesgsize]);
+
+ DLOG(L<<"TCP Connection accepted on fd "<<fd<<endl);
+ bool logDNSQueries= ::arg().mustDo("log-dns-queries");
+ for(;;) {
+
+ uint16_t pktlen;
+ if(!readnWithTimeout(fd, &pktlen, 2, false))
+ break;
+ else
+ pktlen=ntohs(pktlen);
+
+ // this check will always be false *if* no one touches
+ // the mesg array. pktlen can be maximum of 65535 as
+ // it is 2 byte unsigned variable. In getQuestion, we
+ // write to 0 up to pktlen-1 so 65535 is just right.
+
+ // do not remove this check as it will catch if someone
+ // decreases the mesg buffer size for some reason.
+ if(pktlen > mesgsize) {
+ L<<Logger::Warning<<"Received an overly large question from "<<remote.toString()<<", dropping"<<endl;
+ break;
+ }
+
+ getQuestion(fd, mesg.get(), pktlen, remote);
+ S.inc("tcp-queries");
+ if(remote.sin4.sin_family == AF_INET6)
+ S.inc("tcp6-queries");
+ else
+ S.inc("tcp4-queries");
+
+ packet=shared_ptr<DNSPacket>(new DNSPacket(true));
+ packet->setRemote(&remote);
+ packet->d_tcp=true;
+ packet->setSocket(fd);
+ if(packet->parse(mesg.get(), pktlen)<0)
+ break;
+
+ if(packet->qtype.getCode()==QType::AXFR) {
+ if(doAXFR(packet->qdomain, packet, fd))
+ incTCPAnswerCount(remote);
+ continue;
+ }
+
+ if(packet->qtype.getCode()==QType::IXFR) {
+ if(doIXFR(packet, fd))
+ incTCPAnswerCount(remote);
+ continue;
+ }
+
+ shared_ptr<DNSPacket> reply;
+ shared_ptr<DNSPacket> cached= shared_ptr<DNSPacket>(new DNSPacket(false));
+ if(logDNSQueries) {
+ string remote;
+ if(packet->hasEDNSSubnet())
+ remote = packet->getRemote().toString() + "<-" + packet->getRealRemote().toString();
+ else
+ remote = packet->getRemote().toString();
+ L << Logger::Notice<<"TCP Remote "<< remote <<" wants '" << packet->qdomain<<"|"<<packet->qtype.getName() <<
+ "', do = " <<packet->d_dnssecOk <<", bufsize = "<< packet->getMaxReplyLen()<<": ";
+ }
+
+
+ if(!packet->d.rd && packet->couldBeCached() && PC.get(packet.get(), cached.get(), false)) { // short circuit - does the PacketCache recognize this question?
+ if(logDNSQueries)
+ L<<"packetcache HIT"<<endl;
+ cached->setRemote(&packet->d_remote);
+ cached->d.id=packet->d.id;
+ cached->d.rd=packet->d.rd; // copy in recursion desired bit
+ cached->commitD(); // commit d to the packet inlined
+
+ if(LPE) LPE->police(&(*packet), &(*cached), true);
+
+ sendPacket(cached, fd); // presigned, don't do it again
+ continue;
+ }
+ if(logDNSQueries)
+ L<<"packetcache MISS"<<endl;
+ {
+ Lock l(&s_plock);
+ if(!s_P) {
+ L<<Logger::Error<<"TCP server is without backend connections, launching"<<endl;
+ s_P=new PacketHandler;
+ }
+ bool shouldRecurse;
+
+ reply=shared_ptr<DNSPacket>(s_P->questionOrRecurse(packet.get(), &shouldRecurse)); // we really need to ask the backend :-)
+
+ if(LPE) LPE->police(&(*packet), &(*reply), true);
+
+ if(shouldRecurse) {
+ proxyQuestion(packet);
+ continue;
+ }
+ }
+
+ if(!reply) // unable to write an answer?
+ break;
+
+ sendPacket(reply, fd);
+ }
+ }
+ catch(PDNSException &ae) {
+ Lock l(&s_plock);
+ delete s_P;
+ s_P = 0; // on next call, backend will be recycled
+ L<<Logger::Error<<"TCP nameserver had error, cycling backend: "<<ae.reason<<endl;
+ }
+ catch(NetworkError &e) {
+ L<<Logger::Info<<"TCP Connection Thread died because of network error: "<<e.what()<<endl;
+ }
+
+ catch(std::exception &e) {
+ L<<Logger::Error<<"TCP Connection Thread died because of STL error: "<<e.what()<<endl;
+ }
+ catch( ... )
+ {
+ L << Logger::Error << "TCP Connection Thread caught unknown exception." << endl;
+ }
+ d_connectionroom_sem->post();
+
+ try {
+ closesocket(fd);
+ }
+ catch(const PDNSException& e) {
+ L<<Logger::Error<<"Error closing TCP socket: "<<e.reason<<endl;
+ }
+
+ return 0;
+}
+
+
+// call this method with s_plock held!
+bool TCPNameserver::canDoAXFR(shared_ptr<DNSPacket> q)
+{
+ if(::arg().mustDo("disable-axfr"))
+ return false;
+
+ if(q->d_havetsig) { // if you have one, it must be good
+ TSIGRecordContent trc;
+ DNSName keyname;
+ string secret;
+ if(!checkForCorrectTSIG(q.get(), s_P->getBackend(), &keyname, &secret, &trc)) {
+ return false;
+ } else {
+ getTSIGHashEnum(trc.d_algoName, q->d_tsig_algo);
+ if (q->d_tsig_algo == TSIG_GSS) {
+ GssContext gssctx(keyname);
+ if (!gssctx.getPeerPrincipal(q->d_peer_principal)) {
+ L<<Logger::Warning<<"Failed to extract peer principal from GSS context with keyname '"<<keyname<<"'"<<endl;
+ }
+ }
+ }
+
+ DNSSECKeeper dk;
+
+ if (q->d_tsig_algo == TSIG_GSS) {
+ vector<string> princs;
+ s_P->getBackend()->getDomainMetadata(q->qdomain, "GSS-ALLOW-AXFR-PRINCIPAL", princs);
+ for(const std::string& princ : princs) {
+ if (q->d_peer_principal == princ) {
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig'"<<endl;
+ return true;
+ }
+ }
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' denied: TSIG signed request with principal '"<<q->d_peer_principal<<"' and algorithm 'gss-tsig' is not permitted"<<endl;
+ return false;
+ }
+
+ if(!dk.TSIGGrantsAccess(q->qdomain, keyname)) {
+ L<<Logger::Error<<"AXFR '"<<q->qdomain<<"' denied: key with name '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"' does not grant access to zone"<<endl;
+ return false;
+ }
+ else {
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: TSIG signed request with authorized key '"<<keyname<<"' and algorithm '"<<getTSIGAlgoName(q->d_tsig_algo)<<"'"<<endl;
+ return true;
+ }
+ }
+
+ // cerr<<"checking allow-axfr-ips"<<endl;
+ if(!(::arg()["allow-axfr-ips"].empty()) && d_ng.match( (ComboAddress *) &q->d_remote )) {
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in allow-axfr-ips"<<endl;
+ return true;
+ }
+
+ FindNS fns;
+
+ // cerr<<"doing per-zone-axfr-acls"<<endl;
+ SOAData sd;
+ if(s_P->getBackend()->getSOAUncached(q->qdomain,sd)) {
+ // cerr<<"got backend and SOA"<<endl;
+ DNSBackend *B=sd.db;
+ vector<string> acl;
+ s_P->getBackend()->getDomainMetadata(q->qdomain, "ALLOW-AXFR-FROM", acl);
+ for (vector<string>::const_iterator i = acl.begin(); i != acl.end(); ++i) {
+ // cerr<<"matching against "<<*i<<endl;
+ if(pdns_iequals(*i, "AUTO-NS")) {
+ // cerr<<"AUTO-NS magic please!"<<endl;
+
+ DNSResourceRecord rr;
+ set<DNSName> nsset;
+
+ B->lookup(QType(QType::NS),q->qdomain);
+ while(B->get(rr))
+ nsset.insert(DNSName(rr.content));
+ for(const auto & j: nsset) {
+ vector<string> nsips=fns.lookup(j, B);
+ for(vector<string>::const_iterator k=nsips.begin();k!=nsips.end();++k) {
+ // cerr<<"got "<<*k<<" from AUTO-NS"<<endl;
+ if(*k == q->getRemote().toString())
+ {
+ // cerr<<"got AUTO-NS hit"<<endl;
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in NSset"<<endl;
+ return true;
+ }
+ }
+ }
+ }
+ else
+ {
+ Netmask nm = Netmask(*i);
+ if(nm.match( (ComboAddress *) &q->d_remote ))
+ {
+ L<<Logger::Warning<<"AXFR of domain '"<<q->qdomain<<"' allowed: client IP "<<q->getRemote()<<" is in per-domain ACL"<<endl;
+ // cerr<<"hit!"<<endl;
+ return true;
+ }
+ }
+ }
+ }
+
+ extern CommunicatorClass Communicator;
+
+ if(Communicator.justNotified(q->qdomain, q->getRemote().toString())) { // we just notified this ip
+ L<<Logger::Warning<<"Approved AXFR of '"<<q->qdomain<<"' from recently notified slave "<<q->getRemote()<<endl;
+ return true;
+ }
+
+ L<<Logger::Error<<"AXFR of domain '"<<q->qdomain<<"' denied: client IP "<<q->getRemote()<<" has no permission"<<endl;
+ return false;
+}
+
+namespace {
+ struct NSECXEntry
+ {
+ set<uint16_t> d_set;
+ unsigned int d_ttl;
+ bool d_auth;
+ };
+
+ DNSResourceRecord makeDNSRRFromSOAData(const SOAData& sd)
+ {
+ DNSResourceRecord soa;
+ soa.qname= sd.qname;
+ soa.qtype=QType::SOA;
+ soa.content=serializeSOAData(sd);
+ soa.ttl=sd.ttl;
+ soa.domain_id=sd.domain_id;
+ soa.auth = true;
+ soa.d_place=DNSResourceRecord::ANSWER;
+ return soa;
+ }
+
+ shared_ptr<DNSPacket> getFreshAXFRPacket(shared_ptr<DNSPacket> q)
+ {
+ shared_ptr<DNSPacket> ret = shared_ptr<DNSPacket>(q->replyPacket());
+ ret->setCompress(false);
+ ret->d_dnssecOk=false; // RFC 5936, 2.2.5
+ ret->d_tcp = true;
+ return ret;
+ }
+}
+
+
+/** do the actual zone transfer. Return 0 in case of error, 1 in case of success */
+int TCPNameserver::doAXFR(const DNSName &target, shared_ptr<DNSPacket> q, int outsock)
+{
+ shared_ptr<DNSPacket> outpacket= getFreshAXFRPacket(q);
+ if(q->d_dnssecOk)
+ outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
+
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' initiated by "<<q->getRemote()<<endl;
+
+ // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
+ SOAData sd;
+ {
+ Lock l(&s_plock);
+ DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no AXFR
+ if(!s_P) {
+ L<<Logger::Error<<"TCP server is without backend connections in doAXFR, launching"<<endl;
+ s_P=new PacketHandler;
+ }
+
+ if (!canDoAXFR(q)) {
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: "<<q->getRemote()<<" cannot request AXFR"<<endl;
+ outpacket->setRcode(9); // 'NOTAUTH'
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+
+ // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
+ if(!s_P->getBackend()->getSOAUncached(target, sd)) {
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative"<<endl;
+ outpacket->setRcode(9); // 'NOTAUTH'
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ }
+
+ UeberBackend db;
+ if(!db.getSOAUncached(target, sd)) {
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
+ outpacket->setRcode(RCode::NotAuth);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+
+ DNSSECKeeper dk;
+ dk.clearCaches(target);
+ bool securedZone = dk.isSecuredZone(target);
+ bool presignedZone = dk.isPresigned(target);
+
+ bool noAXFRBecauseOfNSEC3Narrow=false;
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+ bool NSEC3Zone=false;
+ if(securedZone && dk.getNSEC3PARAM(target, &ns3pr, &narrow)) {
+ NSEC3Zone=true;
+ if(narrow) {
+ L<<Logger::Error<<"Not doing AXFR of an NSEC3 narrow zone '"<<target<<"' for "<<q->getRemote()<<endl;
+ noAXFRBecauseOfNSEC3Narrow=true;
+ }
+ }
+
+ if(noAXFRBecauseOfNSEC3Narrow) {
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' denied to "<<q->getRemote()<<endl;
+ outpacket->setRcode(RCode::Refused);
+ // FIXME: should actually figure out if we are auth over a zone, and send out 9 if we aren't
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+
+ TSIGRecordContent trc;
+ DNSName tsigkeyname;
+ string tsigsecret;
+
+ bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname, 0);
+
+ if(haveTSIGDetails && !tsigkeyname.empty()) {
+ string tsig64;
+ DNSName algorithm=trc.d_algoName; // FIXME400: check
+ if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
+ algorithm = DNSName("hmac-md5");
+ if (algorithm != DNSName("gss-tsig")) {
+ Lock l(&s_plock);
+ s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
+ B64Decode(tsig64, tsigsecret);
+ }
+ }
+
+
+ UeberBackend signatureDB;
+
+ // SOA *must* go out first, our signing pipe might reorder
+ DLOG(L<<"Sending out SOA"<<endl);
+ DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
+ outpacket->addRecord(soa);
+ editSOA(dk, sd.qname, outpacket.get());
+ if(securedZone) {
+ set<DNSName> authSet;
+ authSet.insert(target);
+ addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
+ }
+
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
+
+ sendPacket(outpacket, outsock);
+
+ trc.d_mac = outpacket->d_trc.d_mac;
+ outpacket = getFreshAXFRPacket(q);
+
+ ChunkedSigningPipe csp(target, securedZone, "", ::arg().asNum("signing-threads", 1));
+
+ typedef map<string, NSECXEntry> nsecxrepo_t;
+ nsecxrepo_t nsecxrepo;
+
+ // this is where the DNSKEYs go in
+
+ DNSSECKeeper::keyset_t keys = dk.getKeys(target);
+
+ DNSResourceRecord rr;
+
+ rr.qname = target;
+ rr.ttl = sd.default_ttl;
+ rr.auth = 1; // please sign!
+
+ string publishCDNSKEY, publishCDS;
+ dk.getFromMeta(q->qdomain, "PUBLISH-CDNSKEY", publishCDNSKEY);
+ dk.getFromMeta(q->qdomain, "PUBLISH-CDS", publishCDS);
+ vector<DNSResourceRecord> cds, cdnskey;
+ DNSSECKeeper::keyset_t entryPoints = dk.getEntryPoints(q->qdomain);
+ set<uint32_t> entryPointIds;
+ for (auto const& value : entryPoints)
+ entryPointIds.insert(value.second.id);
+
+ for(const DNSSECKeeper::keyset_t::value_type& value : keys) {
+ rr.qtype = QType(QType::DNSKEY);
+ rr.content = value.first.getDNSKEY().getZoneRepresentation();
+ string keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr, rr.qname) : labelReverse(rr.qname.toString());
+ NSECXEntry& ne = nsecxrepo[keyname];
+
+ ne.d_set.insert(rr.qtype.getCode());
+ ne.d_ttl = sd.default_ttl;
+ csp.submit(rr);
+
+ // generate CDS and CDNSKEY records
+ if(entryPointIds.count(value.second.id) > 0){
+ if(publishCDNSKEY == "1") {
+ rr.qtype=QType(QType::CDNSKEY);
+ rr.content = value.first.getDNSKEY().getZoneRepresentation();
+ cdnskey.push_back(rr);
+ }
+
+ if(!publishCDS.empty()){
+ rr.qtype=QType(QType::CDS);
+ vector<string> digestAlgos;
+ stringtok(digestAlgos, publishCDS, ", ");
+ for(auto const &digestAlgo : digestAlgos) {
+ rr.content=makeDSFromDNSKey(target, value.first.getDNSKEY(), pdns_stou(digestAlgo)).getZoneRepresentation();
+ cds.push_back(rr);
+ }
+ }
+ }
+ }
+
+ if(::arg().mustDo("direct-dnskey")) {
+ sd.db->lookup(QType(QType::DNSKEY), target, NULL, sd.domain_id);
+ while(sd.db->get(rr)) {
+ rr.ttl = sd.default_ttl;
+ csp.submit(rr);
+ }
+ }
+
+ uint8_t flags;
+
+ if(NSEC3Zone) { // now stuff in the NSEC3PARAM
+ flags = ns3pr.d_flags;
+ rr.qtype = QType(QType::NSEC3PARAM);
+ ns3pr.d_flags = 0;
+ rr.content = ns3pr.getZoneRepresentation();
+ ns3pr.d_flags = flags;
+ string keyname = hashQNameWithSalt(ns3pr, rr.qname);
+ NSECXEntry& ne = nsecxrepo[keyname];
+
+ ne.d_set.insert(rr.qtype.getCode());
+ csp.submit(rr);
+ }
+
+ // now start list zone
+ if(!(sd.db->list(target, sd.domain_id))) {
+ L<<Logger::Error<<"Backend signals error condition"<<endl;
+ outpacket->setRcode(2); // 'SERVFAIL'
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+
+
+ const bool rectify = !(presignedZone || ::arg().mustDo("disable-axfr-rectify"));
+ set<DNSName> qnames, nsset, terms;
+ vector<DNSResourceRecord> rrs;
+
+ // Add the CDNSKEY and CDS records we created earlier
+ for (auto const &rr : cds)
+ rrs.push_back(rr);
+
+ for (auto const &rr : cdnskey)
+ rrs.push_back(rr);
+
+ while(sd.db->get(rr)) {
+ rr.qname.makeUsLowerCase();
+ if(rr.qname.isPartOf(target)) {
+ if (rr.qtype.getCode() == QType::ALIAS && ::arg().mustDo("outgoing-axfr-expand-alias")) {
+ vector<DNSResourceRecord> ips;
+ int ret1 = stubDoResolve(rr.content, QType::A, ips);
+ int ret2 = stubDoResolve(rr.content, QType::AAAA, ips);
+ if(ret1 != RCode::NoError || ret2 != RCode::NoError) {
+ L<<Logger::Error<<"Error resolving for ALIAS "<<rr.content<<", aborting AXFR"<<endl;
+ outpacket->setRcode(2); // 'SERVFAIL'
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ for(const auto& ip: ips) {
+ rr.qtype = ip.qtype;
+ rr.content = ip.content;
+ rrs.push_back(rr);
+ }
+ continue;
+ }
+
+ if (rectify) {
+ if (rr.qtype.getCode()) {
+ qnames.insert(rr.qname);
+ if(rr.qtype.getCode() == QType::NS && rr.qname!=target)
+ nsset.insert(rr.qname);
+ } else {
+ // remove existing ents
+ continue;
+ }
+ }
+ rrs.push_back(rr);
+ } else {
+ if (rr.qtype.getCode())
+ L<<Logger::Warning<<"Zone '"<<target<<"' contains out-of-zone data '"<<rr.qname<<"|"<<rr.qtype.getName()<<"', ignoring"<<endl;
+ }
+ }
+
+ // Group records by name and type, signpipe stumbles over interrupted rrsets
+ sort(rrs.begin(), rrs.end(), [](const DNSResourceRecord& a, const DNSResourceRecord& b) {
+ return tie(a.qname, a.qtype) < tie(b.qname, b.qtype);
+ });
+
+ if(rectify) {
+ // set auth
+ for(DNSResourceRecord &rr : rrs) {
+ rr.auth=true;
+ if (rr.qtype.getCode() != QType::NS || rr.qname!=target) {
+ DNSName shorter(rr.qname);
+ do {
+ if (shorter==target) // apex is always auth
+ break;
+ if(nsset.count(shorter) && !(rr.qname==shorter && rr.qtype.getCode() == QType::DS)) {
+ rr.auth=false;
+ break;
+ }
+ } while(shorter.chopOff());
+ }
+ }
+
+ if(NSEC3Zone) {
+ // ents are only required for NSEC3 zones
+ uint32_t maxent = ::arg().asNum("max-ent-entries");
+ set<DNSName> nsec3set, nonterm;
+ for (auto &rr: rrs) {
+ bool skip=false;
+ DNSName shorter = rr.qname;
+ if (shorter != target && shorter.chopOff() && shorter != target) {
+ do {
+ if(nsset.count(shorter)) {
+ skip=true;
+ break;
+ }
+ } while(shorter.chopOff() && shorter != target);
+ }
+ shorter = rr.qname;
+ if(!skip && (rr.qtype.getCode() != QType::NS || !ns3pr.d_flags)) {
+ do {
+ if(!nsec3set.count(shorter)) {
+ nsec3set.insert(shorter);
+ }
+ } while(shorter != target && shorter.chopOff());
+ }
+ }
+
+ for(DNSResourceRecord &rr : rrs) {
+ DNSName shorter(rr.qname);
+ while(shorter != target && shorter.chopOff()) {
+ if(!qnames.count(shorter) && !nonterm.count(shorter) && nsec3set.count(shorter)) {
+ if(!(maxent)) {
+ L<<Logger::Warning<<"Zone '"<<target<<"' has too many empty non terminals."<<endl;
+ return 0;
+ }
+ nonterm.insert(shorter);
+ --maxent;
+ }
+ }
+ }
+
+ for(const auto& nt : nonterm) {
+ DNSResourceRecord rr;
+ rr.qname=nt;
+ rr.qtype="TYPE0";
+ rr.auth=true;
+ rrs.push_back(rr);
+ }
+ }
+
+ DLOG(for(const auto &rr: rrs) cerr<<rr.qname<<"\t"<<rr.qtype.getName()<<"\t"<<rr.auth<<endl;);
+ }
+
+
+ /* now write all other records */
+
+ string keyname;
+ set<string> ns3rrs;
+ unsigned int udiff;
+ DTime dt;
+ dt.set();
+ int records=0;
+ for(DNSResourceRecord &rr : rrs) {
+ if (rr.qtype.getCode() == QType::RRSIG) {
+ RRSIGRecordContent rrc(rr.content);
+ if(presignedZone && rrc.d_type == QType::NSEC3)
+ ns3rrs.insert(fromBase32Hex(makeRelative(rr.qname.toStringNoDot(), target.toStringNoDot()))); // FIXME400
+ continue;
+ }
+
+ // only skip the DNSKEY, CDNSKEY and CDS if direct-dnskey is enabled, to avoid changing behaviour
+ // when it is not enabled.
+ if(::arg().mustDo("direct-dnskey") && (rr.qtype.getCode() == QType::DNSKEY || rr.qtype.getCode() == QType::CDNSKEY || rr.qtype.getCode() == QType::CDS))
+ continue;
+
+ records++;
+ if(securedZone && (rr.auth || rr.qtype.getCode() == QType::NS)) {
+ if (NSEC3Zone || rr.qtype.getCode()) {
+ keyname = NSEC3Zone ? hashQNameWithSalt(ns3pr, rr.qname) : labelReverse(rr.qname.toString());
+ NSECXEntry& ne = nsecxrepo[keyname];
+ ne.d_ttl = sd.default_ttl;
+ ne.d_auth = (ne.d_auth || rr.auth || (NSEC3Zone && (!ns3pr.d_flags || (presignedZone && ns3pr.d_flags))));
+ if (rr.qtype.getCode()) {
+ ne.d_set.insert(rr.qtype.getCode());
+ }
+ }
+ }
+
+ if (!rr.qtype.getCode())
+ continue; // skip empty non-terminals
+
+ if(rr.qtype.getCode() == QType::SOA)
+ continue; // skip SOA - would indicate end of AXFR
+
+ if(csp.submit(rr)) {
+ for(;;) {
+ outpacket->getRRS() = csp.getChunk();
+ if(!outpacket->getRRS().empty()) {
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
+ sendPacket(outpacket, outsock);
+ trc.d_mac=outpacket->d_trc.d_mac;
+ outpacket=getFreshAXFRPacket(q);
+ }
+ else
+ break;
+ }
+ }
+ }
+ /*
+ udiff=dt.udiffNoReset();
+ cerr<<"Starting NSEC: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
+ cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
+ cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
+ */
+ if(securedZone) {
+ if(NSEC3Zone) {
+ for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
+ if(iter->second.d_auth && (!presignedZone || !ns3pr.d_flags || ns3rrs.count(iter->first))) {
+ NSEC3RecordContent n3rc;
+ n3rc.d_set = iter->second.d_set;
+ if (n3rc.d_set.size() && (n3rc.d_set.size() != 1 || !n3rc.d_set.count(QType::NS)))
+ n3rc.d_set.insert(QType::RRSIG);
+ n3rc.d_salt=ns3pr.d_salt;
+ n3rc.d_flags = ns3pr.d_flags;
+ n3rc.d_iterations = ns3pr.d_iterations;
+ n3rc.d_algorithm = 1; // SHA1, fixed in PowerDNS for now
+ nsecxrepo_t::const_iterator inext = iter;
+ inext++;
+ if(inext == nsecxrepo.end())
+ inext = nsecxrepo.begin();
+ while((!inext->second.d_auth || (presignedZone && ns3pr.d_flags && !ns3rrs.count(inext->first))) && inext != iter)
+ {
+ inext++;
+ if(inext == nsecxrepo.end())
+ inext = nsecxrepo.begin();
+ }
+ n3rc.d_nexthash = inext->first;
+ rr.qname = DNSName(toBase32Hex(iter->first))+DNSName(sd.qname);
+
+ rr.ttl = sd.default_ttl;
+ rr.content = n3rc.getZoneRepresentation();
+ rr.qtype = QType::NSEC3;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rr.auth=true;
+ if(csp.submit(rr)) {
+ for(;;) {
+ outpacket->getRRS() = csp.getChunk();
+ if(!outpacket->getRRS().empty()) {
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
+ sendPacket(outpacket, outsock);
+ trc.d_mac=outpacket->d_trc.d_mac;
+ outpacket=getFreshAXFRPacket(q);
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+ }
+ else for(nsecxrepo_t::const_iterator iter = nsecxrepo.begin(); iter != nsecxrepo.end(); ++iter) {
+ NSECRecordContent nrc;
+ nrc.d_set = iter->second.d_set;
+ nrc.d_set.insert(QType::RRSIG);
+ nrc.d_set.insert(QType::NSEC);
+ if(boost::next(iter) != nsecxrepo.end()) {
+ nrc.d_next = DNSName(labelReverse(boost::next(iter)->first));
+ }
+ else
+ nrc.d_next=DNSName(labelReverse(nsecxrepo.begin()->first));
+
+ rr.qname = DNSName(labelReverse(iter->first));
+
+ rr.ttl = sd.default_ttl;
+ rr.content = nrc.getZoneRepresentation();
+ rr.qtype = QType::NSEC;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ rr.auth=true;
+ if(csp.submit(rr)) {
+ for(;;) {
+ outpacket->getRRS() = csp.getChunk();
+ if(!outpacket->getRRS().empty()) {
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
+ sendPacket(outpacket, outsock);
+ trc.d_mac=outpacket->d_trc.d_mac;
+ outpacket=getFreshAXFRPacket(q);
+ }
+ else
+ break;
+ }
+ }
+ }
+ }
+ /*
+ udiff=dt.udiffNoReset();
+ cerr<<"Flushing pipe: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<csp.d_signed<<" / "<<udiff/1000000.0<<endl;
+ cerr<<"Outstanding: "<<csp.d_outstanding<<", "<<csp.d_queued - csp.d_signed << endl;
+ cerr<<"Ready for consumption: "<<csp.getReady()<<endl;
+ * */
+ for(;;) {
+ outpacket->getRRS() = csp.getChunk(true); // flush the pipe
+ if(!outpacket->getRRS().empty()) {
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true); // first answer is 'normal'
+ sendPacket(outpacket, outsock);
+ trc.d_mac=outpacket->d_trc.d_mac;
+ outpacket=getFreshAXFRPacket(q);
+ }
+ else
+ break;
+ }
+
+ udiff=dt.udiffNoReset();
+ if(securedZone)
+ L<<Logger::Info<<"Done signing: "<<csp.d_signed/(udiff/1000000.0)<<" sigs/s, "<<endl;
+
+ DLOG(L<<"Done writing out records"<<endl);
+ /* and terminate with yet again the SOA record */
+ outpacket=getFreshAXFRPacket(q);
+ outpacket->addRecord(soa);
+ editSOA(dk, sd.qname, outpacket.get());
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac, true);
+
+ sendPacket(outpacket, outsock);
+
+ DLOG(L<<"last packet - close"<<endl);
+ L<<Logger::Error<<"AXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
+
+ return 1;
+}
+
+int TCPNameserver::doIXFR(shared_ptr<DNSPacket> q, int outsock)
+{
+ shared_ptr<DNSPacket> outpacket=getFreshAXFRPacket(q);
+ if(q->d_dnssecOk)
+ outpacket->d_dnssecOk=true; // RFC 5936, 2.2.5 'SHOULD'
+
+ uint32_t serial = 0;
+ MOADNSParser mdp(false, q->getString());
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i != mdp.d_answers.end(); ++i) {
+ const DNSRecord *rr = &i->first;
+ if (rr->d_type == QType::SOA && rr->d_place == DNSResourceRecord::AUTHORITY) {
+ vector<string>parts;
+ stringtok(parts, rr->d_content->getZoneRepresentation());
+ if (parts.size() >= 3) {
+ try {
+ serial=pdns_stou(parts[2]);
+ }
+ catch(const std::out_of_range& oor) {
+ L<<Logger::Error<<"Invalid serial in IXFR query"<<endl;
+ outpacket->setRcode(RCode::FormErr);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ } else {
+ L<<Logger::Error<<"No serial in IXFR query"<<endl;
+ outpacket->setRcode(RCode::FormErr);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ } else if (rr->d_type != QType::TSIG && rr->d_type != QType::OPT) {
+ L<<Logger::Error<<"Additional records in IXFR query, type: "<<QType(rr->d_type).getName()<<endl;
+ outpacket->setRcode(RCode::FormErr);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ }
+
+ L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' initiated by "<<q->getRemote()<<" with serial "<<serial<<endl;
+
+ // determine if zone exists and AXFR is allowed using existing backend before spawning a new backend.
+ SOAData sd;
+ {
+ Lock l(&s_plock);
+ DLOG(L<<"Looking for SOA"<<endl); // find domain_id via SOA and list complete domain. No SOA, no IXFR
+ if(!s_P) {
+ L<<Logger::Error<<"TCP server is without backend connections in doIXFR, launching"<<endl;
+ s_P=new PacketHandler;
+ }
+
+ // canDoAXFR does all the ACL checks, and has the if(disable-axfr) shortcut, call it first.
+ if(!canDoAXFR(q) || !s_P->getBackend()->getSOAUncached(q->qdomain, sd)) {
+ L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' failed: not authoritative"<<endl;
+ outpacket->setRcode(9); // 'NOTAUTH'
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ }
+
+ DNSSECKeeper dk;
+ NSEC3PARAMRecordContent ns3pr;
+ bool narrow;
+
+ dk.clearCaches(q->qdomain);
+ bool securedZone = dk.isSecuredZone(q->qdomain);
+ if(dk.getNSEC3PARAM(q->qdomain, &ns3pr, &narrow)) {
+ if(narrow) {
+ L<<Logger::Error<<"Not doing IXFR of an NSEC3 narrow zone."<<endl;
+ L<<Logger::Error<<"IXFR of domain '"<<q->qdomain<<"' denied to "<<q->getRemote()<<endl;
+ outpacket->setRcode(RCode::Refused);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+ }
+
+ DNSName target = q->qdomain;
+
+ UeberBackend db;
+ if(!db.getSOAUncached(target, sd)) {
+ L<<Logger::Error<<"IXFR of domain '"<<target<<"' failed: not authoritative in second instance"<<endl;
+ outpacket->setRcode(RCode::NotAuth);
+ sendPacket(outpacket,outsock);
+ return 0;
+ }
+
+ string soaedit;
+ dk.getSoaEdit(target, soaedit);
+ if (!rfc1982LessThan(serial, calculateEditSOA(sd, soaedit))) {
+ TSIGRecordContent trc;
+ DNSName tsigkeyname;
+ string tsigsecret;
+
+ bool haveTSIGDetails = q->getTSIGDetails(&trc, &tsigkeyname, 0);
+
+ if(haveTSIGDetails && !tsigkeyname.empty()) {
+ string tsig64;
+ DNSName algorithm=trc.d_algoName; // FIXME400: was toLowerCanonic, compare output
+ if (algorithm == DNSName("hmac-md5.sig-alg.reg.int"))
+ algorithm = DNSName("hmac-md5");
+ Lock l(&s_plock);
+ s_P->getBackend()->getTSIGKey(tsigkeyname, &algorithm, &tsig64);
+ B64Decode(tsig64, tsigsecret);
+ }
+
+ UeberBackend signatureDB;
+
+ // SOA *must* go out first, our signing pipe might reorder
+ DLOG(L<<"Sending out SOA"<<endl);
+ DNSResourceRecord soa = makeDNSRRFromSOAData(sd);
+ outpacket->addRecord(soa);
+ editSOA(dk, sd.qname, outpacket.get());
+ if(securedZone) {
+ set<DNSName> authSet;
+ authSet.insert(target);
+ addRRSigs(dk, signatureDB, authSet, outpacket->getRRS());
+ }
+
+ if(haveTSIGDetails && !tsigkeyname.empty())
+ outpacket->setTSIGDetails(trc, tsigkeyname, tsigsecret, trc.d_mac); // first answer is 'normal'
+
+ sendPacket(outpacket, outsock);
+
+ L<<Logger::Error<<"IXFR of domain '"<<target<<"' to "<<q->getRemote()<<" finished"<<endl;
+
+ return 1;
+ }
+
+ L<<Logger::Error<<"IXFR fallback to AXFR for domain '"<<target<<"' our serial "<<sd.serial<<endl;
+ return doAXFR(q->qdomain, q, outsock);
+}
+
+TCPNameserver::~TCPNameserver()
+{
+ delete d_connectionroom_sem;
+}
+
+TCPNameserver::TCPNameserver()
+{
+// sem_init(&d_connectionroom_sem,0,::arg().asNum("max-tcp-connections"));
+ d_connectionroom_sem = new Semaphore( ::arg().asNum( "max-tcp-connections" ));
+ d_tid=0;
+ vector<string>locals;
+ stringtok(locals,::arg()["local-address"]," ,");
+
+ vector<string>locals6;
+ stringtok(locals6,::arg()["local-ipv6"]," ,");
+
+ if(locals.empty() && locals6.empty())
+ throw PDNSException("No local address specified");
+
+ d_ng.toMasks(::arg()["allow-axfr-ips"] );
+
+ signal(SIGPIPE,SIG_IGN);
+
+ for(vector<string>::const_iterator laddr=locals.begin();laddr!=locals.end();++laddr) {
+ int s=socket(AF_INET,SOCK_STREAM,0);
+
+ if(s<0)
+ throw PDNSException("Unable to acquire TCP socket: "+stringerror());
+
+ setCloseOnExec(s);
+
+ ComboAddress local(*laddr, ::arg().asNum("local-port"));
+
+ int tmp=1;
+ if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
+ L<<Logger::Error<<"Setsockopt failed"<<endl;
+ exit(1);
+ }
+
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET, s);
+
+ if(::bind(s, (sockaddr*)&local, local.getSocklen())<0) {
+ close(s);
+ if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-address-nonexist-fail") ) {
+ L<<Logger::Error<<"IPv4 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
+ continue;
+ } else {
+ L<<Logger::Error<<"Unable to bind to TCP socket " << *laddr << ": "<<strerror(errno)<<endl;
+ throw PDNSException("Unable to bind to TCP socket");
+ }
+ }
+
+ listen(s,128);
+ L<<Logger::Error<<"TCP server bound to "<<local.toStringWithPort()<<endl;
+ d_sockets.push_back(s);
+ struct pollfd pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = s;
+ pfd.events = POLLIN;
+
+ d_prfds.push_back(pfd);
+ }
+
+ for(vector<string>::const_iterator laddr=locals6.begin();laddr!=locals6.end();++laddr) {
+ int s=socket(AF_INET6,SOCK_STREAM,0);
+
+ if(s<0)
+ throw PDNSException("Unable to acquire TCPv6 socket: "+stringerror());
+
+ setCloseOnExec(s);
+
+ ComboAddress local(*laddr, ::arg().asNum("local-port"));
+
+ int tmp=1;
+ if(setsockopt(s,SOL_SOCKET,SO_REUSEADDR,(char*)&tmp,sizeof tmp)<0) {
+ L<<Logger::Error<<"Setsockopt failed"<<endl;
+ exit(1);
+ }
+ if( ::arg().mustDo("non-local-bind") )
+ Utility::setBindAny(AF_INET6, s);
+ if(setsockopt(s, IPPROTO_IPV6, IPV6_V6ONLY, &tmp, sizeof(tmp)) < 0) {
+ L<<Logger::Error<<"Failed to set IPv6 socket to IPv6 only, continuing anyhow: "<<strerror(errno)<<endl;
+ }
+ if(bind(s, (const sockaddr*)&local, local.getSocklen())<0) {
+ close(s);
+ if( errno == EADDRNOTAVAIL && ! ::arg().mustDo("local-ipv6-nonexist-fail") ) {
+ L<<Logger::Error<<"IPv6 Address " << *laddr << " does not exist on this server - skipping TCP bind" << endl;
+ continue;
+ } else {
+ L<<Logger::Error<<"Unable to bind to TCPv6 socket" << *laddr << ": "<<strerror(errno)<<endl;
+ throw PDNSException("Unable to bind to TCPv6 socket");
+ }
+ }
+
+ listen(s,128);
+ L<<Logger::Error<<"TCPv6 server bound to "<<local.toStringWithPort()<<endl; // this gets %eth0 right
+ d_sockets.push_back(s);
+
+ struct pollfd pfd;
+ memset(&pfd, 0, sizeof(pfd));
+ pfd.fd = s;
+ pfd.events = POLLIN;
+
+ d_prfds.push_back(pfd);
+ }
+}
+
+
+//! Start of TCP operations thread, we launch a new thread for each incoming TCP question
+void TCPNameserver::thread()
+{
+ try {
+ for(;;) {
+ int fd;
+ struct sockaddr_in remote;
+ Utility::socklen_t addrlen=sizeof(remote);
+
+ int ret=poll(&d_prfds[0], d_prfds.size(), -1); // blocks, forever if need be
+ if(ret <= 0)
+ continue;
+
+ int sock=-1;
+ for(const pollfd& pfd : d_prfds) {
+ if(pfd.revents == POLLIN) {
+ sock = pfd.fd;
+ addrlen=sizeof(remote);
+
+ if((fd=accept(sock, (sockaddr*)&remote, &addrlen))<0) {
+ L<<Logger::Error<<"TCP question accept error: "<<strerror(errno)<<endl;
+
+ if(errno==EMFILE) {
+ L<<Logger::Error<<"TCP handler out of filedescriptors, exiting, won't recover from this"<<endl;
+ exit(1);
+ }
+ }
+ else {
+ pthread_t tid;
+ d_connectionroom_sem->wait(); // blocks if no connections are available
+
+ int room;
+ d_connectionroom_sem->getValue( &room);
+ if(room<1)
+ L<<Logger::Warning<<"Limit of simultaneous TCP connections reached - raise max-tcp-connections"<<endl;
+
+ if(pthread_create(&tid, 0, &doConnection, reinterpret_cast<void*>(fd))) {
+ L<<Logger::Error<<"Error creating thread: "<<stringerror()<<endl;
+ d_connectionroom_sem->post();
+ close(fd);
+ }
+ }
+ }
+ }
+ }
+ }
+ catch(PDNSException &AE) {
+ L<<Logger::Error<<"TCP Nameserver thread dying because of fatal error: "<<AE.reason<<endl;
+ }
+ catch(...) {
+ L<<Logger::Error<<"TCPNameserver dying because of an unexpected fatal error"<<endl;
+ }
+ exit(1); // take rest of server with us
+}
+
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_TCPRECEIVER_HH
+#define PDNS_TCPRECEIVER_HH
+
+#include "dns.hh"
+#include "iputils.hh"
+#include "dnsbackend.hh"
+#include "packethandler.hh"
+#include <vector>
+
+#include <poll.h>
+#include <sys/select.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <sys/uio.h>
+#include <sys/select.h>
+
+#include "namespaces.hh"
+
+class TCPNameserver
+{
+public:
+ TCPNameserver();
+ ~TCPNameserver();
+ void go();
+private:
+
+ static void sendPacket(std::shared_ptr<DNSPacket> p, int outsock);
+ static int readLength(int fd, ComboAddress *remote);
+ static void getQuestion(int fd, char *mesg, int pktlen, const ComboAddress& remote);
+ static int doAXFR(const DNSName &target, std::shared_ptr<DNSPacket> q, int outsock);
+ static int doIXFR(std::shared_ptr<DNSPacket> q, int outsock);
+ static bool canDoAXFR(std::shared_ptr<DNSPacket> q);
+ static void *doConnection(void *data);
+ static void *launcher(void *data);
+ void thread(void);
+ static pthread_mutex_t s_plock;
+ static PacketHandler *s_P;
+ pthread_t d_tid;
+ static Semaphore *d_connectionroom_sem;
+ static NetmaskGroup d_ng;
+
+ vector<int>d_sockets;
+ vector<struct pollfd> d_prfds;
+};
+
+#endif /* PDNS_TCPRECEIVER_HH */
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <boost/test/unit_test.hpp>
+#include "arguments.hh"
+#include "namespaces.hh"
+
+BOOST_AUTO_TEST_SUITE(test_arguments_cc)
+
+BOOST_AUTO_TEST_CASE(test_file_parse) {
+ char path[]="/tmp/pdns-test-conf.XXXXXX";
+ int fd=mkstemp(path);
+ if(fd < 0)
+ BOOST_FAIL("Unable to generate a temporary file");
+
+ string config=
+R"(launch=launch=1234
+test=123\
+456
+test2=here # and here it stops
+fail=no
+success=on
+really=yes)";
+
+ int len=write(fd, config.c_str(), config.size());
+
+ BOOST_CHECK_EQUAL(len, config.size());
+ if(!len)
+ return;
+ close(fd);
+
+ try {
+ ArgvMap arg;
+ for(auto& a : {"launch", "test", "test2", "fail", "success", "really"} )
+ arg.set(a,a);
+ arg.set("default", "default")="no";
+ arg.file(path);
+ unlink(path);
+
+ BOOST_CHECK_EQUAL(arg["launch"], "launch=1234");
+ BOOST_CHECK_EQUAL(arg["test"], "123456");
+ BOOST_CHECK_EQUAL(arg.asNum("test"), 123456);
+ BOOST_CHECK_EQUAL(arg["test2"], "here");
+ BOOST_CHECK_EQUAL(arg.mustDo("fail"), false);
+ BOOST_CHECK_EQUAL(arg.mustDo("success"), true);
+ BOOST_CHECK_EQUAL(arg.mustDo("really"), true);
+ BOOST_CHECK_EQUAL(arg["default"], "no");
+
+ }
+ catch(PDNSException& e) {
+ unlink(path);
+ cerr<<"Exception: "<<e.reason<<endl;
+ BOOST_FAIL("Exception: "+e.reason);
+ }
+};
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "base32.hh"
+
+BOOST_AUTO_TEST_SUITE(test_base32_cc)
+
+BOOST_AUTO_TEST_CASE(test_record_types) {
+ typedef boost::tuple<const std::string, const std::string> case_t;
+ typedef std::list<case_t> cases_t;
+
+ // RFC test vectors
+ cases_t cases = boost::assign::list_of
+ (case_t(std::string(""), std::string("")))
+ (case_t(std::string("f"), std::string("co======")))
+ (case_t(std::string("fo"), std::string("cpng====")))
+ (case_t(std::string("foo"), std::string("cpnmu===")))
+ (case_t(std::string("foob"), std::string("cpnmuog=")))
+ (case_t(std::string("fooba"), std::string("cpnmuoj1")))
+ (case_t(std::string("foobar"), std::string("cpnmuoj1e8======")))
+ ;
+
+ for(const case_t& val : cases) {
+ std::string res;
+ res = toBase32Hex(val.get<0>());
+ BOOST_CHECK_EQUAL(res, val.get<1>());
+ res = fromBase32Hex(val.get<1>());
+ BOOST_CHECK_EQUAL(res, val.get<0>());
+ }
+};
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/std/map.hpp>
+
+#include "base64.hh"
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(base64_cc)
+
+BOOST_AUTO_TEST_CASE(test_Base64_Roundtrip) {
+ std::string before("Some Random String"), after;
+ std::string encoded = Base64Encode(before);
+ B64Decode(encoded, after);
+ BOOST_CHECK_EQUAL(before, after);
+}
+
+/* for a in $(seq 1 32);
+ do
+ plain=$(pwgen -1 -s $a)
+ echo \(\"$plain\",\"$(echo -n $plain | openssl enc -base64)\"\) ;
+ done
+*/
+
+BOOST_AUTO_TEST_CASE(test_Base64_Encode) {
+ typedef std::map<std::string, std::string> cases_t;
+ cases_t cases;
+ assign::insert(cases)
+ ("", "")
+ ("z","eg==")
+ ("x4","eDQ=")
+ ("J07","SjA3")
+ ("kl8F","a2w4Rg==")
+ ("2NUx9","Mk5VeDk=")
+ ("hwXQ8C","aHdYUThD")
+ ("V7ZHmlG","VjdaSG1sRw==")
+ ("FuNFLSd5","RnVORkxTZDU=")
+ ("YVGwy3Vbi","WVZHd3kzVmJp")
+ ("6ueW4V3oLG","NnVlVzRWM29MRw==")
+ ("d5zR7AWIBIQ","ZDV6UjdBV0lCSVE=")
+ ("WJjZ6xgpRMCD","V0pqWjZ4Z3BSTUNE")
+ ("e8I52L0vC9Kfq","ZThJNTJMMHZDOUtmcQ==")
+ ("ufxMi8EZgTDja8","dWZ4TWk4RVpnVERqYTg=")
+ ("MiNPxzxUkNXCFg1","TWlOUHh6eFVrTlhDRmcx")
+ ("abqIPosEky85gFVM","YWJxSVBvc0VreTg1Z0ZWTQ==")
+ ("Qccuox8igoyRKEeTo","UWNjdW94OGlnb3lSS0VlVG8=")
+ ("wbaw6g6WWo4iiYXosV","d2JhdzZnNldXbzRpaVlYb3NW")
+ ("ZIfJZIA3Kd0a6iIr0vc","WklmSlpJQTNLZDBhNmlJcjB2Yw==")
+ ("SUhE1RK7xrRfvYOiaPMQ","U1VoRTFSSzd4clJmdllPaWFQTVE=")
+ ("ZAWsEeB4bcTUzTr828VTd","WkFXc0VlQjRiY1RVelRyODI4VlRk")
+ ("xc9rpu0F5ztR7r3jElr2BS","eGM5cnB1MEY1enRSN3IzakVscjJCUw==")
+ ("xvEWPkZjqVjIZwsL5WhijES","eHZFV1BrWmpxVmpJWndzTDVXaGlqRVM=")
+ ("yy4yAmcBKCNF3hWriWbDnKmF","eXk0eUFtY0JLQ05GM2hXcmlXYkRuS21G")
+ ("9wKEMpl8OlFvnD10wwhoK7BjY","OXdLRU1wbDhPbEZ2bkQxMHd3aG9LN0JqWQ==")
+ ("SB6yLm39pDVIUiQ5g73BvyRzBs","U0I2eUxtMzlwRFZJVWlRNWc3M0J2eVJ6QnM=")
+ ("Acu4kk1puF98lIzd1b9bt8ha7Er","QWN1NGtrMXB1Rjk4bEl6ZDFiOWJ0OGhhN0Vy")
+ ("P4X6efItE6cn03ksLTvniqMQlel3","UDRYNmVmSXRFNmNuMDNrc0xUdm5pcU1RbGVsMw==")
+ ("RnQSvhIOz3ywuHCoSotJGKjBdCVbx","Um5RU3ZoSU96M3l3dUhDb1NvdEpHS2pCZENWYng=")
+ ("ykybXtN0lelsLSzyzd4DTP3sYp8YGu","eWt5Ylh0TjBsZWxzTFN6eXpkNERUUDNzWXA4WUd1")
+ ("eSHBt7Xx5F7A4HFtabXEzDLD01bnSiG","ZVNIQnQ3WHg1RjdBNEhGdGFiWEV6RExEMDFiblNpRw==")
+ ("dq4KydZjmcoQQ45VYBP2EDR8FqKaMul0","ZHE0S3lkWmptY29RUTQ1VllCUDJFRFI4RnFLYU11bDA=");
+
+ for(const cases_t::value_type& val : cases) {
+ std::string encoded = Base64Encode(val.first), decoded;
+ BOOST_CHECK_EQUAL(encoded, val.second);
+ decoded.clear();
+ B64Decode(val.second, decoded);
+ BOOST_CHECK_EQUAL(decoded, val.first);
+ }
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "misc.hh"
+#include "pdnsexception.hh"
+#include <utility>
+
+#include <sstream>
+#include <cstdlib>
+#include "dnsname.hh"
+#include "bindparserclasses.hh"
+
+using std::string;
+
+BOOST_AUTO_TEST_SUITE(bindparser_cc)
+
+BOOST_AUTO_TEST_CASE(test_parser) {
+ const char *srcdir;
+ std::ostringstream pathbuf;
+ BindParser BP;
+ BOOST_CHECK_THROW( BP.parse("../regression-tests/named.confx"), PDNSException);
+ BP.setVerbose(true);
+ srcdir = std::getenv("SRCDIR");
+ if(!srcdir)
+ srcdir="."; // assume no shenanigans
+
+ pathbuf << srcdir << "/../pdns/named.conf.parsertest";
+ BP.parse(pathbuf.str());
+
+ vector<BindDomainInfo> domains=BP.getDomains();
+ BOOST_CHECK_EQUAL(domains.size(), 11);
+
+#define checkzone(i, dname, fname, ztype, nmasters) { \
+ BOOST_CHECK(domains[i].name == DNSName(#dname)); \
+ BOOST_CHECK_EQUAL(domains[i].filename, fname); \
+ BOOST_CHECK_EQUAL(domains[i].type, #ztype); \
+ BOOST_CHECK_EQUAL(domains[i].masters.size(), nmasters); \
+ }
+
+ checkzone(0, example.com, "./zones//example.com", master, 0);
+ checkzone(1, test.com, "./zones//test.com", slave, 1);
+ BOOST_CHECK_EQUAL(domains[1].masters[0], "1.2.3.4:5678");
+ checkzone(2, test.dyndns, "./zones//test.dyndns", garblewarble, 0);
+ checkzone(3, wtest.com, "./zones//wtest.com", master, 0);
+ checkzone(4, nztest.com, "./zones//nztest.com", master, 0);
+ checkzone(5, dnssec-parent.com, "./zones//dnssec-parent.com", master, 0);
+ checkzone(6, delegated.dnssec-parent.com, "./zones//delegated.dnssec-parent.com", master, 0);
+ checkzone(7, secure-delegated.dnssec-parent.com, "./zones//secure-delegated.dnssec-parent.com", master, 0);
+ checkzone(8, minimal.com, "./zones//minimal.com", master, 0);
+ checkzone(9, tsig.com, "./zones//tsig.com", master, 0);
+ checkzone(10, stest.com, "./zones//stest.com", master, 0);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "delaypipe.hh"
+
+BOOST_AUTO_TEST_SUITE(test_delaypipe_hh);
+
+BOOST_AUTO_TEST_CASE(test_object_pipe) {
+ ObjectPipe<int> op;
+ for(int n=0; n < 100; ++n)
+ op.write(n);
+
+ int i;
+ for(int n=0; n < 100; ++n) {
+ bool res=op.read(&i);
+ BOOST_CHECK_EQUAL(res, true);
+ BOOST_CHECK_EQUAL(n, i);
+ }
+
+ op.close();
+ BOOST_CHECK_EQUAL(op.read(&i), false);
+
+};
+
+int done=0;
+BOOST_AUTO_TEST_CASE(test_delay_pipe_small) {
+ struct Work
+ {
+ int i;
+ void operator()()
+ {
+ ++done;
+ }
+ };
+ DelayPipe<Work> dp;
+ int n;
+ for(n=0; n < 5; ++n) {
+ Work w{n};
+ dp.submit(w, 500);
+ }
+ BOOST_CHECK_EQUAL(done, 0);
+
+ for(; n < 10; ++n) {
+ Work w{n};
+ dp.submit(w, 1200);
+ }
+ sleep(1);
+ BOOST_CHECK_EQUAL(done, 5);
+ sleep(1);
+ BOOST_CHECK_EQUAL(done, n);
+
+};
+
+BOOST_AUTO_TEST_CASE(test_delay_pipe_big) {
+ done=0;
+ struct Work
+ {
+ int i;
+ void operator()()
+ {
+ ++done;
+ }
+ };
+ DelayPipe<Work> dp;
+ int n;
+ for(n=0; n < 1000000; ++n) {
+ Work w{n};
+ dp.submit(w, 100);
+ }
+
+ sleep(1);
+ BOOST_CHECK_EQUAL(done, n);
+};
+
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <stdlib.h>
+#include <unistd.h>
+#include <boost/test/unit_test.hpp>
+#include "distributor.hh"
+#include "dnspacket.hh"
+#include "namespaces.hh"
+
+BOOST_AUTO_TEST_SUITE(test_distributor_hh)
+
+struct Question
+{
+ int q;
+ DTime d_dt;
+ DNSName qdomain;
+ DNSPacket* replyPacket()
+ {
+ return new DNSPacket(false);
+ }
+};
+
+struct Backend
+{
+ DNSPacket* question(Question*)
+ {
+ return new DNSPacket(true);
+ }
+};
+
+static std::atomic<int> g_receivedAnswers;
+static void report(DNSPacket* A)
+{
+ delete A;
+ g_receivedAnswers++;
+}
+
+BOOST_AUTO_TEST_CASE(test_distributor_basic) {
+ ::arg().set("overload-queue-length","Maximum queuelength moving to packetcache only")="0";
+ ::arg().set("max-queue-length","Maximum queuelength before considering situation lost")="5000";
+ ::arg().set("queue-limit","Maximum number of milliseconds to queue a query")="1500";
+ S.declare("servfail-packets","Number of times a server-failed packet was sent out");
+ S.declare("timedout-packets", "timedout-packets");
+
+ auto d=Distributor<DNSPacket, Question, Backend>::Create(2);
+
+ int n;
+ for(n=0; n < 100; ++n) {
+ auto q = new Question();
+ q->d_dt.set();
+ d->question(q, report);
+ }
+ sleep(1);
+ BOOST_CHECK_EQUAL(n, g_receivedAnswers);
+};
+
+struct BackendSlow
+{
+ DNSPacket* question(Question*)
+ {
+ sleep(1);
+ return new DNSPacket(true);
+ }
+};
+
+
+BOOST_AUTO_TEST_CASE(test_distributor_queue) {
+ auto d=Distributor<DNSPacket, Question, BackendSlow>::Create(2);
+
+ BOOST_CHECK_EXCEPTION( {
+ int n;
+ for(n=0; n < 6000; ++n) {
+ auto q = new Question();
+ q->d_dt.set();
+ d->question(q, report);
+ }
+ }, DistributorFatal, [](DistributorFatal) { return true; });
+};
+
+struct BackendDies
+{
+ BackendDies()
+ {
+ d_ourcount=s_count++;
+ }
+ ~BackendDies()
+ {
+ }
+ DNSPacket* question(Question* q)
+ {
+ // cout<<"Q: "<<q->qdomain<<endl;
+ if(!d_ourcount && ++d_count == 10) {
+ // cerr<<"Going.. down!"<<endl;
+ throw runtime_error("kill");
+ }
+ return new DNSPacket(true);
+ }
+ static std::atomic<int> s_count;
+ int d_count{0};
+ int d_ourcount;
+};
+
+std::atomic<int> BackendDies::s_count;
+
+std::atomic<int> g_receivedAnswers2;
+
+static void report2(DNSPacket* A)
+{
+ delete A;
+ g_receivedAnswers2++;
+}
+
+
+BOOST_AUTO_TEST_CASE(test_distributor_dies) {
+ auto d=Distributor<DNSPacket, Question, BackendDies>::Create(10);
+ sleep(1);
+ g_receivedAnswers=0;
+
+ try {
+ for(int n=0; n < 100; ++n) {
+ auto q = new Question();
+ q->d_dt.set();
+ q->qdomain=DNSName(std::to_string(n));
+ d->question(q, report2);
+ }
+
+ sleep(1);
+ cerr<<"Queued: "<<d->getQueueSize()<<endl;
+ cerr<<"Received: "<<g_receivedAnswers2<<endl;
+ }
+ catch(std::exception& e) {
+ cerr<<e.what()<<endl;
+ }
+ catch(PDNSException &pe) {
+ cerr<<pe.reason<<endl;
+ }
+};
+
+
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+// Disable this code for gcc 4.8 and lower
+#if (__GNUC__ == 4 && __GNUC_MINOR__ > 8) || !__GNUC__
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/std/map.hpp>
+
+#include <boost/accumulators/statistics/median.hpp>
+#include <boost/accumulators/statistics/mean.hpp>
+#include <boost/accumulators/accumulators.hpp>
+#include <boost/accumulators/statistics.hpp>
+
+#include "dns_random.hh"
+#include "namespaces.hh"
+
+
+using namespace boost;
+using namespace boost::accumulators;
+
+typedef accumulator_set<
+ double
+ , stats<boost::accumulators::tag::median(with_p_square_quantile),
+ boost::accumulators::tag::mean(immediate)
+ >
+ > acc_t;
+
+
+
+BOOST_AUTO_TEST_SUITE(test_dns_random_hh)
+
+
+
+BOOST_AUTO_TEST_CASE(test_dns_random_average) {
+
+ dns_random_init("loremipsumdolorx");
+ acc_t acc;
+
+ for(unsigned int n=0; n < 100000; ++n) {
+ acc(dns_random(100000)/100000.0);
+ }
+ BOOST_CHECK_CLOSE(0.5, median(acc), 2.0); // within 2%
+ BOOST_CHECK_CLOSE(0.5, mean(acc), 2.0);
+
+
+ // please add covariance tests, chi-square, Kolmogorov-Smirnov
+}
+
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
+#endif
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/std/map.hpp>
+#include <numeric>
+#include <math.h>
+#include "dnsname.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include <unordered_set>
+using namespace boost;
+using std::string;
+
+BOOST_AUTO_TEST_SUITE(dnsname_cc)
+
+BOOST_AUTO_TEST_CASE(test_basic) {
+ string before("www.ds9a.nl.");
+ DNSName b(before);
+ BOOST_CHECK_EQUAL(b.getRawLabels().size(), 3);
+ string after(b.toString());
+ BOOST_CHECK_EQUAL(before, after);
+
+ DNSName jpmens("ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
+
+ BOOST_CHECK_EQUAL(jpmens.toString(), "ccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc.bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb.aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.test.xxx.yyy-yyyy.zzzzzzzzz-test.");
+
+ DNSName wwwds9anl("www.ds9a.nl.");
+ DNSName wwwds9anl1("www.ds9a\002nl.");
+ DNSName nl("nl.");
+ BOOST_CHECK(wwwds9anl.isPartOf(nl));
+ BOOST_CHECK(!wwwds9anl1.isPartOf(nl));
+ BOOST_CHECK(wwwds9anl.isPartOf(wwwds9anl));
+
+ BOOST_CHECK(!nl.isPartOf(wwwds9anl));
+
+ BOOST_CHECK(wwwds9anl == wwwds9anl);
+
+ BOOST_CHECK(DNSName("wWw.ds9A.Nl.") == DNSName("www.ds9a.nl."));
+ BOOST_CHECK(DNSName("www.ds9a.nl.") == DNSName("www.ds9a.nl."));
+
+ BOOST_CHECK(DNSName("www.ds9a.nl.").toString() == "www.ds9a.nl.");
+
+
+ { // Check root vs empty
+ DNSName name("."); // root
+ DNSName parent; // empty
+ BOOST_CHECK(name != parent);
+ }
+
+ { // Check name part of root
+ DNSName name("a.");
+ DNSName parent(".");
+ BOOST_CHECK(name.isPartOf(parent));
+ }
+
+ { // Label boundary
+ DNSName name("a\002bb.");
+ DNSName parent("bb.");
+ BOOST_CHECK(!name.isPartOf(parent));
+ }
+
+ { // Multi label parent
+ DNSName name("a.bb.ccc.dddd.");
+ DNSName parent("ccc.dddd.");
+ BOOST_CHECK(name.isPartOf(parent));
+ }
+
+ { // Last char diff
+ DNSName name("a.bb.ccc.dddd.");
+ DNSName parent("ccc.dddx.");
+ BOOST_CHECK(!name.isPartOf(parent));
+ }
+
+ { // Equal length identical
+ DNSName name("aaaa.bbb.cc.d.");
+ DNSName parent("aaaa.bbb.cc.d.");
+ BOOST_CHECK(name.isPartOf(parent));
+ }
+
+ { // Equal length first char diff
+ DNSName name("xaaa.bbb.cc.d.");
+ DNSName parent("aaaa.bbb.cc.d.");
+ BOOST_CHECK(!name.isPartOf(parent));
+ }
+
+ { // Make relative
+ DNSName name("aaaa.bbb.cc.d.");
+ DNSName parent("cc.d.");
+ BOOST_CHECK_EQUAL( name.makeRelative(parent), DNSName("aaaa.bbb."));
+ }
+
+ { // Labelreverse
+ DNSName name("aaaa.bbb.cc.d.");
+ BOOST_CHECK( name.labelReverse() == DNSName("d.cc.bbb.aaaa."));
+ }
+
+ { // empty() empty
+ DNSName name;
+ BOOST_CHECK(name.empty());
+ }
+
+ { // empty() root
+ DNSName name(".");
+ BOOST_CHECK(!name.empty());
+
+ DNSName rootnodot("");
+ BOOST_CHECK_EQUAL(name, rootnodot);
+
+ string empty;
+ DNSName rootnodot2(empty);
+ BOOST_CHECK_EQUAL(rootnodot2, name);
+ }
+
+ DNSName left("ds9a.nl.");
+ left.prependRawLabel("www");
+ BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl."));
+
+ left.appendRawLabel("com");
+
+ BOOST_CHECK( left == DNSName("WwW.Ds9A.Nl.com."));
+
+ DNSName unset;
+
+ unset.appendRawLabel("www");
+ unset.appendRawLabel("powerdns.com");
+ unset.appendRawLabel("com");
+
+ BOOST_CHECK_EQUAL(unset.toString(), "www.powerdns\\.com.com.");
+
+ DNSName rfc4343_2_2(R"(Donald\032E\.\032Eastlake\0323rd.example.)");
+ DNSName example("example.");
+ BOOST_CHECK(rfc4343_2_2.isPartOf(example));
+
+ auto labels=rfc4343_2_2.getRawLabels();
+ BOOST_CHECK_EQUAL(*labels.begin(), "Donald E. Eastlake 3rd");
+ BOOST_CHECK_EQUAL(*labels.rbegin(), "example");
+ BOOST_CHECK_EQUAL(labels.size(), 2);
+
+
+ DNSName build;
+ build.appendRawLabel("Donald E. Eastlake 3rd");
+ build.appendRawLabel("example");
+ BOOST_CHECK_EQUAL(build.toString(), R"(Donald\032E\.\032Eastlake\0323rd.example.)");
+ BOOST_CHECK_THROW(DNSName broken("bert..hubert."), std::runtime_error);
+
+ DNSName n;
+ n.appendRawLabel("powerdns.dnsmaster");
+ n.appendRawLabel("powerdns");
+ n.appendRawLabel("com");
+
+ BOOST_CHECK_EQUAL(n.toString(), "powerdns\\.dnsmaster.powerdns.com.");
+
+ // BOOST_CHECK(DNSName().toString() != ".");
+
+ DNSName p;
+ string label("power");
+ label.append(1, (char)0);
+ label.append("dns");
+ p.appendRawLabel(label);
+ p.appendRawLabel("com");
+
+ BOOST_CHECK_EQUAL(p.toString(), "power\\000dns.com.");
+}
+
+BOOST_AUTO_TEST_CASE(test_trim) {
+ DNSName w("www.powerdns.com.");
+ BOOST_CHECK_EQUAL(w.countLabels(), 3);
+ w.trimToLabels(2);
+ BOOST_CHECK_EQUAL(w.toString(), "powerdns.com.");
+ DNSName w2("powerdns.com.");
+ BOOST_CHECK(w==w2);
+
+ DNSName root(".");
+ BOOST_CHECK_EQUAL(root.countLabels(), 0);
+}
+
+BOOST_AUTO_TEST_CASE(test_toolong) {
+
+ BOOST_CHECK_THROW(DNSName w("1234567890123456789012345678901234567890123456789012345678901234567890.com."), std::range_error);
+
+ BOOST_CHECK_THROW(DNSName w("12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.12345678901234567890.12345678901234567890123456.789012345678901.234567890.234567890.789012345678901.234567890.234567890.789012345678901.234567890.234567890.com."), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_dnsstrings) {
+ DNSName w("www.powerdns.com.");
+ BOOST_CHECK_EQUAL(w.toDNSString(), string("\003www\010powerdns\003com\000", 18));
+}
+
+BOOST_AUTO_TEST_CASE(test_empty) {
+ DNSName empty;
+ BOOST_CHECK_THROW(empty.toString(), std::out_of_range);
+ BOOST_CHECK_THROW(empty.toStringNoDot(), std::out_of_range);
+ BOOST_CHECK_THROW(empty.toDNSString(), std::out_of_range);
+ BOOST_CHECK(empty.empty());
+ BOOST_CHECK(!empty.isRoot());
+ BOOST_CHECK(!empty.isWildcard());
+ BOOST_CHECK_EQUAL(empty, empty);
+ BOOST_CHECK(!(empty < empty));
+
+ DNSName root(".");
+ BOOST_CHECK(empty < root);
+
+ BOOST_CHECK_THROW(empty.isPartOf(root), std::out_of_range);
+ BOOST_CHECK_THROW(root.isPartOf(empty), std::out_of_range);
+}
+
+BOOST_AUTO_TEST_CASE(test_specials) {
+ DNSName root(".");
+
+ BOOST_CHECK(root.isRoot());
+ BOOST_CHECK(root != DNSName());
+
+ DNSName wcard("*.powerdns.com");
+ BOOST_CHECK(wcard.isWildcard());
+
+ DNSName notwcard("www.powerdns.com");
+ BOOST_CHECK(!notwcard.isWildcard());
+}
+
+
+BOOST_AUTO_TEST_CASE(test_chopping) {
+ DNSName w("www.powerdns.com.");
+ BOOST_CHECK_EQUAL(w.toString(), "www.powerdns.com.");
+ BOOST_CHECK(w.chopOff());
+ BOOST_CHECK_EQUAL(w.toString(), "powerdns.com.");
+ BOOST_CHECK(w.chopOff());
+ BOOST_CHECK_EQUAL(w.toString(), "com.");
+ BOOST_CHECK(w.chopOff());
+ BOOST_CHECK_EQUAL(w.toString(), ".");
+ BOOST_CHECK(!w.chopOff());
+ BOOST_CHECK(!w.chopOff());
+
+ w.prependRawLabel("net");
+ w.prependRawLabel("root-servers");
+ w.prependRawLabel("a");
+ BOOST_CHECK_EQUAL(w.toString(), "a.root-servers.net.");
+}
+
+BOOST_AUTO_TEST_CASE(test_Append) {
+ DNSName dn("www."), powerdns("powerdns.com.");
+ DNSName tot=dn+powerdns;
+
+ BOOST_CHECK_EQUAL(tot.toString(), "www.powerdns.com.");
+ BOOST_CHECK(tot == DNSName("www.powerdns.com."));
+
+ dn+=powerdns;
+
+ BOOST_CHECK(dn == DNSName("www.powerdns.com."));
+}
+
+BOOST_AUTO_TEST_CASE(test_PacketParse) {
+ vector<unsigned char> packet;
+ reportBasicTypes();
+ DNSName root(".");
+ DNSPacketWriter dpw1(packet, DNSName("."), QType::AAAA);
+ DNSName p((char*)&packet[0], packet.size(), 12, false);
+ BOOST_CHECK_EQUAL(p, root);
+ unsigned char* buffer=&packet[0];
+ /* set invalid label len:
+ - packet.size() == 17 (sizeof(dnsheader) + 1 + 2 + 2)
+ - label len < packet.size() but
+ - offset is 12, label len of 15 should be rejected
+ because offset + 15 >= packet.size()
+ */
+ buffer[sizeof(dnsheader)] = 15;
+ BOOST_CHECK_THROW(DNSName((char*)&packet[0], packet.size(), 12, false), std::range_error);
+}
+
+
+BOOST_AUTO_TEST_CASE(test_hash) {
+ DNSName a("wwW.Ds9A.Nl"), b("www.ds9a.nl");
+ BOOST_CHECK_EQUAL(a.hash(), b.hash());
+
+ vector<uint32_t> counts(1500);
+
+ for(unsigned int n=0; n < 100000; ++n) {
+ DNSName dn(std::to_string(n)+"."+std::to_string(n*2)+"ds9a.nl");
+ DNSName dn2(std::to_string(n)+"."+std::to_string(n*2)+"Ds9a.nL");
+ BOOST_CHECK_EQUAL(dn.hash(), dn2.hash());
+ counts[dn.hash() % counts.size()]++;
+ }
+
+ double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0);
+ double m = sum / counts.size();
+
+ double accum = 0.0;
+ std::for_each (std::begin(counts), std::end(counts), [&](const double d) {
+ accum += (d - m) * (d - m);
+ });
+
+ double stdev = sqrt(accum / (counts.size()-1));
+ BOOST_CHECK(stdev < 10);
+}
+
+BOOST_AUTO_TEST_CASE(test_hashContainer) {
+ std::unordered_set<DNSName> s;
+ s.insert(DNSName("www.powerdns.com"));
+ BOOST_CHECK(s.count(DNSName("WwW.PoWerDNS.CoM")));
+ BOOST_CHECK_EQUAL(s.size(), 1);
+ s.insert(DNSName("www.POWERDNS.com"));
+ BOOST_CHECK_EQUAL(s.size(), 1);
+ s.insert(DNSName("www2.POWERDNS.com"));
+ BOOST_CHECK_EQUAL(s.size(), 2);
+
+ s.clear();
+ unsigned int n=0;
+ for(; n < 100000; ++n)
+ s.insert(DNSName(std::to_string(n)+".test.nl"));
+ BOOST_CHECK_EQUAL(s.size(), n);
+
+}
+
+
+BOOST_AUTO_TEST_CASE(test_QuestionHash) {
+ vector<unsigned char> packet;
+ reportBasicTypes();
+ DNSPacketWriter dpw1(packet, DNSName("www.ds9a.nl."), QType::AAAA);
+
+ auto hash1=hashQuestion((char*)&packet[0], packet.size(), 0);
+ DNSPacketWriter dpw2(packet, DNSName("wWw.Ds9A.nL."), QType::AAAA);
+ auto hash2=hashQuestion((char*)&packet[0], packet.size(), 0);
+ BOOST_CHECK_EQUAL(hash1, hash2);
+
+ vector<uint32_t> counts(1500);
+
+ for(unsigned int n=0; n < 100000; ++n) {
+ packet.clear();
+ DNSPacketWriter dpw1(packet, DNSName(std::to_string(n)+"."+std::to_string(n*2)+"."), QType::AAAA);
+ counts[hashQuestion((char*)&packet[0], packet.size(), 0) % counts.size()]++;
+ }
+
+ double sum = std::accumulate(std::begin(counts), std::end(counts), 0.0);
+ double m = sum / counts.size();
+
+ double accum = 0.0;
+ std::for_each (std::begin(counts), std::end(counts), [&](const double d) {
+ accum += (d - m) * (d - m);
+ });
+
+ double stdev = sqrt(accum / (counts.size()-1));
+ BOOST_CHECK(stdev < 10);
+}
+
+
+BOOST_AUTO_TEST_CASE(test_packetParse) {
+ vector<unsigned char> packet;
+ reportBasicTypes();
+ DNSPacketWriter dpw(packet, DNSName("www.ds9a.nl."), QType::AAAA);
+
+ uint16_t qtype, qclass;
+ DNSName dn((char*)&packet[0], packet.size(), 12, false, &qtype, &qclass);
+ BOOST_CHECK_EQUAL(dn.toString(), "www.ds9a.nl.");
+ BOOST_CHECK(qtype == QType::AAAA);
+ BOOST_CHECK_EQUAL(qclass, 1);
+
+ dpw.startRecord(DNSName("ds9a.nl."), DNSRecordContent::TypeToNumber("NS"));
+ NSRecordContent nrc("ns1.powerdns.com");
+ nrc.toPacket(dpw);
+
+ dpw.commit();
+
+ /* packet now looks like this:
+ 012345678901 12 bytes of header
+ 3www4ds9a2nl0 13 bytes of name
+ 0001 0001 4 bytes of qtype and qclass
+ answername 2 bytes
+ 0001 0001 4 bytes of qtype and class
+ 0000 0000 4 bytes of TTL
+ 0000 2 bytes of content length
+ content name */
+
+ DNSName dn2((char*)&packet[0], packet.size(), 12+13+4, true, &qtype, &qclass);
+ BOOST_CHECK_EQUAL(dn2.toString(), "ds9a.nl.");
+ BOOST_CHECK(qtype == QType::NS);
+ BOOST_CHECK_EQUAL(qclass, 1);
+
+ DNSName dn3((char*)&packet[0], packet.size(), 12+13+4+2 + 4 + 4 + 2, true);
+ BOOST_CHECK_EQUAL(dn3.toString(), "ns1.powerdns.com.");
+ try {
+ DNSName dn4((char*)&packet[0], packet.size(), 12+13+4, false); // compressed, should fail
+ BOOST_CHECK(0);
+ }
+ catch(...){}
+}
+
+BOOST_AUTO_TEST_CASE(test_escaping) {
+ DNSName n;
+ string label;
+
+ for(int i = 0; i < 250; ++i) {
+ if(!((i+1)%63)) {
+ n.appendRawLabel(label);
+ label.clear();
+ }
+ label.append(1,(char)i);
+ }
+ if(!label.empty())
+ n.appendRawLabel(label);
+
+ DNSName n2(n.toString());
+ BOOST_CHECK(n==n2);
+}
+
+BOOST_AUTO_TEST_CASE(test_suffixmatch) {
+ SuffixMatchNode smn;
+ DNSName ezdns("ezdns.it.");
+ smn.add(ezdns.getRawLabels());
+
+ smn.add(DNSName("org.").getRawLabels());
+
+ DNSName wwwpowerdnscom("www.powerdns.com.");
+ DNSName wwwezdnsit("www.ezdns.it.");
+ BOOST_CHECK(smn.check(wwwezdnsit));
+ BOOST_CHECK(!smn.check(wwwpowerdnscom));
+
+ BOOST_CHECK(smn.check(DNSName("www.powerdns.org.")));
+ BOOST_CHECK(smn.check(DNSName("www.powerdns.oRG.")));
+
+ smn.add(DNSName("news.bbc.co.uk."));
+ BOOST_CHECK(smn.check(DNSName("news.bbc.co.uk.")));
+ BOOST_CHECK(smn.check(DNSName("www.news.bbc.co.uk.")));
+ BOOST_CHECK(smn.check(DNSName("www.www.www.www.www.news.bbc.co.uk.")));
+ BOOST_CHECK(!smn.check(DNSName("images.bbc.co.uk.")));
+
+ BOOST_CHECK(!smn.check(DNSName("www.news.gov.uk.")));
+
+ smn.add(DNSName(".")); // block the root
+ BOOST_CHECK(smn.check(DNSName("a.root-servers.net.")));
+
+ DNSName examplenet("example.net.");
+ DNSName net("net.");
+ smn.add(examplenet);
+ smn.add(net);
+ BOOST_CHECK(smn.check(examplenet));
+ BOOST_CHECK(smn.check(net));
+}
+
+
+BOOST_AUTO_TEST_CASE(test_concat) {
+ DNSName first("www."), second("powerdns.com.");
+ BOOST_CHECK_EQUAL((first+second).toString(), "www.powerdns.com.");
+}
+
+BOOST_AUTO_TEST_CASE(test_compare_naive) {
+ BOOST_CHECK(DNSName("abc.com.") < DNSName("zdf.com."));
+ BOOST_CHECK(DNSName("Abc.com.") < DNSName("zdf.com."));
+ BOOST_CHECK(DNSName("Abc.com.") < DNSName("Zdf.com."));
+ BOOST_CHECK(DNSName("abc.com.") < DNSName("Zdf.com."));
+}
+
+BOOST_AUTO_TEST_CASE(test_compare_empty) {
+ DNSName a, b;
+ BOOST_CHECK(!(a<b));
+ BOOST_CHECK(!a.canonCompare(b));
+}
+
+BOOST_AUTO_TEST_CASE(test_casing) {
+ DNSName a("WwW.PoWeRdNS.Com"), b("www.powerdns.com.");
+ BOOST_CHECK_EQUAL(a,b);
+ BOOST_CHECK_EQUAL(a.toString(), "WwW.PoWeRdNS.Com.");
+ DNSName c=a.makeLowerCase();
+ BOOST_CHECK_EQUAL(a,c);
+ BOOST_CHECK_EQUAL(b,c);
+ BOOST_CHECK_EQUAL(c.toString(), b.toString());
+ BOOST_CHECK_EQUAL(c.toString(), "www.powerdns.com.");
+}
+
+
+
+BOOST_AUTO_TEST_CASE(test_compare_canonical) {
+ DNSName lower("bert.com."), higher("alpha.nl.");
+ BOOST_CHECK(lower.canonCompare(higher));
+
+ BOOST_CHECK(DNSName("bert.com").canonCompare(DNSName("www.bert.com")));
+ BOOST_CHECK(DNSName("BeRt.com").canonCompare(DNSName("WWW.berT.com")));
+ BOOST_CHECK(!DNSName("www.BeRt.com").canonCompare(DNSName("WWW.berT.com")));
+
+ CanonDNSNameCompare a;
+ BOOST_CHECK(a(DNSName("."), DNSName("www.powerdns.com")));
+ BOOST_CHECK(a(DNSName("."), DNSName("www.powerdns.net")));
+ BOOST_CHECK(!a(DNSName("www.powerdns.net"), DNSName(".")));
+
+ vector<DNSName> vec;
+ for(const std::string& a : {"bert.com.", "alpha.nl.", "articles.xxx.",
+ "Aleph1.powerdns.com.", "ZOMG.powerdns.com.", "aaa.XXX.", "yyy.XXX.",
+ "test.powerdns.com."}) {
+ vec.push_back(DNSName(a));
+ }
+ sort(vec.begin(), vec.end(), CanonDNSNameCompare());
+ // for(const auto& v : vec)
+ // cerr<<'"'<<v.toString()<<'"'<<endl;
+
+ vector<DNSName> right;
+ for(const auto& a: {"bert.com.", "Aleph1.powerdns.com.",
+ "test.powerdns.com.",
+ "ZOMG.powerdns.com.",
+ "alpha.nl.",
+ "aaa.XXX.",
+ "articles.xxx.",
+ "yyy.XXX."})
+ right.push_back(DNSName(a));
+
+
+ BOOST_CHECK(vec==right);
+}
+
+
+BOOST_AUTO_TEST_CASE(test_empty_label) { // empty label
+
+ { // append
+ DNSName dn("www.");
+ BOOST_CHECK_THROW(dn.appendRawLabel(""), std::range_error);
+ }
+
+ { // prepend
+ DNSName dn("www.");
+ BOOST_CHECK_THROW(dn.prependRawLabel(""), std::range_error);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_label_length_max) { // 63 char label
+
+ string label("123456789012345678901234567890123456789012345678901234567890123");
+
+ { // append
+ DNSName dn("www.");
+ dn.appendRawLabel(label);
+ BOOST_CHECK_EQUAL(dn.toString(), "www." + label + ".");
+ }
+
+ { // prepend
+ DNSName dn("www.");
+ dn.prependRawLabel(label);
+ BOOST_CHECK_EQUAL(dn.toString(), label + ".www.");
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_label_length_too_long) { // 64 char label
+
+ string label("1234567890123456789012345678901234567890123456789012345678901234");
+
+ { // append
+ DNSName dn("www.");
+ BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error);
+ }
+
+ { // prepend
+ DNSName dn("www.");
+ BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_name_length_max) { // 255 char name
+
+ string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.");
+ string label("123");
+
+ { // append
+ DNSName dn(name);
+ dn.appendRawLabel(label);
+ BOOST_CHECK_EQUAL(dn.toString().size(), 254);
+ }
+
+ { // prepend
+ DNSName dn(name);
+ dn.prependRawLabel(label);
+ BOOST_CHECK_EQUAL(dn.toString().size(), 254);
+ }
+
+ { // concat
+ DNSName dn(name);
+
+ dn += DNSName(label + ".");
+ BOOST_CHECK_EQUAL(dn.toString().size(), 254);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_name_length_too_long) { // 256 char name
+
+ string name("123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789.123456789."
+ "123456789.123456789.123456789.123456789.123456789.");
+ string label("1234");
+
+ { // append
+ DNSName dn(name);
+ BOOST_CHECK_THROW(dn.appendRawLabel(label), std::range_error);
+ }
+
+ { // prepend
+ DNSName dn(name);
+ BOOST_CHECK_THROW(dn.prependRawLabel(label), std::range_error);
+ }
+
+ { // concat
+ DNSName dn(name);
+ BOOST_CHECK_THROW(dn += DNSName(label + "."), std::range_error);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(test_invalid_label_length) { // Invalid label length in qname
+
+ string name("\x02""ns\x07""example\x04""com\x00", 16);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_compression) { // Compression test
+
+ string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05", 21);
+
+ DNSName dn(name.c_str(), name.size(), 15, true);
+ BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
+}
+
+BOOST_AUTO_TEST_CASE(test_compression_qtype_qclass) { // Compression test with QClass and QType extraction
+
+ uint16_t qtype = 0;
+ uint16_t qclass = 0;
+
+ {
+ string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""\x01", 25);
+ DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass);
+ BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
+ BOOST_CHECK_EQUAL(qtype, 1);
+ BOOST_CHECK_EQUAL(qclass, 1);
+ }
+
+ {
+ /* same but this time we are one byte short for the qclass */
+ string name("\x03""com\x00""\x07""example\xc0""\x00""\x03""www\xc0""\x05""\x00""\x01""\x00""", 24);
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true, &qtype, &qclass), std::range_error);
+ }
+
+ {
+ /* this time with a compression pointer such as (labellen << 8) != 0, see #4718 */
+ string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00""\x01", 25);
+ name.insert(0, 256, '0');
+
+ DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass);
+ BOOST_CHECK_EQUAL(dn.toString(), "www.example.com.");
+ BOOST_CHECK_EQUAL(qtype, 1);
+ BOOST_CHECK_EQUAL(qclass, 1);
+ }
+
+ {
+ /* same but this time we are one byte short for the qclass */
+ string name("\x03""com\x00""\x07""example\xc1""\x00""\x03""www\xc1""\x05""\x00""\x01""\x00", 24);
+ name.insert(0, 256, '0');
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 271, true, &qtype, &qclass), std::range_error);
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_compression_single_bit_set) { // first 2 bits as 10 or 01, not 11
+
+ // first 2 bits: 10
+ {
+ string name("\x03""com\x00""\x07""example\x80""\x00""\x03""www\x80""\x05", 21);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error);
+ }
+
+ // first 2 bits: 01
+ {
+ string name("\x03""com\x00""\x07""example\x40""\x00""\x03""www\x40""\x05", 21);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 15, true), std::range_error);
+ }
+
+}
+
+BOOST_AUTO_TEST_CASE(test_pointer_pointer_root) { // Pointer to pointer to root
+
+ string name("\x00""\xc0""\x00""\x03""com\xc0""\x01",9);
+
+ DNSName dn(name.c_str(), name.size(), 3, true);
+ BOOST_CHECK_EQUAL(dn.toString(), "com.");
+}
+
+BOOST_AUTO_TEST_CASE(test_bad_compression_pointer) { // Pointing beyond packet boundary
+
+ std::string name("\x03""com\x00""\x07""example\xc0""\x11""xc0""\x00", 17);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 5, true), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_compression_loop) { // Compression loop (add one label)
+
+ std::string name("\x03""www\xc0""\x00", 6);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.length(), 0, true), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_compression_loop1) { // Compression loop (pointer loop)
+
+ string name("\xc0""\x00", 2);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), 0, true), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_compression_loop2) { // Compression loop (deep recursion)
+
+ int i;
+ string name("\x00\xc0\x00", 3);
+ for (i=0; i<98; ++i) {
+ name.append( 1, ((i >> 7) & 0xff) | 0xc0);
+ name.append( 1, ((i << 1) & 0xff) | 0x01);
+ }
+ BOOST_CHECK_NO_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true));
+
+ ++i;
+ name.append( 1, ((i >> 7) & 0xff) | 0xc0);
+ name.append( 1, ((i << 1) & 0xff) | 0x01);
+
+ BOOST_CHECK_THROW(DNSName dn(name.c_str(), name.size(), name.size()-2, true), std::range_error);
+}
+
+BOOST_AUTO_TEST_CASE(test_wirelength) { // Testing if we get the correct value from the wirelength function
+ DNSName name("www.powerdns.com");
+ BOOST_CHECK_EQUAL(name.wirelength(), 18);
+
+ DNSName sname("powerdns.com");
+ sname.prependRawLabel(string("ww\x00""w", 4));
+ BOOST_CHECK_EQUAL(sname.wirelength(), 19);
+
+ sname = DNSName("powerdns.com");
+ sname.prependRawLabel(string("www\x00", 4));
+ BOOST_CHECK_EQUAL(sname.wirelength(), 19);
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "dnsparser.hh"
+
+BOOST_AUTO_TEST_SUITE(test_dnsparser_hh)
+
+BOOST_AUTO_TEST_CASE(test_type_lowercase) {
+ std::string lc("type12345");
+ std::string uc("TYPE12345");
+
+ uint16_t lc_result = DNSRecordContent::TypeToNumber(lc);
+ uint16_t uc_result = DNSRecordContent::TypeToNumber(uc);
+ BOOST_CHECK_EQUAL(lc_result, 12345);
+ BOOST_CHECK_EQUAL(lc_result, uc_result);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/scoped_ptr.hpp>
+#include "dnsrecords.hh"
+
+#define CASE_L(type, inval, zoneval, lineval, broken) case_t(type, std::string(inval), std::string(zoneval), std::string(lineval, sizeof(lineval)-1), broken)
+#define CASE_S(type, zoneval, lineval, broken) CASE_L(type, zoneval, zoneval, lineval, broken)
+BOOST_AUTO_TEST_SUITE(test_dnsrecords_cc)
+
+#define REC_CHECK_EQUAL(a,b) { if (val.get<4>()) { BOOST_WARN_EQUAL(a,b); } else { BOOST_CHECK_EQUAL(a,b); } }
+#define REC_CHECK_MESSAGE(cond,msg) { if (val.get<4>()) { BOOST_WARN_MESSAGE(cond,msg); } else { BOOST_CHECK_MESSAGE(cond,msg); } }
+#define REC_FAIL_XSUCCESS(msg) { if (val.get<4>()) { BOOST_CHECK_MESSAGE(false, std::string("Test has unexpectedly passed: ") + msg); } } // fail if test succeeds
+#define REC_FAIL_XSUCCESS2(msg) { if (val.get<2>()) { BOOST_CHECK_MESSAGE(false, std::string("Test has unexpectedly passed: ") + msg); } } // fail if test succeeds (for the bad records test case)
+
+typedef enum { zone, wire } case_type_enum_t;
+
+BOOST_AUTO_TEST_CASE(test_record_types) {
+ // tuple contains <type, user value, zone representation, line value, broken>
+ typedef boost::tuple<const QType::typeenum, const std::string, const std::string, const std::string, bool> case_t;
+ typedef std::list<case_t> cases_t;
+ reportAllTypes();
+ MRRecordContent::report();
+ IPSECKEYRecordContent::report();
+ KXRecordContent::report();
+ DHCIDRecordContent::report();
+ TSIGRecordContent::report();
+ TKEYRecordContent::report();
+
+// NB!!! WHEN ADDING A TEST MAKE SURE YOU PUT IT NEXT TO IT'S KIND
+// TO MAKE SURE TEST NUMBERING DOES NOT BREAK
+
+// why yes, they are unordered by name, how nice of you to notice
+
+ cases_t cases = boost::assign::list_of
+ (CASE_S(QType::A, "127.0.0.1", "\x7F\x00\x00\x01",false))
+// local nameserver
+ (CASE_L(QType::NS, "ns.rec.test.", "ns.rec.test.", "\x02ns\xc0\x11",false))
+// non-local nameserver
+ (CASE_S(QType::NS, "ns.example.com.", "\x02ns\x07""example\x03""com\x00",false))
+// local alias
+ (CASE_L(QType::CNAME, "name.rec.test.", "name.rec.test.", "\x04name\xc0\x11",false))
+// non-local alias
+ (CASE_S(QType::CNAME, "name.example.com.", "\x04name\x07""example\x03""com\x00",false))
+// max label length (63)
+ (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.example.com.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x07""example\x03""com\x00", false))
+// local max name length (255)
+ (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012.rec.test.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x34""1234567890123456789012345678901234567890123456789012\xc0\x11", false))
+// non-local max name length (255)
+ (CASE_S(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.1234567890123456789012345678901234567890123456789012345678901.", "\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3f""123456789012345678901234567890123456789012345678901234567890123\x3d""1234567890123456789012345678901234567890123456789012345678901\x00", false))
+// local names
+ (CASE_S(QType::SOA, "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "\x02ns\xc0\x11\x0ahostmaster\x04test\x03rec\x00\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false))
+// local name without dots
+ (CASE_L(QType::SOA, "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "ns.rec.test. hostmaster.test.rec. 2013051201 3600 3600 604800 120", "\x02ns\xc0\x11\x0ahostmaster\x04test\x03rec\x00\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false))
+// non-local names
+ (CASE_S(QType::SOA, "ns.example.com. hostmaster.example.com. 2013051201 3600 3600 604800 120", "\x02ns\x07""example\x03""com\x00\x0ahostmaster\xc0\x28\x77\xfc\xb9\x41\x00\x00\x0e\x10\x00\x00\x0e\x10\x00\x09\x3a\x80\x00\x00\x00\x78",false))
+
+// BROKEN TESTS (2) (deprecated)
+// local name
+ (CASE_S(QType::MR, "newmailbox.rec.test.", "\x0anewmailbox\xc0\x11",false))
+// non-local name
+ (CASE_S(QType::MR, "newmailbox.example.com.", "\x0anewmailbox\x07""example\x03""com\x00",false))
+
+// local name
+ (CASE_L(QType::PTR, "ptr.rec.test.", "ptr.rec.test.", "\x03ptr\xc0\x11",false))
+// non-local name
+ (CASE_L(QType::PTR, "ptr.example.com.", "ptr.example.com.", "\x03ptr\x07""example\x03""com\x00",false))
+ (CASE_S(QType::HINFO, "\"i686\" \"Linux\"", "\x04i686\x05Linux",false))
+ (CASE_L(QType::HINFO, "i686 \"Linux\"", "\"i686\" \"Linux\"", "\x04i686\x05Linux",true))
+ (CASE_L(QType::HINFO, "\"i686\" Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux",false))
+ (CASE_L(QType::HINFO, "i686 Linux", "\"i686\" \"Linux\"", "\x04i686\x05Linux",true))
+// local name
+ (CASE_S(QType::MX, "10 mx.rec.test.", "\x00\x0a\02mx\xc0\x11",false))
+// non-local name
+ (CASE_S(QType::MX, "20 mx.example.com.", "\x00\x14\02mx\x07""example\x03""com\x00",false))
+// root label
+ (CASE_S(QType::MX, "20 .", "\x00\x14\x00",false))
+
+ (CASE_S(QType::TXT, "\"short text\"", "\x0ashort text",false))
+ (CASE_S(QType::TXT, "\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\"", "\xff""long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a""2222222222",false))
+ (CASE_L(QType::TXT, "\"long record test 11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111112222222222\"", "\"long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\" \"2222222222\"", "\xff""long record test 1111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111\x0a""2222222222",false))
+ (CASE_L(QType::TXT, "\"\\195\\133LAND ISLANDS\"", "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS", false))
+ (CASE_L(QType::TXT, "\"\xc3\x85LAND ISLANDS\"", "\"\\195\\133LAND ISLANDS\"", "\x0e\xc3\x85LAND ISLANDS", false))
+ (CASE_L(QType::TXT, "\"nonbreakingtxt\"", "\"nonbreakingtxt\"", "\x0enonbreakingtxt",false))
+// local name
+ (CASE_S(QType::RP, "admin.rec.test. admin-info.rec.test.", "\x05""admin\x03rec\x04test\x00\x0a""admin-info\x03rec\x04test\x00",false))
+// non-local name
+ (CASE_S(QType::RP, "admin.example.com. admin-info.example.com.", "\x05""admin\x07""example\x03""com\x00\x0a""admin-info\x07""example\x03""com\x00",false))
+// local name
+ (CASE_S(QType::AFSDB, "1 afs-server.rec.test.", "\x00\x01\x0a""afs-server\x03rec\x04test\x00",false))
+// non-local name
+ (CASE_S(QType::AFSDB, "1 afs-server.example.com.", "\x00\x01\x0a""afs-server\x07""example\x03""com\x00",false))
+// deprecated (and i don't know what i am doing wrong)
+ (CASE_S(QType::KEY, "0 3 3 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x00\x00\x03\x03\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false))
+ (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E", "32 7 19.000 S 116 2 25.000 E 0.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x96\x80",false))
+ (CASE_L(QType::LOC, "32 7 19 S 116 2 25 E 10m", "32 7 19.000 S 116 2 25.000 E 10.00m 1.00m 10000.00m 10.00m", "\x00\x12\x16\x13\x79\x1b\x7d\x28\x98\xe6\x48\x68\x00\x98\x9a\x68",false))
+ (CASE_L(QType::LOC, "42 21 54 N 71 06 18 W -24m 30m", "42 21 54.000 N 71 6 18.000 W -24.00m 30.00m 10000.00m 10.00m", "\x00\x33\x16\x13\x89\x17\x2d\xd0\x70\xbe\x15\xf0\x00\x98\x8d\x20",false))
+ (CASE_L(QType::LOC, "42 21 43.952 N 71 5 6.344 W -24m 1m 200m", "42 21 43.952 N 71 5 6.344 W -24.00m 1.00m 200.00m 10.00m", "\x00\x12\x24\x13\x89\x17\x06\x90\x70\xbf\x2d\xd8\x00\x98\x8d\x20",false))
+ (CASE_S(QType::AAAA, "fe80::250:56ff:fe9b:114", "\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14",false))
+ (CASE_S(QType::AAAA, "2a02:1b8:10:2::151", "\x2a\x02\x01\xb8\x00\x10\x00\x02\x00\x00\x00\x00\x00\x00\x01\x51",false))
+ (CASE_S(QType::AAAA, "::1", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",false))
+// local name
+ (CASE_S(QType::SRV, "10 10 5060 sip.rec.test.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x03rec\x04test\x00",false))
+// non-local name
+ (CASE_S(QType::SRV, "10 10 5060 sip.example.com.", "\x00\x0a\x00\x0a\x13\xc4\x03sip\x07""example\x03""com\x00",false))
+// root name
+ (CASE_S(QType::SRV, "10 10 5060 .", "\x00\x0a\x00\x0a\x13\xc4\x00",false))
+
+ (CASE_S(QType::NAPTR, "100 10 \"\" \"\" \"/urn:cid:.+@([^\\\\.]+\\\\.)(.*)$/\\\\2/i\" .", "\x00\x64\x00\x0a\x00\x00\x20/urn:cid:.+@([^\\.]+\\.)(.*)$/\\2/i\x00",false))
+ (CASE_S(QType::NAPTR, "100 50 \"s\" \"http+I2L+I2C+I2R\" \"\" _http._tcp.rec.test.", "\x00\x64\x00\x32\x01s\x10http+I2L+I2C+I2R\x00\x05_http\x04_tcp\x03rec\x04test\x00",false))
+ (CASE_S(QType::KX, "10 mail.rec.test.", "\x00\x0a\x04mail\x03rec\x04test\x00",false))
+
+// X.509 as per PKIX
+ (CASE_S(QType::CERT, "1 0 0 MIIB9DCCAV2gAwIBAgIJAKxUfFVXhw7HMA0GCSqGSIb3DQEBBQUAMBMxETAPBgNVBAMMCHJlYy50ZXN0MB4XDTEzMDUxMjE5NDgwOVoXDTEzMDYxMTE5NDgwOVowEzERMA8GA1UEAwwIcmVjLnRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANKCu5aN/ewOXRPfzAo27XMXhYFCThCjfInTAUIEkzs6jBFZ/eyyIa/kFoiD0tAKwfFfykYU+9XgXeLjetD7rYt3SN3bzzCznoBGbGHHM0Fecrn0LV+tC/NfBB61Yx7e0AMUxmxIeLNRQW5ca5CW8qcIiiQ4fl0BScUjc5+E9QLHAgMBAAGjUDBOMB0GA1UdDgQWBBRzcVu/2bwrgkES+FhYbxZqr7mUgjAfBgNVHSMEGDAWgBRzcVu/2bwrgkES+FhYbxZqr7mUgjAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBBQUAA4GBAFVQ8dZBOasOhsWzA/xpAV0WdsqVkxBxrkGIRlbHHBFqOBOOz2MFSzUNx4mDy0qDKI28gcWmWaVsxoQ9VFLD6YRJuUoM8MDNcZDJbKpfDumjvvfnUAK+SiM2c4Ur3xpf0wanCA60/q2bOtFiB0tfAH6RVuIgMC3qjHAIaKEld+fE", "\x00\x01\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false))
+ (CASE_L(QType::DS, "20642 8 2 04443ABE7E94C3985196BEAE5D548C727B044DDA5151E60D7CD76A9F D931D00E", "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false))
+ (CASE_L(QType::DS, "20642 8 2 04443ABE7E94C3985196BEAE5D548C727B044DDA5151E60D7CD76A9F D931D00E", "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false))
+ (CASE_S(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88",false))
+// as per RFC4025
+ (CASE_L(QType::SSHFP, "1 1 aa65e3415a50d9b3519c2b17aceb815fc253 8d88", "1 1 aa65e3415a50d9b3519c2b17aceb815fc2538d88", "\x01\x01\xaa\x65\xe3\x41\x5a\x50\xd9\xb3\x51\x9c\x2b\x17\xac\xeb\x81\x5f\xc2\x53\x8d\x88",false))
+// as per RFC4025
+ (CASE_S(QType::IPSECKEY, "255 0 0", "\xff\x00\x00",false))
+ (CASE_S(QType::IPSECKEY, "255 0 1 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\xff\x00\x01\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false))
+ (CASE_S(QType::IPSECKEY, "255 1 0 127.0.0.1", "\xff\x01\x00\x7f\x00\x00\x01", false))
+ (CASE_S(QType::IPSECKEY, "255 2 0 fe80::250:56ff:fe9b:114", "\xff\x02\x00\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14", false))
+ (CASE_S(QType::IPSECKEY, "10 1 1 127.0.0.1 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x01\x01\x7f\x00\x00\x01\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52", false))
+ (CASE_S(QType::IPSECKEY, "10 2 1 fe80::250:56ff:fe9b:114 V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x02\x01\xFE\x80\x00\x00\x00\x00\x00\x00\x02\x50\x56\xFF\xFE\x9B\x01\x14\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52", false))
+ (CASE_S(QType::IPSECKEY, "10 3 1 gw.rec.test. V19hwufL6LJARVIxzHDyGdvZ7dbQE0Kyl18yPIWj/sbCcsBbz7zO6Q2qgdzmWI3OvGNne2nxflhorhefKIMsUg==", "\x0a\x03\x01\x02gw\x03rec\x04test\x00\x57\x5f\x61\xc2\xe7\xcb\xe8\xb2\x40\x45\x52\x31\xcc\x70\xf2\x19\xdb\xd9\xed\xd6\xd0\x13\x42\xb2\x97\x5f\x32\x3c\x85\xa3\xfe\xc6\xc2\x72\xc0\x5b\xcf\xbc\xce\xe9\x0d\xaa\x81\xdc\xe6\x58\x8d\xce\xbc\x63\x67\x7b\x69\xf1\x7e\x58\x68\xae\x17\x9f\x28\x83\x2c\x52",false))
+
+ (CASE_S(QType::RRSIG, "SOA 8 3 300 20130523000000 20130509000000 54216 rec.test. ecWKD/OsdAiXpbM/sgPT82KVD/WiQnnqcxoJgiH3ixHa+LOAcYU7FG7V4BRRJxLriY1e0rB2gAs3kCel9D4bzfK6wAqG4Di/eHUgHptRlaR2ycELJ4t1pjzrnuGiIzA1wM2izRmeE+Xoy1367Qu0pOz5DLzTfQITWFsB2iUzN4Y=", "\x00\x06\x08\x03\x00\x00\x01\x2c\x51\x9d\x5c\x00\x51\x8a\xe7\x00\xd3\xc8\x03\x72\x65\x63\x04\x74\x65\x73\x74\x00\x79\xc5\x8a\x0f\xf3\xac\x74\x08\x97\xa5\xb3\x3f\xb2\x03\xd3\xf3\x62\x95\x0f\xf5\xa2\x42\x79\xea\x73\x1a\x09\x82\x21\xf7\x8b\x11\xda\xf8\xb3\x80\x71\x85\x3b\x14\x6e\xd5\xe0\x14\x51\x27\x12\xeb\x89\x8d\x5e\xd2\xb0\x76\x80\x0b\x37\x90\x27\xa5\xf4\x3e\x1b\xcd\xf2\xba\xc0\x0a\x86\xe0\x38\xbf\x78\x75\x20\x1e\x9b\x51\x95\xa4\x76\xc9\xc1\x0b\x27\x8b\x75\xa6\x3c\xeb\x9e\xe1\xa2\x23\x30\x35\xc0\xcd\xa2\xcd\x19\x9e\x13\xe5\xe8\xcb\x5d\xfa\xed\x0b\xb4\xa4\xec\xf9\x0c\xbc\xd3\x7d\x02\x13\x58\x5b\x01\xda\x25\x33\x37\x86",false))
+ (CASE_S(QType::NSEC, "a.rec.test. A NS SOA MX AAAA RRSIG NSEC DNSKEY", "\x01""a\x03rec\x04test\x00\x00\x07\x62\x01\x00\x08\x00\x03\x80",false))
+ (CASE_S(QType::DNSKEY, "257 3 5 AwEAAZVtlHc8O4TVmlGx/PGJTc7hbVjMR7RywxLuAm1dqgyHvgNRD7chYLsALOdZKW6VRvusbyhoOPilnh8XpucBDqjGD6lIemsURz7drZEqcLupVA0TPxXABZ6auJ3jumqIhSOcLj9rpSwI4xuWt0yu6LR9tL2q8+A0yEZxcAaKS+Wq0fExJ93NxgXl1/fY+JcYQvonjd31GxXXef9uf0exXyzowh5h8+IIBETU+ZiYVB5BqiwkICZL/OX57idm99ycA2/tIen66F8u2ueTvgPcecnoqHvW0MtLQKzeNmqdGNthHhV5di0SZdMZQeo/izs68uN2WzqQDZy9Ec2JwBTbxWE=", "\x01\x01\x03\x05\x03\x01\x00\x01\x95\x6d\x94\x77\x3c\x3b\x84\xd5\x9a\x51\xb1\xfc\xf1\x89\x4d\xce\xe1\x6d\x58\xcc\x47\xb4\x72\xc3\x12\xee\x02\x6d\x5d\xaa\x0c\x87\xbe\x03\x51\x0f\xb7\x21\x60\xbb\x00\x2c\xe7\x59\x29\x6e\x95\x46\xfb\xac\x6f\x28\x68\x38\xf8\xa5\x9e\x1f\x17\xa6\xe7\x01\x0e\xa8\xc6\x0f\xa9\x48\x7a\x6b\x14\x47\x3e\xdd\xad\x91\x2a\x70\xbb\xa9\x54\x0d\x13\x3f\x15\xc0\x05\x9e\x9a\xb8\x9d\xe3\xba\x6a\x88\x85\x23\x9c\x2e\x3f\x6b\xa5\x2c\x08\xe3\x1b\x96\xb7\x4c\xae\xe8\xb4\x7d\xb4\xbd\xaa\xf3\xe0\x34\xc8\x46\x71\x70\x06\x8a\x4b\xe5\xaa\xd1\xf1\x31\x27\xdd\xcd\xc6\x05\xe5\xd7\xf7\xd8\xf8\x97\x18\x42\xfa\x27\x8d\xdd\xf5\x1b\x15\xd7\x79\xff\x6e\x7f\x47\xb1\x5f\x2c\xe8\xc2\x1e\x61\xf3\xe2\x08\x04\x44\xd4\xf9\x98\x98\x54\x1e\x41\xaa\x2c\x24\x20\x26\x4b\xfc\xe5\xf9\xee\x27\x66\xf7\xdc\x9c\x03\x6f\xed\x21\xe9\xfa\xe8\x5f\x2e\xda\xe7\x93\xbe\x03\xdc\x79\xc9\xe8\xa8\x7b\xd6\xd0\xcb\x4b\x40\xac\xde\x36\x6a\x9d\x18\xdb\x61\x1e\x15\x79\x76\x2d\x12\x65\xd3\x19\x41\xea\x3f\x8b\x3b\x3a\xf2\xe3\x76\x5b\x3a\x90\x0d\x9c\xbd\x11\xcd\x89\xc0\x14\xdb\xc5\x61",false))
+
+ (CASE_S(QType::DHCID, "AAAB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x00\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false))
+ (CASE_S(QType::DHCID, "AAEB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x01\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false))
+ (CASE_S(QType::DHCID, "AAIB92JtyyO73zqENgu9LVua+0PZoeCcKapTw4asbYmx5F4=", "\x00\x02\x01\xf7\x62\x6d\xcb\x23\xbb\xdf\x3a\x84\x36\x0b\xbd\x2d\x5b\x9a\xfb\x43\xd9\xa1\xe0\x9c\x29\xaa\x53\xc3\x86\xac\x6d\x89\xb1\xe4\x5e",false))
+
+ (CASE_S(QType::NSEC3, "1 1 1 f00b RPF1JGFCCNFA7STPTIJ9FPFNM40A4FLL NS SOA RRSIG DNSKEY NSEC3PARAM", "\x01\x01\x00\x01\x02\xf0\x0b\x14\xde\x5e\x19\xc1\xec\x65\xde\xa3\xf3\xb9\xec\xa6\x97\xe5\xf7\xb1\x00\xa2\x3e\xb5\x00\x07\x22\x00\x00\x00\x00\x02\x90",false))
+ (CASE_S(QType::NSEC3PARAM, "1 0 1 f00b", "\x01\x00\x00\x01\x02\xf0\x0b",false))
+
+ (CASE_S(QType::TLSA, "0 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x00\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false))
+ (CASE_S(QType::TLSA, "0 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x00\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false))
+ (CASE_S(QType::TLSA, "1 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x01\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false))
+ (CASE_S(QType::TLSA, "1 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x01\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false))
+ (CASE_S(QType::TLSA, "1 0 1 6acea2f68b03d9efe97a967e137aca6ac3a89490d532d87806d9e9c257668453", "\x01\x00\x01\x6a\xce\xa2\xf6\x8b\x03\xd9\xef\xe9\x7a\x96\x7e\x13\x7a\xca\x6a\xc3\xa8\x94\x90\xd5\x32\xd8\x78\x06\xd9\xe9\xc2\x57\x66\x84\x53",false))
+ (CASE_S(QType::TLSA, "1 0 2 e6dce237992803488d11d828b7728deddd4577de73d7d078338c8a45880beddff98e076a28bf8e3068da8e73667b802a721c95d7323b038c60200a430cb6fbd4", "\x01\x00\x02\xe6\xdc\xe2\x37\x99\x28\x03\x48\x8d\x11\xd8\x28\xb7\x72\x8d\xed\xdd\x45\x77\xde\x73\xd7\xd0\x78\x33\x8c\x8a\x45\x88\x0b\xed\xdf\xf9\x8e\x07\x6a\x28\xbf\x8e\x30\x68\xda\x8e\x73\x66\x7b\x80\x2a\x72\x1c\x95\xd7\x32\x3b\x03\x8c\x60\x20\x0a\x43\x0c\xb6\xfb\xd4",false))
+ (CASE_S(QType::TLSA, "2 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x02\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false))
+ (CASE_S(QType::TLSA, "2 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x02\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false))
+
+ (CASE_S(QType::TLSA, "3 0 0 308201f43082015da003020102020900ac547c5557870ec7300d06092a864886f70d010105050030133111300f06035504030c087265632e74657374301e170d3133303531323139343830395a170d3133303631313139343830395a30133111300f06035504030c087265632e7465737430819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001a350304e301d0603551d0e0416041473715bbfd9bc2b824112f858586f166aafb99482301f0603551d2304183016801473715bbfd9bc2b824112f858586f166aafb99482300c0603551d13040530030101ff300d06092a864886f70d0101050500038181005550f1d64139ab0e86c5b303fc69015d1676ca95931071ae41884656c71c116a38138ecf63054b350dc78983cb4a83288dbc81c5a659a56cc6843d5452c3e98449b94a0cf0c0cd7190c96caa5f0ee9a3bef7e75002be4a233673852bdf1a5fd306a7080eb4fead9b3ad162074b5f007e9156e220302dea8c700868a12577e7c4", "\x03\x00\x00\x30\x82\x01\xf4\x30\x82\x01\x5d\xa0\x03\x02\x01\x02\x02\x09\x00\xac\x54\x7c\x55\x57\x87\x0e\xc7\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x1e\x17\x0d\x31\x33\x30\x35\x31\x32\x31\x39\x34\x38\x30\x39\x5a\x17\x0d\x31\x33\x30\x36\x31\x31\x31\x39\x34\x38\x30\x39\x5a\x30\x13\x31\x11\x30\x0f\x06\x03\x55\x04\x03\x0c\x08\x72\x65\x63\x2e\x74\x65\x73\x74\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01\xa3\x50\x30\x4e\x30\x1d\x06\x03\x55\x1d\x0e\x04\x16\x04\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x1f\x06\x03\x55\x1d\x23\x04\x18\x30\x16\x80\x14\x73\x71\x5b\xbf\xd9\xbc\x2b\x82\x41\x12\xf8\x58\x58\x6f\x16\x6a\xaf\xb9\x94\x82\x30\x0c\x06\x03\x55\x1d\x13\x04\x05\x30\x03\x01\x01\xff\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x05\x05\x00\x03\x81\x81\x00\x55\x50\xf1\xd6\x41\x39\xab\x0e\x86\xc5\xb3\x03\xfc\x69\x01\x5d\x16\x76\xca\x95\x93\x10\x71\xae\x41\x88\x46\x56\xc7\x1c\x11\x6a\x38\x13\x8e\xcf\x63\x05\x4b\x35\x0d\xc7\x89\x83\xcb\x4a\x83\x28\x8d\xbc\x81\xc5\xa6\x59\xa5\x6c\xc6\x84\x3d\x54\x52\xc3\xe9\x84\x49\xb9\x4a\x0c\xf0\xc0\xcd\x71\x90\xc9\x6c\xaa\x5f\x0e\xe9\xa3\xbe\xf7\xe7\x50\x02\xbe\x4a\x23\x36\x73\x85\x2b\xdf\x1a\x5f\xd3\x06\xa7\x08\x0e\xb4\xfe\xad\x9b\x3a\xd1\x62\x07\x4b\x5f\x00\x7e\x91\x56\xe2\x20\x30\x2d\xea\x8c\x70\x08\x68\xa1\x25\x77\xe7\xc4",false))
+ (CASE_S(QType::TLSA, "3 1 0 30819f300d06092a864886f70d010101050003818d0030818902818100d282bb968dfdec0e5d13dfcc0a36ed73178581424e10a37c89d3014204933b3a8c1159fdecb221afe4168883d2d00ac1f15fca4614fbd5e05de2e37ad0fbad8b7748dddbcf30b39e80466c61c733415e72b9f42d5fad0bf35f041eb5631eded00314c66c4878b351416e5c6b9096f2a7088a24387e5d0149c523739f84f502c70203010001", "\x03\x01\x00\x30\x81\x9f\x30\x0d\x06\x09\x2a\x86\x48\x86\xf7\x0d\x01\x01\x01\x05\x00\x03\x81\x8d\x00\x30\x81\x89\x02\x81\x81\x00\xd2\x82\xbb\x96\x8d\xfd\xec\x0e\x5d\x13\xdf\xcc\x0a\x36\xed\x73\x17\x85\x81\x42\x4e\x10\xa3\x7c\x89\xd3\x01\x42\x04\x93\x3b\x3a\x8c\x11\x59\xfd\xec\xb2\x21\xaf\xe4\x16\x88\x83\xd2\xd0\x0a\xc1\xf1\x5f\xca\x46\x14\xfb\xd5\xe0\x5d\xe2\xe3\x7a\xd0\xfb\xad\x8b\x77\x48\xdd\xdb\xcf\x30\xb3\x9e\x80\x46\x6c\x61\xc7\x33\x41\x5e\x72\xb9\xf4\x2d\x5f\xad\x0b\xf3\x5f\x04\x1e\xb5\x63\x1e\xde\xd0\x03\x14\xc6\x6c\x48\x78\xb3\x51\x41\x6e\x5c\x6b\x90\x96\xf2\xa7\x08\x8a\x24\x38\x7e\x5d\x01\x49\xc5\x23\x73\x9f\x84\xf5\x02\xc7\x02\x03\x01\x00\x01",false))
+
+ (CASE_S(QType::OPENPGPKEY, "mQINBFUIXh0BEADNPlL6NpWEaR2KJx6p19scIVpsBIo7UqzCIzeFbRJaGDhn/HlQgcwAalcVNmWUX0ZQsrdn9CEfLWuFu9ON2o1TslYiwn+oSAlH2raFm2eyJTp/iM7IUUCte5jmf3d+L9rjVI7JjmMnbVo6SVY2KDDD72dULcg7IqYcCAN4CT+tPZP5y4cYf+DxRlpxhxvqqiGyAi6lAcJ24/8fJ4hsG0lS1vU12LWeWTHa5aRMM+x9kmv3GYdXG+FxFqZw52kZEnAscpC2ymbX+1YFCr8sjGYGde/D+5cLvuu4PGNZ4fkSeS+0yXve/s6u1mX6RkkF6SOGWuJfBJOGdWzYwber9kqgqpHTjpr8HOybzVroBijtTlB/tommIUd4BTk9Jv4fv2gA4UkC13UM9KBF1NnzUnKC+Js49O3mj0HZDoCrkWMnZyDsEmhMyQPU6YRFHWmB6OTKeD/Znk+b1uz+HIBgrbNuiG/A0c00Vnj7lR4p94oOuypI00XusLsJwPsjI4EgFGKdoRtM0spJhi+3gf88Vq0NENBaFVHLBGWVFaVrffurGcDZYUAdnvm8jSPCgBPfFxpZutexNkLjyaaXjDtga5/n5gSd/3RpWCvp9u3W5jcTNDZF4TORnOXUWHcot/+XmyH8/+cn8ydt0prOLGQ+FtdI+AWyMCXHen6aaZ1jeSLZqwARAQABtFpwZG5zIHJlZ3Jlc3Npb24gdGVzdGluZyBrZXkgKG9ubHkgZm9yIHRlc3RpbmcgdGhlIG9wZW5wZ3BrZXkgcnIpIDxyZWdyZXNzaW9uQHBvd2VyZG5zLm9yZz6JAjcEEwEIACEFAlUIXh0CGwMFCwkIBwIGFQgJCgsCBBYCAwECHgECF4AACgkQPr/KqoyK2Z7A6Q//YOBu8nwt+fguSo/vyCln0PqnTiBm4RvE2gPDUnsKuoXoP5F56XHBXKl9kEgmycht/nc7c7NRHzUhacM2RQau6CgNZE8KLaqDTKlEuc/ANtrnGGYG8gMId4TlzU5taLEA8yrHIHnwnMuDDpx1a0ETkbYCrj7CynqdhXCABqFjgRL7Qb37UnLPE7YdFt7fRGwZVLnb3GVZLKHurZ0TANvLdRVDST3f0lCcYMppPbHAvi2MIU71FPGkms++tj4gTltq0VRvrMNm1e5v4+hHZ++QN4sm4+DJGlo7l850gnMXc7c7GkRGtg8gV0h5k5jX5icdgxyvENTuBQ+QprkYTRh9uYzpoTQ+NYRZlgaJxxaDIv1K/kb3oPtnAEKJBC02IZbB0EiS3R5pxYXhUNoWV7ez2A4hX1L+tfvlgCAbbQ/cBLvqXgpgsf9x4ygSi52vQBy3twZyrtLsogxacxADfPcyleHtju/+lSku+Z6+W6OojA0kY2HlaMyQATJLIXd+6NE/tYy70RsU9Oq0OyVTjxh21SPLsExeSwSfciVSLn7IuKGIOV82MEHFhpo1Uhv+G52J8T1fI730sS4Tl5DekLaCz1pg/FmI/EQeAsYqm98uDAaFQcs6gDse8VYGmp2XYsoCW72as8ElKmMIbQ/xD7qxDORLmjCtVoyKH19+s6Pp61a5Ag0EVQheHQEQAMN6pcLJUhw9bfO5kqhLv4prt0AqVBUok6U8tIaEc9vDaasBcFHXgPsoOG97DXB6BdvsHuK/5uMVH5PNe58MLp08iCoIt0C0CbN3+D9Qbeg37AyKyFanB/CXq1tPKVCJc6BMNkO/BswnUsTTmlcd4GovpaJUOOZzblGUQBbhzRohhmOGfdsScGeeYME/yNFqzt1ZArV4va1hOLOUpNFv9TOy0ZVi/yDi+sYA9fCSZU9alWI/cbBct5I+3bh1l26umlZsYQm8uqnSgiQWpRm6UJO6xQbmUN9GzCYyKCmpzZRduqqjjtiF10W1yzioTfTtq2cvU6PdINYY8w2UuOjRd9gChtvGuduOIwqlRTYSaXX1dDoFe1vWqZzRm+pIDumO9eX5jMmzFXLDG2pD2l97zoSjVFf/pYoBasgX43e3V/aEk9PUgXbYFm2QxFMcIYSO9GEDMoE+QxoMXf1UjLxMCK5gD5iHL3Ff2zyXLzlTZE+fHPMLcAkzcp2u6pJ9xpAGekqqeqnISXZ2o8yXsqv8NVvl1zaSiSqU+kak9mIg/2+WC9W1qO2PeSLW2tiis980QnmyDOBg2oL01ITh/u+GTodEGwfRYJoNAJgUjcUMpWl0LuoG8lG6wukhA4QYFWpf2QPVgTR63VbpFgwCnUcSEPqHB0BRCsDHsd0k+/YSuPolABEBAAGJAh8EGAEIAAkFAlUIXh0CGwwACgkQPr/KqoyK2Z6zPA/+PkJTzP8kQw4GW0x2ZxXfOmkRVYpSEoHehf6y9YFN00+T8pb71RGItvuX5v6oPKPClOnIVg2WVHOq6Q3HsXEzl7oIbOtPE98WXHiVXud/djc54uHz9WjSPfy/idP7SMslo29BHR/K9nQkiGtayD57wdxgbLXObE3fA0gl4AsWl1EZzNcWVL4SIrvnBGpYIUGBcsTIiP3p09bu4Qf6HjJRXZlBuizigIgeO39l/G6tb6GA1cnbq4y6aCtQeXHLrnvak1jRqznlJWUqS1mQgOPF1MuOduHAvQbfMBQXAEfgOTzuH9PuKoGm7MePwTrU5GsOpNgS4LbvIRODJxYD+vIwA5BniijgfN9aj9KQVMURrd4Np7i0EVmj8P9FtNgYsEaDt7laGpNB9+9Y9heb6kNEulF7KI7y8CKikgvFGHHCyX2BCCbQBqi6wbEGq16qkTJmesYu9ig4v4xD/Q/cLJFziJLjEcWsL7hq7q2o6e7NL6hf5aTH0/bdeMXMqRzDCAFQ5Z+x0QUCgVonxzj+CuTD/LeOs/QHu/9emvm9EOMYY/X9vidLf58PT/AMqMiYbNWty6qY6k2LMw74Yd4+hO+Tjrk8MrqbCUs9h6ih9IOCo68JTWQQbgWSk2TAyd3U4OqTyBnHWr0HhHDRTOxyDbZUtXbk/r4Q4gTcAt+qjpswPyk=", "\x99\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xcd\x3e\x52\xfa\x36\x95\x84\x69\x1d\x8a\x27\x1e\xa9\xd7\xdb\x1c\x21\x5a\x6c\x04\x8a\x3b\x52\xac\xc2\x23\x37\x85\x6d\x12\x5a\x18\x38\x67\xfc\x79\x50\x81\xcc\x00\x6a\x57\x15\x36\x65\x94\x5f\x46\x50\xb2\xb7\x67\xf4\x21\x1f\x2d\x6b\x85\xbb\xd3\x8d\xda\x8d\x53\xb2\x56\x22\xc2\x7f\xa8\x48\x09\x47\xda\xb6\x85\x9b\x67\xb2\x25\x3a\x7f\x88\xce\xc8\x51\x40\xad\x7b\x98\xe6\x7f\x77\x7e\x2f\xda\xe3\x54\x8e\xc9\x8e\x63\x27\x6d\x5a\x3a\x49\x56\x36\x28\x30\xc3\xef\x67\x54\x2d\xc8\x3b\x22\xa6\x1c\x08\x03\x78\x09\x3f\xad\x3d\x93\xf9\xcb\x87\x18\x7f\xe0\xf1\x46\x5a\x71\x87\x1b\xea\xaa\x21\xb2\x02\x2e\xa5\x01\xc2\x76\xe3\xff\x1f\x27\x88\x6c\x1b\x49\x52\xd6\xf5\x35\xd8\xb5\x9e\x59\x31\xda\xe5\xa4\x4c\x33\xec\x7d\x92\x6b\xf7\x19\x87\x57\x1b\xe1\x71\x16\xa6\x70\xe7\x69\x19\x12\x70\x2c\x72\x90\xb6\xca\x66\xd7\xfb\x56\x05\x0a\xbf\x2c\x8c\x66\x06\x75\xef\xc3\xfb\x97\x0b\xbe\xeb\xb8\x3c\x63\x59\xe1\xf9\x12\x79\x2f\xb4\xc9\x7b\xde\xfe\xce\xae\xd6\x65\xfa\x46\x49\x05\xe9\x23\x86\x5a\xe2\x5f\x04\x93\x86\x75\x6c\xd8\xc1\xb7\xab\xf6\x4a\xa0\xaa\x91\xd3\x8e\x9a\xfc\x1c\xec\x9b\xcd\x5a\xe8\x06\x28\xed\x4e\x50\x7f\xb6\x89\xa6\x21\x47\x78\x05\x39\x3d\x26\xfe\x1f\xbf\x68\x00\xe1\x49\x02\xd7\x75\x0c\xf4\xa0\x45\xd4\xd9\xf3\x52\x72\x82\xf8\x9b\x38\xf4\xed\xe6\x8f\x41\xd9\x0e\x80\xab\x91\x63\x27\x67\x20\xec\x12\x68\x4c\xc9\x03\xd4\xe9\x84\x45\x1d\x69\x81\xe8\xe4\xca\x78\x3f\xd9\x9e\x4f\x9b\xd6\xec\xfe\x1c\x80\x60\xad\xb3\x6e\x88\x6f\xc0\xd1\xcd\x34\x56\x78\xfb\x95\x1e\x29\xf7\x8a\x0e\xbb\x2a\x48\xd3\x45\xee\xb0\xbb\x09\xc0\xfb\x23\x23\x81\x20\x14\x62\x9d\xa1\x1b\x4c\xd2\xca\x49\x86\x2f\xb7\x81\xff\x3c\x56\xad\x0d\x10\xd0\x5a\x15\x51\xcb\x04\x65\x95\x15\xa5\x6b\x7d\xfb\xab\x19\xc0\xd9\x61\x40\x1d\x9e\xf9\xbc\x8d\x23\xc2\x80\x13\xdf\x17\x1a\x59\xba\xd7\xb1\x36\x42\xe3\xc9\xa6\x97\x8c\x3b\x60\x6b\x9f\xe7\xe6\x04\x9d\xff\x74\x69\x58\x2b\xe9\xf6\xed\xd6\xe6\x37\x13\x34\x36\x45\xe1\x33\x91\x9c\xe5\xd4\x58\x77\x28\xb7\xff\x97\x9b\x21\xfc\xff\xe7\x27\xf3\x27\x6d\xd2\x9a\xce\x2c\x64\x3e\x16\xd7\x48\xf8\x05\xb2\x30\x25\xc7\x7a\x7e\x9a\x69\x9d\x63\x79\x22\xd9\xab\x00\x11\x01\x00\x01\xb4\x5a\x70\x64\x6e\x73\x20\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x6b\x65\x79\x20\x28\x6f\x6e\x6c\x79\x20\x66\x6f\x72\x20\x74\x65\x73\x74\x69\x6e\x67\x20\x74\x68\x65\x20\x6f\x70\x65\x6e\x70\x67\x70\x6b\x65\x79\x20\x72\x72\x29\x20\x3c\x72\x65\x67\x72\x65\x73\x73\x69\x6f\x6e\x40\x70\x6f\x77\x65\x72\x64\x6e\x73\x2e\x6f\x72\x67\x3e\x89\x02\x37\x04\x13\x01\x08\x00\x21\x05\x02\x55\x08\x5e\x1d\x02\x1b\x03\x05\x0b\x09\x08\x07\x02\x06\x15\x08\x09\x0a\x0b\x02\x04\x16\x02\x03\x01\x02\x1e\x01\x02\x17\x80\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xc0\xe9\x0f\xff\x60\xe0\x6e\xf2\x7c\x2d\xf9\xf8\x2e\x4a\x8f\xef\xc8\x29\x67\xd0\xfa\xa7\x4e\x20\x66\xe1\x1b\xc4\xda\x03\xc3\x52\x7b\x0a\xba\x85\xe8\x3f\x91\x79\xe9\x71\xc1\x5c\xa9\x7d\x90\x48\x26\xc9\xc8\x6d\xfe\x77\x3b\x73\xb3\x51\x1f\x35\x21\x69\xc3\x36\x45\x06\xae\xe8\x28\x0d\x64\x4f\x0a\x2d\xaa\x83\x4c\xa9\x44\xb9\xcf\xc0\x36\xda\xe7\x18\x66\x06\xf2\x03\x08\x77\x84\xe5\xcd\x4e\x6d\x68\xb1\x00\xf3\x2a\xc7\x20\x79\xf0\x9c\xcb\x83\x0e\x9c\x75\x6b\x41\x13\x91\xb6\x02\xae\x3e\xc2\xca\x7a\x9d\x85\x70\x80\x06\xa1\x63\x81\x12\xfb\x41\xbd\xfb\x52\x72\xcf\x13\xb6\x1d\x16\xde\xdf\x44\x6c\x19\x54\xb9\xdb\xdc\x65\x59\x2c\xa1\xee\xad\x9d\x13\x00\xdb\xcb\x75\x15\x43\x49\x3d\xdf\xd2\x50\x9c\x60\xca\x69\x3d\xb1\xc0\xbe\x2d\x8c\x21\x4e\xf5\x14\xf1\xa4\x9a\xcf\xbe\xb6\x3e\x20\x4e\x5b\x6a\xd1\x54\x6f\xac\xc3\x66\xd5\xee\x6f\xe3\xe8\x47\x67\xef\x90\x37\x8b\x26\xe3\xe0\xc9\x1a\x5a\x3b\x97\xce\x74\x82\x73\x17\x73\xb7\x3b\x1a\x44\x46\xb6\x0f\x20\x57\x48\x79\x93\x98\xd7\xe6\x27\x1d\x83\x1c\xaf\x10\xd4\xee\x05\x0f\x90\xa6\xb9\x18\x4d\x18\x7d\xb9\x8c\xe9\xa1\x34\x3e\x35\x84\x59\x96\x06\x89\xc7\x16\x83\x22\xfd\x4a\xfe\x46\xf7\xa0\xfb\x67\x00\x42\x89\x04\x2d\x36\x21\x96\xc1\xd0\x48\x92\xdd\x1e\x69\xc5\x85\xe1\x50\xda\x16\x57\xb7\xb3\xd8\x0e\x21\x5f\x52\xfe\xb5\xfb\xe5\x80\x20\x1b\x6d\x0f\xdc\x04\xbb\xea\x5e\x0a\x60\xb1\xff\x71\xe3\x28\x12\x8b\x9d\xaf\x40\x1c\xb7\xb7\x06\x72\xae\xd2\xec\xa2\x0c\x5a\x73\x10\x03\x7c\xf7\x32\x95\xe1\xed\x8e\xef\xfe\x95\x29\x2e\xf9\x9e\xbe\x5b\xa3\xa8\x8c\x0d\x24\x63\x61\xe5\x68\xcc\x90\x01\x32\x4b\x21\x77\x7e\xe8\xd1\x3f\xb5\x8c\xbb\xd1\x1b\x14\xf4\xea\xb4\x3b\x25\x53\x8f\x18\x76\xd5\x23\xcb\xb0\x4c\x5e\x4b\x04\x9f\x72\x25\x52\x2e\x7e\xc8\xb8\xa1\x88\x39\x5f\x36\x30\x41\xc5\x86\x9a\x35\x52\x1b\xfe\x1b\x9d\x89\xf1\x3d\x5f\x23\xbd\xf4\xb1\x2e\x13\x97\x90\xde\x90\xb6\x82\xcf\x5a\x60\xfc\x59\x88\xfc\x44\x1e\x02\xc6\x2a\x9b\xdf\x2e\x0c\x06\x85\x41\xcb\x3a\x80\x3b\x1e\xf1\x56\x06\x9a\x9d\x97\x62\xca\x02\x5b\xbd\x9a\xb3\xc1\x25\x2a\x63\x08\x6d\x0f\xf1\x0f\xba\xb1\x0c\xe4\x4b\x9a\x30\xad\x56\x8c\x8a\x1f\x5f\x7e\xb3\xa3\xe9\xeb\x56\xb9\x02\x0d\x04\x55\x08\x5e\x1d\x01\x10\x00\xc3\x7a\xa5\xc2\xc9\x52\x1c\x3d\x6d\xf3\xb9\x92\xa8\x4b\xbf\x8a\x6b\xb7\x40\x2a\x54\x15\x28\x93\xa5\x3c\xb4\x86\x84\x73\xdb\xc3\x69\xab\x01\x70\x51\xd7\x80\xfb\x28\x38\x6f\x7b\x0d\x70\x7a\x05\xdb\xec\x1e\xe2\xbf\xe6\xe3\x15\x1f\x93\xcd\x7b\x9f\x0c\x2e\x9d\x3c\x88\x2a\x08\xb7\x40\xb4\x09\xb3\x77\xf8\x3f\x50\x6d\xe8\x37\xec\x0c\x8a\xc8\x56\xa7\x07\xf0\x97\xab\x5b\x4f\x29\x50\x89\x73\xa0\x4c\x36\x43\xbf\x06\xcc\x27\x52\xc4\xd3\x9a\x57\x1d\xe0\x6a\x2f\xa5\xa2\x54\x38\xe6\x73\x6e\x51\x94\x40\x16\xe1\xcd\x1a\x21\x86\x63\x86\x7d\xdb\x12\x70\x67\x9e\x60\xc1\x3f\xc8\xd1\x6a\xce\xdd\x59\x02\xb5\x78\xbd\xad\x61\x38\xb3\x94\xa4\xd1\x6f\xf5\x33\xb2\xd1\x95\x62\xff\x20\xe2\xfa\xc6\x00\xf5\xf0\x92\x65\x4f\x5a\x95\x62\x3f\x71\xb0\x5c\xb7\x92\x3e\xdd\xb8\x75\x97\x6e\xae\x9a\x56\x6c\x61\x09\xbc\xba\xa9\xd2\x82\x24\x16\xa5\x19\xba\x50\x93\xba\xc5\x06\xe6\x50\xdf\x46\xcc\x26\x32\x28\x29\xa9\xcd\x94\x5d\xba\xaa\xa3\x8e\xd8\x85\xd7\x45\xb5\xcb\x38\xa8\x4d\xf4\xed\xab\x67\x2f\x53\xa3\xdd\x20\xd6\x18\xf3\x0d\x94\xb8\xe8\xd1\x77\xd8\x02\x86\xdb\xc6\xb9\xdb\x8e\x23\x0a\xa5\x45\x36\x12\x69\x75\xf5\x74\x3a\x05\x7b\x5b\xd6\xa9\x9c\xd1\x9b\xea\x48\x0e\xe9\x8e\xf5\xe5\xf9\x8c\xc9\xb3\x15\x72\xc3\x1b\x6a\x43\xda\x5f\x7b\xce\x84\xa3\x54\x57\xff\xa5\x8a\x01\x6a\xc8\x17\xe3\x77\xb7\x57\xf6\x84\x93\xd3\xd4\x81\x76\xd8\x16\x6d\x90\xc4\x53\x1c\x21\x84\x8e\xf4\x61\x03\x32\x81\x3e\x43\x1a\x0c\x5d\xfd\x54\x8c\xbc\x4c\x08\xae\x60\x0f\x98\x87\x2f\x71\x5f\xdb\x3c\x97\x2f\x39\x53\x64\x4f\x9f\x1c\xf3\x0b\x70\x09\x33\x72\x9d\xae\xea\x92\x7d\xc6\x90\x06\x7a\x4a\xaa\x7a\xa9\xc8\x49\x76\x76\xa3\xcc\x97\xb2\xab\xfc\x35\x5b\xe5\xd7\x36\x92\x89\x2a\x94\xfa\x46\xa4\xf6\x62\x20\xff\x6f\x96\x0b\xd5\xb5\xa8\xed\x8f\x79\x22\xd6\xda\xd8\xa2\xb3\xdf\x34\x42\x79\xb2\x0c\xe0\x60\xda\x82\xf4\xd4\x84\xe1\xfe\xef\x86\x4e\x87\x44\x1b\x07\xd1\x60\x9a\x0d\x00\x98\x14\x8d\xc5\x0c\xa5\x69\x74\x2e\xea\x06\xf2\x51\xba\xc2\xe9\x21\x03\x84\x18\x15\x6a\x5f\xd9\x03\xd5\x81\x34\x7a\xdd\x56\xe9\x16\x0c\x02\x9d\x47\x12\x10\xfa\x87\x07\x40\x51\x0a\xc0\xc7\xb1\xdd\x24\xfb\xf6\x12\xb8\xfa\x25\x00\x11\x01\x00\x01\x89\x02\x1f\x04\x18\x01\x08\x00\x09\x05\x02\x55\x08\x5e\x1d\x02\x1b\x0c\x00\x0a\x09\x10\x3e\xbf\xca\xaa\x8c\x8a\xd9\x9e\xb3\x3c\x0f\xfe\x3e\x42\x53\xcc\xff\x24\x43\x0e\x06\x5b\x4c\x76\x67\x15\xdf\x3a\x69\x11\x55\x8a\x52\x12\x81\xde\x85\xfe\xb2\xf5\x81\x4d\xd3\x4f\x93\xf2\x96\xfb\xd5\x11\x88\xb6\xfb\x97\xe6\xfe\xa8\x3c\xa3\xc2\x94\xe9\xc8\x56\x0d\x96\x54\x73\xaa\xe9\x0d\xc7\xb1\x71\x33\x97\xba\x08\x6c\xeb\x4f\x13\xdf\x16\x5c\x78\x95\x5e\xe7\x7f\x76\x37\x39\xe2\xe1\xf3\xf5\x68\xd2\x3d\xfc\xbf\x89\xd3\xfb\x48\xcb\x25\xa3\x6f\x41\x1d\x1f\xca\xf6\x74\x24\x88\x6b\x5a\xc8\x3e\x7b\xc1\xdc\x60\x6c\xb5\xce\x6c\x4d\xdf\x03\x48\x25\xe0\x0b\x16\x97\x51\x19\xcc\xd7\x16\x54\xbe\x12\x22\xbb\xe7\x04\x6a\x58\x21\x41\x81\x72\xc4\xc8\x88\xfd\xe9\xd3\xd6\xee\xe1\x07\xfa\x1e\x32\x51\x5d\x99\x41\xba\x2c\xe2\x80\x88\x1e\x3b\x7f\x65\xfc\x6e\xad\x6f\xa1\x80\xd5\xc9\xdb\xab\x8c\xba\x68\x2b\x50\x79\x71\xcb\xae\x7b\xda\x93\x58\xd1\xab\x39\xe5\x25\x65\x2a\x4b\x59\x90\x80\xe3\xc5\xd4\xcb\x8e\x76\xe1\xc0\xbd\x06\xdf\x30\x14\x17\x00\x47\xe0\x39\x3c\xee\x1f\xd3\xee\x2a\x81\xa6\xec\xc7\x8f\xc1\x3a\xd4\xe4\x6b\x0e\xa4\xd8\x12\xe0\xb6\xef\x21\x13\x83\x27\x16\x03\xfa\xf2\x30\x03\x90\x67\x8a\x28\xe0\x7c\xdf\x5a\x8f\xd2\x90\x54\xc5\x11\xad\xde\x0d\xa7\xb8\xb4\x11\x59\xa3\xf0\xff\x45\xb4\xd8\x18\xb0\x46\x83\xb7\xb9\x5a\x1a\x93\x41\xf7\xef\x58\xf6\x17\x9b\xea\x43\x44\xba\x51\x7b\x28\x8e\xf2\xf0\x22\xa2\x92\x0b\xc5\x18\x71\xc2\xc9\x7d\x81\x08\x26\xd0\x06\xa8\xba\xc1\xb1\x06\xab\x5e\xaa\x91\x32\x66\x7a\xc6\x2e\xf6\x28\x38\xbf\x8c\x43\xfd\x0f\xdc\x2c\x91\x73\x88\x92\xe3\x11\xc5\xac\x2f\xb8\x6a\xee\xad\xa8\xe9\xee\xcd\x2f\xa8\x5f\xe5\xa4\xc7\xd3\xf6\xdd\x78\xc5\xcc\xa9\x1c\xc3\x08\x01\x50\xe5\x9f\xb1\xd1\x05\x02\x81\x5a\x27\xc7\x38\xfe\x0a\xe4\xc3\xfc\xb7\x8e\xb3\xf4\x07\xbb\xff\x5e\x9a\xf9\xbd\x10\xe3\x18\x63\xf5\xfd\xbe\x27\x4b\x7f\x9f\x0f\x4f\xf0\x0c\xa8\xc8\x98\x6c\xd5\xad\xcb\xaa\x98\xea\x4d\x8b\x33\x0e\xf8\x61\xde\x3e\x84\xef\x93\x8e\xb9\x3c\x32\xba\x9b\x09\x4b\x3d\x87\xa8\xa1\xf4\x83\x82\xa3\xaf\x09\x4d\x64\x10\x6e\x05\x92\x93\x64\xc0\xc9\xdd\xd4\xe0\xea\x93\xc8\x19\xc7\x5a\xbd\x07\x84\x70\xd1\x4c\xec\x72\x0d\xb6\x54\xb5\x76\xe4\xfe\xbe\x10\xe2\x04\xdc\x02\xdf\xaa\x8e\x9b\x30\x3f\x29",false))
+
+ (CASE_S(QType::SPF, "\"v=spf1 a:mail.rec.test ~all\"", "\x1bv=spf1 a:mail.rec.test ~all",false))
+ (CASE_S(QType::EUI48, "00-11-22-33-44-55", "\x00\x11\x22\x33\x44\x55",false))
+ (CASE_S(QType::EUI64, "00-11-22-33-44-55-66-77", "\x00\x11\x22\x33\x44\x55\x66\x77",false))
+ (CASE_S(QType::TSIG, "HMAC-MD5.SIG-ALG.REG.INT. 1368386956 60 16 TkbpD66/Mtgo8GUEFZIwhg== 12345 0 0", "\x08HMAC-MD5\x07SIG-ALG\x03REG\x03INT\x00\x00\x00\x51\x8f\xed\x8c\x00\x3c\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86\x30\x39\x00\x00\x00\x00",false))
+ (CASE_S(QType::TSIG, "HMAC-MD5.SIG-ALG.REG.INT. 1368386956 60 16 TkbpD66/Mtgo8GUEFZIwhg== 12345 18 16 TkbpD66/Mtgo8GUEFZIwhg==", "\x08HMAC-MD5\x07SIG-ALG\x03REG\x03INT\x00\x00\x00\x51\x8f\xed\x8c\x00\x3c\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86\x30\x39\x00\x12\x00\x10\x4e\x46\xe9\x0f\xae\xbf\x32\xd8\x28\xf0\x65\x04\x15\x92\x30\x86",false))
+ (CASE_S(QType::TKEY, "gss-tsig. 12345 12345 3 21 4 dGVzdA== 4 dGVzdA==", "\x08gss-tsig\x00\x00\x00\x30\x39\x00\x00\x30\x39\x00\x03\x00\x15\x00\x04test\x00\x04test", false))
+/* (CASE_S(QType::ADDR, "zone format", "line format",false)) */
+ (CASE_S(QType::DLV, "20642 8 2 04443abe7e94c3985196beae5d548c727b044dda5151e60d7cd76a9fd931d00e", "\x50\xa2\x08\x02\x04\x44\x3a\xbe\x7e\x94\xc3\x98\x51\x96\xbe\xae\x5d\x54\x8c\x72\x7b\x04\x4d\xda\x51\x51\xe6\x0d\x7c\xd7\x6a\x9f\xd9\x31\xd0\x0e",false))
+ (CASE_S(QType::URI, "10000 1 \"ftp://ftp1.example.com/public\"", "\x27\x10\x00\x01\x66\x74\x70\x3a\x2f\x2f\x66\x74\x70\x31\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x70\x75\x62\x6c\x69\x63", false))
+ (CASE_S(QType::URI, "10 1 \"ftp://ftp1.example.com/public/with/a/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/very/long/url\"", "\x00\x0a\x00\x01\x66\x74\x70\x3a\x2f\x2f\x66\x74\x70\x31\x2e\x65\x78\x61\x6d\x70\x6c\x65\x2e\x63\x6f\x6d\x2f\x70\x75\x62\x6c\x69\x63\x2f\x77\x69\x74\x68\x2f\x61\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x76\x65\x72\x79\x2f\x6c\x6f\x6e\x67\x2f\x75\x72\x6c", false))
+ (CASE_S(QType::CAA, "0 issue \"example.net\"", "\x00\x05\x69\x73\x73\x75\x65\x65\x78\x61\x6d\x70\x6c\x65\x2e\x6e\x65\x74",false))
+ (CASE_S((QType::typeenum)65226,"\\# 3 414243","\x41\x42\x43",false))
+;
+
+ int n=0;
+ int lq=-1;
+ for(const cases_t::value_type& val : cases) {
+ QType q(val.get<0>());
+ if (lq != q.getCode()) n = 0;
+ lq = q.getCode();
+ n++;
+ BOOST_TEST_CHECKPOINT("Checking record type " << q.getName() << " test #" << n);
+ BOOST_TEST_MESSAGE("Checking record type " << q.getName() << " test #" << n);
+ try {
+ std::string recData;
+ if (q.getCode() != QType::TSIG) {
+ boost::scoped_ptr<DNSRecordContent> rec(DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>()));
+ BOOST_CHECK_MESSAGE(rec != NULL, "mastermake( " << q.getCode() << ", 1, " << val.get<1>() << ") returned NULL");
+ if (rec == NULL) continue;
+ // now verify the record (note that this will be same as *zone* value (except for certain QTypes)
+
+ switch(q.getCode()) {
+ case QType::NS:
+ case QType::PTR:
+ case QType::MX:
+ case QType::CNAME:
+ case QType::SOA:
+ case QType::TXT:
+ // check *input* value instead
+ REC_CHECK_EQUAL(rec->getZoneRepresentation(), val.get<1>());
+ break;
+ default:
+ REC_CHECK_EQUAL(rec->getZoneRepresentation(), val.get<2>());
+ }
+ recData = rec->serialize(DNSName("rec.test"));
+ } else {
+ std::shared_ptr<DNSRecordContent> rec3 = DNSRecordContent::unserialize(DNSName("rec.test"),q.getCode(),(val.get<3>()));
+ // TSIG special, only works the other way
+ recData = rec3->serialize(DNSName("rec.test"));
+ }
+ std::shared_ptr<DNSRecordContent> rec2 = DNSRecordContent::unserialize(DNSName("rec.test"),q.getCode(),recData);
+ BOOST_CHECK_MESSAGE(rec2 != NULL, "unserialize(rec.test, " << q.getCode() << ", recData) returned NULL");
+ if (rec2 == NULL) continue;
+ // now verify the zone representation (here it can be different!)
+ REC_CHECK_EQUAL(rec2->getZoneRepresentation(), val.get<2>());
+ // and last, check the wire format (using hex format for error readability)
+ string cmpData = makeHexDump(val.get<3>());
+ recData = makeHexDump(recData);
+ REC_CHECK_EQUAL(recData, cmpData);
+ } catch (std::runtime_error &err) {
+ REC_CHECK_MESSAGE(false, "Failed to verify " << q.getName() << ": " << err.what());
+ continue;
+ }
+ REC_FAIL_XSUCCESS(q.getName() << " test #" << n << " has unexpectedly passed")
+ }
+}
+
+bool test_dnsrecords_cc_predicate( std::exception const &ex ) { return true; }
+
+// these *MUST NOT* parse properly!
+BOOST_AUTO_TEST_CASE(test_record_types_bad_values) {
+ // qtype, value, zone/wire format, broken
+ typedef boost::tuple<const QType::typeenum, const std::string, case_type_enum_t, bool> case_t;
+ typedef std::list<case_t> cases_t;
+
+ cases_t cases = boost::assign::list_of
+ (case_t(QType::A, "932.521.256.42", zone, false)) // hollywood IP
+ (case_t(QType::A, "932.521", zone, false)) // truncated IP
+ (case_t(QType::A, "\xca\xec\x00", wire, false)) // truncated wire value
+ (case_t(QType::A, "127.0.0.1 evil data", zone, false)) // trailing garbage
+ (case_t(QType::AAAA, "23:00", zone, false)) // time when this test was written
+ (case_t(QType::AAAA, "23:00::15::43", zone, false)) // double compression
+ (case_t(QType::AAAA, "2a23:00::15::", zone, false)) // ditto
+ (case_t(QType::AAAA, "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff", zone, false)) // truncated wire value
+// empty label, must be broken
+ (case_t(QType::CNAME, "name..example.com.", zone, false))
+// overly large label (64), must be broken
+ (case_t(QType::CNAME, "1234567890123456789012345678901234567890123456789012345678901234.example.com.", zone, false))
+// local overly large name (256), must be broken
+ (case_t(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123.rec.test.", zone, false))
+// non-local overly large name (256), must be broken
+ (case_t(QType::CNAME, "123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.123456789012345678901234567890123456789012345678901234567890123.12345678901234567890123456789012345678901234567890123456789012.", zone, false))
+ (case_t(QType::SOA, "ns.rec.test hostmaster.test.rec 20130512010 3600 3600 604800 120", zone, false)) // too long serial
+;
+
+ int n=0;
+ int lq=-1;
+
+ for(const cases_t::value_type& val : cases) {
+ QType q(val.get<0>());
+ if (lq != q.getCode()) n = 0;
+ lq = q.getCode();
+ n++;
+ BOOST_TEST_CHECKPOINT("Checking bad value for record type " << q.getName() << " test #" << n);
+ BOOST_TEST_MESSAGE("Checking bad value for record type " << q.getName() << " test #" << n);
+
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, DNSName("unit.test"), q.getCode());
+
+ if (val.get<2>()) {
+ bool success=true;
+ BOOST_WARN_EXCEPTION( { boost::scoped_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>())); pw.startRecord(DNSName("unit.test"), q.getCode()); drc->toPacket(pw); success=false; }, std::exception, test_dnsrecords_cc_predicate );
+ if (success==false) REC_FAIL_XSUCCESS2(q.getName() << " test #" << n << " has unexpectedly passed"); // a bad record was detected when it was supposed not to be detected
+ } else {
+ BOOST_CHECK_EXCEPTION( { boost::scoped_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(q.getCode(), 1, val.get<1>())); pw.startRecord(DNSName("unit.test"), q.getCode()); drc->toPacket(pw); }, std::exception, test_dnsrecords_cc_predicate );
+ }
+ };
+}
+
+// special opt record test, because opt is odd
+BOOST_AUTO_TEST_CASE(test_opt_record_in) {
+ EDNSOpts eo;
+
+ // test that nsid gets parsed into system
+ std::string packet("\xf0\x01\x01\x00\x00\x01\x00\x01\x00\x00\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\x00\x00\x00\x10\x00\x04\x7f\x00\x00\x01\x00\x00\x29\x05\x00\x00\x00\x00\x00\x00\x0c\x00\x03\x00\x08powerdns",89);
+ OPTRecordContent::report();
+
+ MOADNSParser mdp(true, (char*)&*packet.begin(), (unsigned int)packet.size());
+
+ BOOST_CHECK_EQUAL(getEDNSOpts(mdp, &eo), true);
+
+ // this should contain NSID now
+ BOOST_CHECK_EQUAL(eo.d_packetsize, 1280);
+
+ // it should contain NSID option with value 'powerdns', and nothing else
+ BOOST_CHECK_EQUAL(eo.d_options.size(), 1);
+ BOOST_CHECK_EQUAL(eo.d_options[0].first, 3); // nsid
+ BOOST_CHECK_EQUAL(eo.d_options[0].second, "powerdns");
+}
+
+BOOST_AUTO_TEST_CASE(test_opt_record_out) {
+ vector<uint8_t> pak;
+ vector<pair<uint16_t,string > > opts;
+
+ DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A);
+ pw.startRecord(DNSName("www.powerdns.com"), QType::A, 16, 1, DNSResourceRecord::ANSWER);
+ pw.xfrIP(htonl(0x7f000001));
+ opts.push_back(pair<uint16_t,string>(3, "powerdns"));
+ pw.addOpt(1280, 0, 0, opts);
+ pw.getHeader()->id = htons(0xf001);
+ pw.getHeader()->rd = 1;
+ pw.commit();
+
+ // see if we can build a DNS packet that looks like this...
+ std::string packet("\xf0\x01\x01\x00\x00\x01\x00\x01\x00\x00\x00\x01\x03www\x08powerdns\x03""com\x00\x00\x01\x00\x01\xc0\x0c\x00\x01\x00\x01\x00\x00\x00\x10\x00\x04\x7f\x00\x00\x01\x00\x00\x29\x05\x00\x00\x00\x00\x00\x00\x0c\x00\x03\x00\x08powerdns",73);
+
+ BOOST_CHECK_EQUAL(makeHexDump(std::string(pak.begin(),pak.end())), makeHexDump(packet));
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <bitset>
+#include "iputils.hh"
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(iputils_hh)
+
+BOOST_AUTO_TEST_CASE(test_ComboAddress) {
+ ComboAddress local("127.0.0.1", 53);
+ BOOST_CHECK(local==local);
+ BOOST_CHECK_EQUAL(local.sin4.sin_family, AF_INET);
+ BOOST_CHECK_EQUAL(local.sin4.sin_port, htons(53));
+ BOOST_CHECK_EQUAL(local.sin4.sin_addr.s_addr, htonl(0x7f000001UL));
+
+ ComboAddress remote("130.161.33.15", 53);
+ BOOST_CHECK(!(local == remote));
+ BOOST_CHECK_EQUAL(remote.sin4.sin_port, htons(53));
+
+ ComboAddress withport("213.244.168.210:53");
+ BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53));
+
+ ComboAddress withportO("213.244.168.210:53", 5300);
+ BOOST_CHECK_EQUAL(withportO.sin4.sin_port, htons(53));
+
+ withport = ComboAddress("[::]:53");
+ BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(53));
+
+ withport = ComboAddress("[::]:5300", 53);
+ BOOST_CHECK_EQUAL(withport.sin4.sin_port, htons(5300));
+
+ // Verify that 2 'empty' ComboAddresses are equal, used in syncres.hh to
+ // signal auth-zones
+ ComboAddress a = ComboAddress();
+ ComboAddress b = ComboAddress();
+ BOOST_CHECK(a == b);
+
+ // Verify that 2 ComboAddresses are not the same
+ ComboAddress c = ComboAddress("127.0.0.1:53");
+ ComboAddress d = ComboAddress("127.0.0.1:52");
+ ComboAddress e = ComboAddress("127.0.0.2:53");
+
+ BOOST_CHECK(a != c);
+ BOOST_CHECK(c != d);
+ BOOST_CHECK(c != e);
+ BOOST_CHECK(d != e);
+ BOOST_CHECK(!(a != b));
+
+ // Verify that we don't allow invalid port numbers
+ BOOST_CHECK_THROW(ComboAddress("127.0.0.1:70000"), PDNSException); // Port no. too high
+ BOOST_CHECK_THROW(ComboAddress("127.0.0.1:-6"), PDNSException); // Port no. too low
+ BOOST_CHECK_THROW(ComboAddress("[::1]:70000"), PDNSException); // Port no. too high
+ BOOST_CHECK_THROW(ComboAddress("[::1]:-6"), PDNSException); // Port no. too low
+}
+
+BOOST_AUTO_TEST_CASE(test_ComboAddressCompare) {
+ ComboAddress a, b;
+ memset(&a, 0, sizeof(a));
+ memset(&b, 0, sizeof(b));
+ BOOST_CHECK(!(a<b));
+ BOOST_CHECK(!(a>b));
+}
+
+BOOST_AUTO_TEST_CASE(test_ComboAddressTruncate) {
+ ComboAddress ca4("130.161.252.29");
+ ca4.truncate(24);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+ ca4.truncate(16);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.0.0");
+
+
+
+ ca4 = ComboAddress("130.161.252.29");
+ ComboAddress orig(ca4);
+ for(int n=32; n; --n) {
+ ca4.truncate(n);
+
+ uint32_t p;
+ memcpy(&p, (char*)&ca4.sin4.sin_addr.s_addr, 4);
+ std::bitset<32> result(htonl(p));
+
+ memcpy(&p, (char*)&orig.sin4.sin_addr.s_addr, 4);
+ std::bitset<32> manual(htonl(p));
+
+ auto tokill=32-n;
+ for(int i =0; i< tokill; ++i)
+ manual.set(i, 0);
+
+ BOOST_CHECK_EQUAL(result, manual);
+ }
+
+ ca4 = ComboAddress("130.161.252.29");
+ ca4.truncate(31);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28");
+
+ ca4.truncate(30);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.28");
+
+ ca4.truncate(29);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.24");
+
+ ca4.truncate(23);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+
+ ca4.truncate(22);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.252.0");
+
+ ca4.truncate(21);
+ BOOST_CHECK_EQUAL(ca4.toString(), "130.161.248.0");
+
+ ComboAddress ca6("2001:888:2000:1d::2");
+ ca6.truncate(120);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+ ca6.truncate(64);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+ ca6.truncate(72); // 0102 304 0506 78
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000:1d::");
+ ca6.truncate(56);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::");
+ ca6.truncate(48);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888:2000::");
+ ca6.truncate(32);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001:888::");
+ ca6.truncate(16);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2001::");
+ ca6.truncate(8);
+ BOOST_CHECK_EQUAL(ca6.toString(), "2000::");
+
+
+ orig=ca6=ComboAddress("2001:888:2000:1d::2");
+ for(int n=128; n; --n) {
+ ca6.truncate(n);
+
+ std::bitset<128> result, manual;
+ for(int i=0; i < 16; ++i) {
+ result<<=8;
+ result|= std::bitset<128>(*((unsigned char*)&ca6.sin6.sin6_addr.s6_addr + i));
+
+ manual<<=8;
+ manual|= std::bitset<128>(*((unsigned char*)&orig.sin6.sin6_addr.s6_addr + i));
+ }
+
+ auto tokill=128-n;
+ for(int i =0; i< tokill; ++i)
+ manual.set(i, 0);
+
+ BOOST_CHECK_EQUAL(result, manual);
+ }
+}
+
+
+BOOST_AUTO_TEST_CASE(test_Mapping)
+{
+ ComboAddress lh("::1");
+ BOOST_CHECK_EQUAL(lh.toString(), "::1");
+
+ ComboAddress lh2("::2");
+ BOOST_CHECK_EQUAL(lh2.toString(), "::2");
+
+}
+
+BOOST_AUTO_TEST_CASE(test_Netmask) {
+ ComboAddress local("127.0.0.1", 53);
+ ComboAddress remote("130.161.252.29", 53);
+
+ Netmask nm("127.0.0.1/24");
+ BOOST_CHECK(nm.match(local));
+ BOOST_CHECK(!nm.match(remote));
+
+ Netmask nm6("fe80::92fb:a6ff:fe4a:51da/64");
+ BOOST_CHECK(nm6.match("fe80::92fb:a6ff:fe4a:51db"));
+ BOOST_CHECK(!nm6.match("fe81::92fb:a6ff:fe4a:51db"));
+
+ Netmask nmp("130.161.252.29/32");
+ BOOST_CHECK(nmp.match(remote));
+
+ Netmask nmp6("fe80::92fb:a6ff:fe4a:51da/128");
+ BOOST_CHECK(nmp6.match("fe80::92fb:a6ff:fe4a:51da"));
+ BOOST_CHECK(!nmp6.match("fe81::92fb:a6ff:fe4a:51db"));
+
+ Netmask all("0.0.0.0/0");
+ BOOST_CHECK(all.match(local) && all.match(remote));
+
+ Netmask all6("::/0");
+ BOOST_CHECK(all6.match("::1") && all6.match("fe80::92fb:a6ff:fe4a:51da"));
+}
+
+BOOST_AUTO_TEST_CASE(test_NetmaskGroup) {
+ NetmaskGroup ng;
+ ng.addMask("10.0.1.0");
+ BOOST_CHECK(ng.match(ComboAddress("10.0.1.0")));
+ ng.toMasks("127.0.0.0/8, 10.0.0.0/24");
+ BOOST_CHECK(ng.match(ComboAddress("127.0.0.1")));
+ BOOST_CHECK(ng.match(ComboAddress("10.0.0.3")));
+ BOOST_CHECK(ng.match(ComboAddress("10.0.1.0")));
+ BOOST_CHECK(!ng.match(ComboAddress("128.1.2.3")));
+ BOOST_CHECK(!ng.match(ComboAddress("10.0.1.1")));
+ BOOST_CHECK(!ng.match(ComboAddress("::1")));
+ ng.addMask("::1");
+ BOOST_CHECK(ng.match(ComboAddress("::1")));
+ BOOST_CHECK(!ng.match(ComboAddress("::2")));
+ ng.addMask("fe80::/16");
+ BOOST_CHECK(ng.match(ComboAddress("fe80::1")));
+ BOOST_CHECK(!ng.match(ComboAddress("fe81::1")));
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include "md5.hh"
+#include "misc.hh"
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(test_md5_hh)
+
+BOOST_AUTO_TEST_CASE(test_pdns_md5sum)
+{
+ std::string result = "a3 24 8c e3 1a 88 a6 40 e6 30 73 98 57 6d 06 9e ";
+ std::string sum = pdns_md5sum("a quick brown fox jumped over the lazy dog");
+
+ BOOST_CHECK_EQUAL(makeHexDump(sum), result);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include "misc.hh"
+#include "dns.hh"
+#include <arpa/inet.h>
+#include <utility>
+
+using std::string;
+
+BOOST_AUTO_TEST_SUITE(misc_hh)
+typedef pair<std::string, uint16_t> typedns_t;
+
+BOOST_AUTO_TEST_CASE(test_CIStringCompare) {
+ set<std::string, CIStringCompare> nsset;
+ nsset.insert("abc");
+ nsset.insert("ns.example.com");
+ nsset.insert("");
+ nsset.insert("def");
+ nsset.insert("aBc");
+ nsset.insert("ns.example.com");
+ BOOST_CHECK_EQUAL(nsset.size(), 4);
+
+ ostringstream s;
+ for(set<std::string, CIStringCompare>::const_iterator i=nsset.begin();i!=nsset.end();++i) {
+ s<<"("<<*i<<")";
+ }
+ BOOST_CHECK_EQUAL(s.str(), "()(abc)(def)(ns.example.com)");
+}
+
+BOOST_AUTO_TEST_CASE(test_CIStringPairCompare) {
+ set<typedns_t, CIStringPairCompare> nsset2;
+ nsset2.insert(make_pair("ns.example.com", 1));
+ nsset2.insert(make_pair("abc", 1));
+ nsset2.insert(make_pair("", 1));
+ nsset2.insert(make_pair("def", 1));
+ nsset2.insert(make_pair("abc", 2));
+ nsset2.insert(make_pair("abc", 1));
+ nsset2.insert(make_pair("ns.example.com", 0));
+ nsset2.insert(make_pair("abc", 2));
+ nsset2.insert(make_pair("ABC", 2));
+ BOOST_CHECK_EQUAL(nsset2.size(), 6);
+
+ ostringstream s;
+ for(set<typedns_t, CIStringPairCompare>::const_iterator i=nsset2.begin();i!=nsset2.end();++i) {
+ s<<"("<<i->first<<"|"<<i->second<<")";
+ }
+ BOOST_CHECK_EQUAL(s.str(), "(|1)(abc|1)(abc|2)(def|1)(ns.example.com|0)(ns.example.com|1)");
+}
+
+BOOST_AUTO_TEST_CASE(test_pdns_ilexicographical_compare) {
+ typedef boost::tuple<const std::string, const std::string, bool> case_t;
+ typedef std::list<case_t> cases_t;
+
+ cases_t cases = boost::assign::list_of
+ (case_t(std::string(""), std::string(""), false))
+ (case_t(std::string(""), std::string("abc"), true))
+ (case_t(std::string("abc"), std::string(""), false))
+ (case_t(std::string("abc"), std::string("abcd"), true))
+ (case_t(std::string("abcd"), std::string("abc"), false))
+ (case_t(std::string("abd"), std::string("abc"), false))
+ (case_t(std::string("abc"), std::string("abd"), true))
+ (case_t(std::string("abc"), std::string("Abc"), false))
+ (case_t(std::string("Abc"), std::string("abc"), false))
+ ;
+
+ for(const case_t& val : cases) {
+ bool res;
+ res = pdns_ilexicographical_compare(val.get<0>(), val.get<1>());
+ BOOST_CHECK_EQUAL(res, val.get<2>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_pdns_iequals) {
+ typedef boost::tuple<const std::string, const std::string, bool> case_t;
+ typedef std::list<case_t> cases_t;
+
+ cases_t cases = boost::assign::list_of
+ (case_t(std::string(""), std::string(""), true))
+ (case_t(std::string(""), std::string("abc"), false))
+ (case_t(std::string("abc"), std::string(""), false))
+ (case_t(std::string("abc"), std::string("abcd"), false))
+ (case_t(std::string("abcd"), std::string("abc"), false))
+ (case_t(std::string("abd"), std::string("abc"), false))
+ (case_t(std::string("abc"), std::string("abd"), false))
+ (case_t(std::string("abc"), std::string("Abc"), true))
+ (case_t(std::string("Abc"), std::string("abc"), true))
+ ;
+
+ for(const case_t& val : cases) {
+ bool res;
+ res = pdns_iequals(val.get<0>(), val.get<1>());
+ BOOST_CHECK_EQUAL(res, val.get<2>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_stripDot) {
+ BOOST_CHECK_EQUAL(stripDot("."), "");
+ BOOST_CHECK_EQUAL(stripDot(""), "");
+ BOOST_CHECK_EQUAL(stripDot("www.powerdns.com."), "www.powerdns.com");
+ BOOST_CHECK_EQUAL(stripDot("www.powerdns.com"), "www.powerdns.com");
+}
+
+BOOST_AUTO_TEST_CASE(test_labelReverse) {
+ BOOST_CHECK_EQUAL(labelReverse("www.powerdns.com"), "com powerdns www");
+}
+
+BOOST_AUTO_TEST_CASE(test_makeRelative) {
+ BOOST_CHECK_EQUAL(makeRelative("www.powerdns.com", "powerdns.com"), "www");
+ BOOST_CHECK_EQUAL(makeRelative("PoWeRdNs.CoM", "powerdns.com"), "");
+}
+
+BOOST_AUTO_TEST_CASE(test_AtomicCounter) {
+ AtomicCounter ac(0);
+ ++ac;
+ ++ac;
+ BOOST_CHECK_EQUAL(ac, 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_endianness) {
+ uint32_t i = 1;
+#if BYTE_ORDER == BIG_ENDIAN
+ BOOST_CHECK_EQUAL(i, htonl(i));
+#elif BYTE_ORDER == LITTLE_ENDIAN
+ uint32_t j=0x01000000;
+ BOOST_CHECK_EQUAL(i, ntohl(j));
+#else
+ BOOST_FAIL("Did not detect endianness at all");
+#endif
+}
+
+BOOST_AUTO_TEST_CASE(test_parseService) {
+ ServiceTuple tp;
+ parseService("smtp.powerdns.com:25", tp);
+ BOOST_CHECK_EQUAL(tp.host, "smtp.powerdns.com");
+ BOOST_CHECK_EQUAL(tp.port, 25);
+ parseService("smtp.powerdns.com", tp);
+ BOOST_CHECK_EQUAL(tp.port, 25);
+}
+
+BOOST_AUTO_TEST_CASE(test_ternary) {
+ int maxqps=1024;
+ BOOST_CHECK_EQUAL(defTer(maxqps, 16384), maxqps);
+ BOOST_CHECK_EQUAL(defTer(0, 16384), 16384);
+
+ int* qps=0;
+ BOOST_CHECK_EQUAL(*defTer(qps, &maxqps), 1024);
+}
+
+BOOST_AUTO_TEST_CASE(test_SimpleMatch) {
+ BOOST_CHECK_EQUAL(SimpleMatch("").match(std::string("")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("?").match(std::string("")), false);
+ BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("")), true);
+
+ BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("abc")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("ab")), false);
+ BOOST_CHECK_EQUAL(SimpleMatch("abc").match(std::string("bc")), false);
+
+ BOOST_CHECK_EQUAL(SimpleMatch("?").match(std::string("a")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("abc")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("ab")), false);
+ BOOST_CHECK_EQUAL(SimpleMatch("a?c").match(std::string("bc")), false);
+
+ BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("*")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("abc")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("ab")), false);
+ BOOST_CHECK_EQUAL(SimpleMatch("a*c").match(std::string("bc")), false);
+
+ BOOST_CHECK_EQUAL(SimpleMatch("*").match(std::string("abcdefghj")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("*a").match(std::string("abca")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("*a").match(std::string("abcb")), false);
+ BOOST_CHECK_EQUAL(SimpleMatch("abc*").match(std::string("abcabcabcabacabac")), true);
+ BOOST_CHECK_EQUAL(SimpleMatch("abc*").match(std::string("abc")), true);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "iputils.hh"
+#include "nameserver.hh"
+#include "statbag.hh"
+#include "arguments.hh"
+#include <utility>
+
+extern vector<ComboAddress> g_localaddresses;
+
+ArgvMap &arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+BOOST_AUTO_TEST_SUITE(nameserver_cc)
+
+BOOST_AUTO_TEST_CASE(test_AddressIsUs4) {
+ ComboAddress local1("127.0.0.1", 53);
+ ComboAddress local2("127.0.0.2", 53);
+ ComboAddress Remote("192.168.255.255", 53);
+
+ g_localaddresses.push_back(ComboAddress("0.0.0.0", 53));
+
+ BOOST_CHECK_EQUAL(AddressIsUs(local1), true);
+// BOOST_CHECK_EQUAL(AddressIsUs(local2), false);
+ BOOST_CHECK_EQUAL(AddressIsUs(Remote), false);
+
+ g_localaddresses.clear();
+ g_localaddresses.push_back(ComboAddress("192.168.255.255", 53));
+ BOOST_CHECK_EQUAL(AddressIsUs(Remote), true);
+ Remote.sin4.sin_port = 1;
+ BOOST_CHECK_EQUAL(AddressIsUs(Remote), false);
+}
+
+BOOST_AUTO_TEST_CASE(test_AddressIsUs6) {
+ ComboAddress local1("127.0.0.1", 53);
+ ComboAddress local2("127.0.0.2", 53);
+ ComboAddress local3("::1", 53);
+ ComboAddress Remote("192.168.255.255", 53);
+
+ g_localaddresses.clear();
+ g_localaddresses.push_back(ComboAddress("::", 53));
+
+ BOOST_CHECK_EQUAL(AddressIsUs(local1), true);
+// BOOST_CHECK_EQUAL(AddressIsUs(local2), false);
+ BOOST_CHECK_EQUAL(AddressIsUs(local3), true);
+ BOOST_CHECK_EQUAL(AddressIsUs(Remote), false);
+ Remote.sin4.sin_port = 1;
+ BOOST_CHECK_EQUAL(AddressIsUs(Remote), false);
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <bitset>
+#include "iputils.hh"
+
+using namespace boost;
+
+BOOST_AUTO_TEST_SUITE(nmtree)
+
+BOOST_AUTO_TEST_CASE(test_basic) {
+ NetmaskTree<int> nmt;
+ nmt.insert(Netmask("130.161.252.0/24")).second=0;
+ nmt.insert(Netmask("130.161.0.0/16")).second=1;
+ nmt.insert(Netmask("130.0.0.0/8")).second=2;
+
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("213.244.168.210")), (void*)0);
+ auto found=nmt.lookup(ComboAddress("130.161.252.29"));
+ BOOST_CHECK(found);
+ BOOST_CHECK_EQUAL(found->second, 0);
+ found=nmt.lookup(ComboAddress("130.161.180.1"));
+ BOOST_CHECK(found);
+ BOOST_CHECK_EQUAL(found->second, 1);
+
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.255.255.255"))->second, 2);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.252.255"))->second, 0);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.253.255"))->second, 1);
+
+ found=nmt.lookup(ComboAddress("130.145.180.1"));
+ BOOST_CHECK(found);
+ BOOST_CHECK_EQUAL(found->second, 2);
+
+ nmt.clear();
+ BOOST_CHECK(!nmt.lookup(ComboAddress("130.161.180.1")));
+
+ nmt.insert(Netmask("::1")).second=1;
+ nmt.insert(Netmask("::/0")).second=0;
+ nmt.insert(Netmask("fe80::/16")).second=2;
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("130.161.253.255")), (void*)0);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::2"))->second, 0);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::ffff"))->second, 0);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("::1"))->second, 1);
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("fe80::1"))->second, 2);
+}
+
+BOOST_AUTO_TEST_CASE(test_single) {
+ NetmaskTree<bool> nmt;
+ nmt.insert(Netmask("127.0.0.0/8")).second=1;
+ BOOST_CHECK_EQUAL(nmt.lookup(ComboAddress("127.0.0.1"))->second, 1);
+}
+
+BOOST_AUTO_TEST_CASE(test_scale) {
+ string start="192.168.";
+ NetmaskTree<int> works;
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ works.insert(Netmask(start+std::to_string(i)+"."+std::to_string(j))).second=i*j;
+ }
+ }
+
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+"."+std::to_string(j)))->second, i*j);
+ }
+ }
+
+ start="130.161.";
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+"."+std::to_string(j))), (void*)0);
+ }
+ }
+
+ start="2000:123:";
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ works.insert(Netmask(start+std::to_string(i)+":"+std::to_string(j)+"::/64")).second=i*j;
+ }
+ }
+
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+":"+std::to_string(j)+"::"+std::to_string(i)+":"+std::to_string(j)))->second, i*j);
+ }
+ }
+
+ start="2001:123:";
+ for(int i=0; i < 256; ++i) {
+ for(int j=0; j < 256; ++j) {
+ BOOST_CHECK_EQUAL(works.lookup(ComboAddress(start+std::to_string(i)+":"+std::to_string(j)+"::"+std::to_string(i)+":"+std::to_string(j))), (void*)0);
+ }
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/test/floating_point_comparison.hpp>
+#include "iputils.hh"
+#include "nameserver.hh"
+#include "statbag.hh"
+#include "packetcache.hh"
+#include "arguments.hh"
+#include <utility>
+extern StatBag S;
+
+BOOST_AUTO_TEST_SUITE(packetcache_cc)
+
+BOOST_AUTO_TEST_CASE(test_PacketCacheSimple) {
+ PacketCache PC;
+
+ ::arg().set("max-cache-entries", "Maximum number of cache entries")="1000000";
+ ::arg().set("cache-ttl","Seconds to store packets in the PacketCache")="20";
+ ::arg().set("recursive-cache-ttl","Seconds to store packets for recursive queries in the PacketCache")="10";
+ ::arg().set("negquery-cache-ttl","Seconds to store negative query results in the QueryCache")="60";
+ ::arg().set("query-cache-ttl","Seconds to store query results in the QueryCache")="20";
+ ::arg().set("recursor","If recursion is desired, IP address of a recursing nameserver")="no";
+
+ S.declare("deferred-cache-inserts","Amount of cache inserts that were deferred because of maintenance");
+ S.declare("deferred-cache-lookup","Amount of cache lookups that were deferred because of maintenance");
+
+
+ BOOST_CHECK_EQUAL(PC.size(), 0);
+ PC.insert(DNSName("hello"), QType(QType::A), PacketCache::QUERYCACHE, "something", 3600, 1);
+ BOOST_CHECK_EQUAL(PC.size(), 1);
+ PC.purge();
+ BOOST_CHECK_EQUAL(PC.size(), 0);
+
+ int counter=0;
+ try {
+ for(counter = 0; counter < 100000; ++counter) {
+ DNSName a=DNSName("hello ")+DNSName(std::to_string(counter));
+ BOOST_CHECK_EQUAL(DNSName(a.toString()), a);
+
+ PC.insert(a, QType(QType::A), PacketCache::QUERYCACHE, "something", 3600, 1);
+ if(!PC.purge(a.toString()))
+ BOOST_FAIL("Could not remove entry we just added to packet cache!");
+ PC.insert(a, QType(QType::A), PacketCache::QUERYCACHE, "something", 3600, 1);
+ }
+
+ BOOST_CHECK_EQUAL(PC.size(), counter);
+
+ int delcounter=0;
+ for(delcounter=0; delcounter < counter/100; ++delcounter) {
+ DNSName a=DNSName("hello ")+DNSName(std::to_string(delcounter));
+ PC.purge(a.toString());
+ }
+
+ BOOST_CHECK_EQUAL(PC.size(), counter-delcounter);
+
+ int matches=0;
+ vector<DNSResourceRecord> entry;
+ int expected=counter-delcounter;
+ for(; delcounter < counter; ++delcounter) {
+ if(PC.getEntry(DNSName("hello ")+DNSName(std::to_string(delcounter)), QType(QType::A), PacketCache::QUERYCACHE, entry, 1)) {
+ matches++;
+ }
+ }
+ BOOST_CHECK_EQUAL(matches, expected);
+ // BOOST_CHECK_EQUAL(entry, "something");
+ }
+ catch(PDNSException& e) {
+ cerr<<"Had error: "<<e.reason<<endl;
+ throw;
+ }
+
+}
+
+static PacketCache* g_PC;
+
+static void *threadMangler(void* a)
+try
+{
+ unsigned int offset=(unsigned int)(unsigned long)a;
+ for(unsigned int counter=0; counter < 100000; ++counter)
+ g_PC->insert(DNSName("hello ")+DNSName(std::to_string(counter+offset)), QType(QType::A), PacketCache::QUERYCACHE, "something", 3600, 1);
+ return 0;
+}
+ catch(PDNSException& e) {
+ cerr<<"Had error: "<<e.reason<<endl;
+ throw;
+ }
+
+AtomicCounter g_missing;
+
+static void *threadReader(void* a)
+try
+{
+ unsigned int offset=(unsigned int)(unsigned long)a;
+ vector<DNSResourceRecord> entry;
+ for(unsigned int counter=0; counter < 100000; ++counter)
+ if(!g_PC->getEntry(DNSName("hello ")+DNSName(std::to_string(counter+offset)), QType(QType::A), PacketCache::QUERYCACHE, entry, 1)) {
+ g_missing++;
+ }
+ return 0;
+}
+catch(PDNSException& e) {
+ cerr<<"Had error in threadReader: "<<e.reason<<endl;
+ throw;
+}
+
+
+
+BOOST_AUTO_TEST_CASE(test_PacketCacheThreaded) {
+ try {
+ PacketCache PC;
+ g_PC=&PC;
+ pthread_t tid[4];
+ for(int i=0; i < 4; ++i)
+ pthread_create(&tid[i], 0, threadMangler, (void*)(i*1000000UL));
+ void* res;
+ for(int i=0; i < 4 ; ++i)
+ pthread_join(tid[i], &res);
+
+ BOOST_CHECK_EQUAL(PC.size() + S.read("deferred-cache-inserts"), 400000);
+ BOOST_CHECK_SMALL(1.0*S.read("deferred-cache-inserts"), 10000.0);
+
+ for(int i=0; i < 4; ++i)
+ pthread_create(&tid[i], 0, threadReader, (void*)(i*1000000UL));
+ for(int i=0; i < 4 ; ++i)
+ pthread_join(tid[i], &res);
+
+ BOOST_CHECK(S.read("deferred-cache-inserts") + S.read("deferred-cache-lookup") >= g_missing);
+ // BOOST_CHECK_EQUAL(S.read("deferred-cache-lookup"), 0); // cache cleaning invalidates this
+ }
+ catch(PDNSException& e) {
+ cerr<<"Had error: "<<e.reason<<endl;
+ throw;
+ }
+
+}
+
+bool g_stopCleaning;
+static void *cacheCleaner(void*)
+try
+{
+ while(!g_stopCleaning) {
+ g_PC->cleanup();
+ }
+
+ return 0;
+}
+catch(PDNSException& e) {
+ cerr<<"Had error in threadReader: "<<e.reason<<endl;
+ throw;
+}
+
+BOOST_AUTO_TEST_CASE(test_PacketCacheClean) {
+ try {
+ PacketCache PC;
+
+ for(unsigned int counter = 0; counter < 1000000; ++counter) {
+ PC.insert(DNSName("hello ")+DNSName(std::to_string(counter)), QType(QType::A), PacketCache::QUERYCACHE, "something", 1, 1);
+ }
+
+ sleep(1);
+
+ g_PC=&PC;
+ pthread_t tid[4];
+
+ ::arg().set("max-cache-entries")="10000";
+
+ pthread_create(&tid[0], 0, threadReader, (void*)(0*1000000UL));
+ pthread_create(&tid[1], 0, threadReader, (void*)(1*1000000UL));
+ pthread_create(&tid[2], 0, threadReader, (void*)(2*1000000UL));
+ // pthread_create(&tid[2], 0, threadMangler, (void*)(0*1000000UL));
+ pthread_create(&tid[3], 0, cacheCleaner, 0);
+
+ void *res;
+ for(int i=0; i < 3 ; ++i)
+ pthread_join(tid[i], &res);
+ g_stopCleaning=true;
+ pthread_join(tid[3], &res);
+ }
+ catch(PDNSException& e) {
+ cerr<<"Had error in threadReader: "<<e.reason<<endl;
+ throw;
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_PacketCachePacket) {
+ try {
+ ::arg().setSwitch("no-shuffle","Set this to prevent random shuffling of answers - for regression testing")="off";
+
+ PacketCache PC;
+ vector<uint8_t> pak;
+ vector<pair<uint16_t,string > > opts;
+
+ DNSPacketWriter pw(pak, DNSName("www.powerdns.com"), QType::A);
+ DNSPacket q(true), r(false), r2(false);
+ q.parse((char*)&pak[0], pak.size());
+
+ pak.clear();
+ DNSPacketWriter pw2(pak, DNSName("www.powerdns.com"), QType::A);
+ pw2.startRecord(DNSName("www.powerdns.com"), QType::A, 16, 1, DNSResourceRecord::ANSWER);
+ pw2.xfrIP(htonl(0x7f000001));
+ pw2.commit();
+
+ r.parse((char*)&pak[0], pak.size());
+
+ PC.insert(&q, &r, false, 3600);
+
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+
+ PC.purge("www.powerdns.com");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 0);
+
+ PC.insert(&q, &r, false, 3600);
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+ PC.purge("com$");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 0);
+
+ PC.insert(&q, &r, false, 3600);
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+ PC.purge("powerdns.com$");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 0);
+
+ PC.insert(&q, &r, false, 3600);
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+ PC.purge("www.powerdns.com$");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 0);
+
+ PC.insert(&q, &r, false, 3600);
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, true), 0);
+ PC.purge("www.powerdns.com$");
+
+ PC.insert(&q, &r, true, 3600);
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, false), 0);
+ PC.purge("www.powerdns.com$");
+
+ PC.insert(&q, &r, true, 3600);
+ PC.purge("www.powerdns.net");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, true), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+ PC.purge("net$");
+ BOOST_CHECK_EQUAL(PC.get(&q, &r2, true), 1);
+ BOOST_CHECK_EQUAL(r2.qdomain, r.qdomain);
+ PC.purge("www.powerdns.com$");
+ BOOST_CHECK_EQUAL(PC.size(), 0);
+ }
+ catch(PDNSException& e) {
+ cerr<<"Had error in threadReader: "<<e.reason<<endl;
+ throw;
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "rcpgenerator.hh"
+#include "misc.hh"
+#include <utility>
+
+using std::string;
+
+BOOST_AUTO_TEST_SUITE(rcp_generator_cc)
+
+BOOST_AUTO_TEST_CASE(test_xfrIP6) {
+ RecordTextReader rtr("::1");
+ string rawIPv6;
+ rtr.xfrIP6(rawIPv6);
+ string loopback6;
+ loopback6.append(15, 0);
+ loopback6.append(1,1);
+ BOOST_CHECK_EQUAL(makeHexDump(rawIPv6), makeHexDump(loopback6));
+
+ RecordTextReader rtr2("2a01:4f8:d12:1880::5");
+ rtr2.xfrIP6(rawIPv6);
+ string ip6("\x2a\x01\x04\xf8\x0d\x12\x18\x80\x00\x00\x00\x00\x00\x00\x00\x05", 16);
+ BOOST_CHECK_EQUAL(makeHexDump(rawIPv6), makeHexDump(ip6));
+
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
+
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "dns_random.hh"
+#include "iputils.hh"
+#include "recpacketcache.hh"
+#include <utility>
+
+
+BOOST_AUTO_TEST_SUITE(recpacketcache_cc)
+
+BOOST_AUTO_TEST_CASE(test_recPacketCacheSimple) {
+ RecursorPacketCache rpc;
+ BOOST_CHECK_EQUAL(rpc.size(), 0);
+
+ DNSName qname("www.powerdns.com");
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, qname, QType::A);
+ pw.getHeader()->rd=true;
+ pw.getHeader()->qr=false;
+ pw.getHeader()->id=random();
+ string qpacket((const char*)&packet[0], packet.size());
+ pw.startRecord(qname, QType::A, 3600);
+
+ ARecordContent ar("127.0.0.1");
+ ar.toPacket(pw);
+ pw.commit();
+ string rpacket((const char*)&packet[0], packet.size());
+
+ rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+ BOOST_CHECK_EQUAL(rpc.size(), 1);
+ rpc.doPruneTo(0);
+ BOOST_CHECK_EQUAL(rpc.size(), 0);
+ rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+ BOOST_CHECK_EQUAL(rpc.size(), 1);
+ rpc.doWipePacketCache(qname);
+ BOOST_CHECK_EQUAL(rpc.size(), 0);
+
+ rpc.insertResponsePacket(0,qname, QType::A, qpacket, rpacket, time(0), 3600);
+ uint32_t age=0;
+ string fpacket;
+ bool found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age);
+ BOOST_CHECK_EQUAL(found, 1);
+ BOOST_CHECK_EQUAL(fpacket, rpacket);
+
+ packet.clear();
+ qname+=DNSName("co.uk");
+ DNSPacketWriter pw2(packet, qname, QType::A);
+
+ pw2.getHeader()->rd=true;
+ pw2.getHeader()->qr=false;
+ pw2.getHeader()->id=random();
+ qpacket.assign((const char*)&packet[0], packet.size());
+ found = rpc.getResponsePacket(0, qpacket, time(0), &fpacket, &age);
+ BOOST_CHECK_EQUAL(found, 0);
+
+ rpc.doWipePacketCache(DNSName("com"), 0xffff, true);
+ BOOST_CHECK_EQUAL(rpc.size(), 0);
+
+
+
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+
+#include "sha.hh"
+#include "misc.hh"
+
+using namespace boost;
+using namespace boost::assign;
+
+BOOST_AUTO_TEST_SUITE(test_sha_hh)
+
+// input, output
+typedef boost::tuple<const std::string, const std::string> case_t;
+typedef std::vector<case_t> cases_t;
+
+BOOST_AUTO_TEST_CASE(test_sha1) {
+ cases_t cases = list_of
+ (case_t("abc", "a9 99 3e 36 47 06 81 6a ba 3e 25 71 78 50 c2 6c 9c d0 d8 9d "))
+ (case_t("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "84 98 3e 44 1c 3b d2 6e ba ae 4a a1 f9 51 29 e5 e5 46 70 f1 "));
+
+ for(case_t& val : cases) {
+ BOOST_CHECK_EQUAL(makeHexDump(pdns_sha1sum(val.get<0>())), val.get<1>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_sha256) {
+ cases_t cases = list_of
+ (case_t("abc", "ba 78 16 bf 8f 01 cf ea 41 41 40 de 5d ae 22 23 b0 03 61 a3 96 17 7a 9c b4 10 ff 61 f2 00 15 ad "))
+ (case_t("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "24 8d 6a 61 d2 06 38 b8 e5 c0 26 93 0c 3e 60 39 a3 3c e4 59 64 ff 21 67 f6 ec ed d4 19 db 06 c1 "));
+
+ for(case_t& val : cases) {
+ BOOST_CHECK_EQUAL(makeHexDump(pdns_sha256sum(val.get<0>())), val.get<1>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_sha384) {
+ cases_t cases = list_of
+ (case_t("abc", "cb 00 75 3f 45 a3 5e 8b b5 a0 3d 69 9a c6 50 07 27 2c 32 ab 0e de d1 63 1a 8b 60 5a 43 ff 5b ed 80 86 07 2b a1 e7 cc 23 58 ba ec a1 34 c8 25 a7 "))
+ (case_t("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "33 91 fd dd fc 8d c7 39 37 07 a6 5b 1b 47 09 39 7c f8 b1 d1 62 af 05 ab fe 8f 45 0d e5 f3 6b c6 b0 45 5a 85 20 bc 4e 6f 5f e9 5b 1f e3 c8 45 2b "));
+
+ for(case_t& val : cases) {
+ BOOST_CHECK_EQUAL(makeHexDump(pdns_sha384sum(val.get<0>())), val.get<1>());
+ }
+}
+
+BOOST_AUTO_TEST_CASE(test_sha512) {
+ cases_t cases = list_of
+ (case_t("abc", "dd af 35 a1 93 61 7a ba cc 41 73 49 ae 20 41 31 12 e6 fa 4e 89 a9 7e a2 0a 9e ee e6 4b 55 d3 9a 21 92 99 2a 27 4f c1 a8 36 ba 3c 23 a3 fe eb bd 45 4d 44 23 64 3c e8 0e 2a 9a c9 4f a5 4c a4 9f "))
+ (case_t("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlmnomnopnopq", "20 4a 8f c6 dd a8 2f 0a 0c ed 7b eb 8e 08 a4 16 57 c1 6e f4 68 b2 28 a8 27 9b e3 31 a7 03 c3 35 96 fd 15 c1 3b 1b 07 f9 aa 1d 3b ea 57 78 9c a0 31 ad 85 c7 a7 1d d7 03 54 ec 63 12 38 ca 34 45 "));
+
+ for(case_t& val : cases) {
+ BOOST_CHECK_EQUAL(makeHexDump(pdns_sha512sum(val.get<0>())), val.get<1>());
+ }
+}
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/scoped_ptr.hpp>
+
+#include "base64.hh"
+#include "dnsseckeeper.hh"
+#include "dnssecinfra.hh"
+#include "misc.hh"
+
+BOOST_AUTO_TEST_SUITE(test_signers)
+
+#if defined(HAVE_LIBSODIUM) || defined(HAVE_LIBDECAF)
+BOOST_AUTO_TEST_CASE(test_ed25519_signer) {
+ vector<std::shared_ptr<DNSRecordContent> > rrs;
+ DNSName qname("example.com.");
+ DNSKEYRecordContent drc;
+
+ // TODO: make this a collection of inputs and resulting sigs for various algos
+ shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc,
+"Private-key-format: v1.2\n"
+"Algorithm: 15 (ED25519)\n"
+"PrivateKey: ODIyNjAzODQ2MjgwODAxMjI2NDUxOTAyMDQxNDIyNjI=");
+
+ DNSSECPrivateKey dpk;
+ dpk.setKey(engine);
+
+ reportBasicTypes();
+
+ rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com."));
+
+ RRSIGRecordContent rrc;
+ rrc.d_originalttl = 3600;
+ rrc.d_sigexpire = 1440021600;
+ rrc.d_siginception = 1438207200;
+ rrc.d_signer = qname;
+ rrc.d_type = QType::MX;
+ rrc.d_labels = 2;
+ // TODO: derive the next two from the key
+ rrc.d_tag = 3613;
+ rrc.d_algorithm = 15;
+
+ string msg = getMessageForRRSET(qname, rrc, rrs, false);
+
+ // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
+ BOOST_CHECK_EQUAL(makeHexDump(msg), "00 0f 0f 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 0e 1d 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ");
+
+ string signature = engine->sign(msg);
+ string b64 = Base64Encode(signature);
+
+ // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
+ BOOST_CHECK_EQUAL(b64, "oL9krJun7xfBOIWcGHi7mag5/hdZrKWw15jPGrHpjQeRAvTdszaPD+QLs3fx8A4M3e23mRZ9VrbpMngwcrqNAg==");
+}
+#endif
+
+#ifdef HAVE_LIBDECAF
+BOOST_AUTO_TEST_CASE(test_ed448_signer) {
+ vector<std::shared_ptr<DNSRecordContent> > rrs;
+ DNSName qname("example.com.");
+ DNSKEYRecordContent drc;
+
+ // TODO: make this a collection of inputs and resulting sigs for various algos
+ shared_ptr<DNSCryptoKeyEngine> engine = DNSCryptoKeyEngine::makeFromISCString(drc,
+"Private-key-format: v1.2\n"
+"Algorithm: 16 (ED448)\n"
+"PrivateKey: xZ+5Cgm463xugtkY5B0Jx6erFTXp13rYegst0qRtNsOYnaVpMx0Z/c5EiA9x8wWbDDct/U3FhYWA\n");
+
+ DNSSECPrivateKey dpk;
+ dpk.setKey(engine);
+
+ reportBasicTypes();
+
+ rrs.push_back(DNSRecordContent::makeunique(QType::MX, 1, "10 mail.example.com."));
+
+ RRSIGRecordContent rrc;
+ rrc.d_originalttl = 3600;
+ rrc.d_sigexpire = 1440021600;
+ rrc.d_siginception = 1438207200;
+ rrc.d_signer = qname;
+ rrc.d_type = QType::MX;
+ rrc.d_labels = 2;
+ // TODO: derive the next two from the key
+ rrc.d_tag = 9713;
+ rrc.d_algorithm = 16;
+
+ string msg = getMessageForRRSET(qname, rrc, rrs, false);
+
+ // vector extracted from https://gitlab.labs.nic.cz/labs/ietf/blob/master/dnskey.py (rev 476d6ded) by printing signature_data
+ BOOST_CHECK_EQUAL(makeHexDump(msg), "00 0f 10 02 00 00 0e 10 55 d4 fc 60 55 b9 4c e0 25 f1 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 00 0f 00 01 00 00 0e 10 00 14 00 0a 04 6d 61 69 6c 07 65 78 61 6d 70 6c 65 03 63 6f 6d 00 ");
+
+ string signature = engine->sign(msg);
+ string b64 = Base64Encode(signature);
+
+ // vector verified from dnskey.py as above, and confirmed with https://www.rfc-editor.org/errata_search.php?rfc=8080&eid=4935
+ BOOST_CHECK_EQUAL(b64, "3cPAHkmlnxcDHMyg7vFC34l0blBhuG1qpwLmjInI8w1CMB29FkEAIJUA0amxWndkmnBZ6SKiwZSAxGILn/NBtOXft0+Gj7FSvOKxE/07+4RQvE581N3Aj/JtIyaiYVdnYtyMWbSNyGEY2213WKsJlwEA");
+}
+#endif
+
+BOOST_AUTO_TEST_SUITE_END()
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <stdint.h>
+#include "misc.hh"
+#include "dns.hh"
+#include "statbag.hh"
+
+using std::string;
+
+static void *threadMangler(void* a)
+{
+ AtomicCounter* ac=(AtomicCounter*)a;
+ for(unsigned int n=0; n < 1000000; ++n)
+ (*ac)++;
+ return 0;
+}
+
+static void *threadMangler2(void* a)
+{
+ StatBag* S = (StatBag*)a;
+ for(unsigned int n=0; n < 1000000; ++n)
+ S->inc("c");
+ return 0;
+}
+
+
+
+BOOST_AUTO_TEST_SUITE(misc_hh)
+
+BOOST_AUTO_TEST_CASE(test_StatBagBasic) {
+ StatBag s;
+ s.declare("a", "description");
+ s.declare("b", "description");
+ s.declare("c", "description");
+ s.inc("a");
+ BOOST_CHECK_EQUAL(s.read("a"), 1);
+
+ int n;
+ for(n=0; n < 1000000; ++n)
+ s.inc("b");
+
+ BOOST_CHECK_EQUAL(s.read("b"), n);
+
+ AtomicCounter* ac = s.getPointer("a");
+ for(n=0; n < 1000000; ++n)
+ (*ac)++;
+
+ BOOST_CHECK_EQUAL(s.read("a"), n+1);
+
+ AtomicCounter* acc = s.getPointer("c");
+ pthread_t tid[4];
+ for(int i=0; i < 4; ++i)
+ pthread_create(&tid[i], 0, threadMangler, (void*)acc);
+ void* res;
+ for(int i=0; i < 4 ; ++i)
+ pthread_join(tid[i], &res);
+
+ BOOST_CHECK_EQUAL(s.read("c"), 4000000U);
+
+ s.set("c", 0);
+
+ for(int i=0; i < 4; ++i)
+ pthread_create(&tid[i], 0, threadMangler2, (void*)&s);
+
+ for(int i=0; i < 4 ; ++i)
+ pthread_join(tid[i], &res);
+
+ BOOST_CHECK_EQUAL(s.read("c"), 4000000U);
+
+
+ s.set("c", 1ULL<<31);
+ BOOST_CHECK_EQUAL(s.read("c"), (1ULL<<31) );
+ s.inc("c");
+ BOOST_CHECK_EQUAL(s.read("c"), (1ULL<<31) +1 );
+
+#ifdef UINTPTR_MAX
+#if UINTPTR_MAX > 0xffffffffULL
+ BOOST_CHECK_EQUAL(sizeof(AtomicCounterInner), 8);
+ s.set("c", 1ULL<<33);
+ BOOST_CHECK_EQUAL(s.read("c"), (1ULL<<33) );
+ s.inc("c");
+ BOOST_CHECK_EQUAL(s.read("c"), (1ULL<<33) +1 );
+
+ s.set("c", ~0ULL);
+ BOOST_CHECK_EQUAL(s.read("c"), 0xffffffffffffffffULL );
+ s.inc("c");
+ BOOST_CHECK_EQUAL(s.read("c"), 0 );
+#else
+ BOOST_CHECK_EQUAL(sizeof(AtomicCounterInner), 4);
+ BOOST_CHECK_EQUAL(~0UL, 0xffffffffUL);
+ s.set("c", ~0UL);
+ BOOST_CHECK_EQUAL(s.read("c"), 0xffffffffUL );
+ s.inc("c");
+ BOOST_CHECK_EQUAL(s.read("c"), 0 );
+#endif
+#endif
+}
+
+
+BOOST_AUTO_TEST_SUITE_END()
+
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_NO_MAIN
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include <boost/assign/list_of.hpp>
+
+#include <boost/tuple/tuple.hpp>
+#include <boost/iostreams/stream.hpp>
+#include <boost/iostreams/device/file.hpp>
+#include "dns.hh"
+#include "zoneparser-tng.hh"
+#include "dnsrecords.hh"
+#include "dnsname.hh"
+#include <fstream>
+#include <cstdlib>
+
+BOOST_AUTO_TEST_SUITE(test_zoneparser_tng_cc)
+
+BOOST_AUTO_TEST_CASE(test_tng_record_types) {
+ reportAllTypes();
+
+ std::ostringstream pathbuf;
+ const char* p = std::getenv("SRCDIR");
+ if(!p)
+ p = ".";
+ pathbuf << p << "/../regression-tests/zones/unit.test";
+ ZoneParserTNG zp(pathbuf.str(), DNSName("unit.test"));
+ DNSResourceRecord rr;
+
+ ifstream ifs(pathbuf.str());
+
+ while(zp.get(rr)) {
+ // make sure these concur.
+ std::string host, type, data;
+ unsigned int ttl;
+ std::getline(ifs, host, ' ');
+ std::getline(ifs, type, ' ');
+ ttl = pdns_stou(type);
+ std::getline(ifs, type, ' ');
+ std::getline(ifs, type, ' ');
+ std::getline(ifs, data, '\n');
+ // see if these agree
+ BOOST_CHECK_EQUAL(rr.qname.toString(), host);
+ BOOST_CHECK_EQUAL(rr.ttl, ttl);
+ BOOST_CHECK_EQUAL(rr.qtype.getName(), type);
+ if (rr.qtype == QType::SOA)
+ continue; // FIXME400 remove trailing dots from data
+ if (*(rr.content.rbegin()) != '.' && *(data.rbegin()) == '.')
+ BOOST_CHECK_EQUAL(rr.content, std::string(data.begin(),data.end()-1));
+ else
+ BOOST_CHECK_EQUAL(rr.content, data);
+ }
+
+}
+
+BOOST_AUTO_TEST_SUITE_END();
--- /dev/null
+#define BOOST_TEST_DYN_LINK
+#define BOOST_TEST_MAIN
+#define BOOST_TEST_MODULE unit
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/test/unit_test.hpp>
+#include "packetcache.hh"
+StatBag S;
+PacketCache PC;
+
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "packethandler.hh"
+
+void PacketHandler::tkeyHandler(DNSPacket *p, DNSPacket *r) {
+ TKEYRecordContent tkey_in;
+ std::shared_ptr<TKEYRecordContent> tkey_out(new TKEYRecordContent());
+ DNSName name;
+ bool sign = false;
+
+ if (!p->getTKEYRecord(&tkey_in, &name)) {
+ L<<Logger::Error<<"TKEY request but no TKEY RR found"<<endl;
+ r->setRcode(RCode::FormErr);
+ return;
+ }
+
+ // retain original name for response
+ tkey_out->d_error = 0;
+ tkey_out->d_mode = tkey_in.d_mode;
+ tkey_out->d_algo = tkey_in.d_algo;
+ tkey_out->d_inception = time((time_t*)NULL);
+ tkey_out->d_expiration = tkey_out->d_inception+15;
+
+ GssContext ctx(name);
+
+ if (tkey_in.d_mode == 3) { // establish context
+ if (tkey_in.d_algo == DNSName("gss-tsig.")) {
+ std::vector<std::string> meta;
+ DNSName tmpName(name);
+ do {
+ if (B.getDomainMetadata(tmpName, "GSS-ACCEPTOR-PRINCIPAL", meta) && meta.size()>0) {
+ break;
+ }
+ } while(tmpName.chopOff());
+
+ if (meta.size()>0) {
+ ctx.setLocalPrincipal(meta[0]);
+ }
+ // try to get a context
+ if (!ctx.accept(tkey_in.d_key, tkey_out->d_key))
+ tkey_out->d_error = 19;
+ else
+ sign = true;
+ } else {
+ tkey_out->d_error = 21; // BADALGO
+ }
+ } else if (tkey_in.d_mode == 5) { // destroy context
+ if (p->d_havetsig == false) { // unauthenticated
+ if (p->d.opcode == Opcode::Update)
+ r->setRcode(RCode::Refused);
+ else
+ r->setRcode(RCode::NotAuth);
+ return;
+ }
+ if (ctx.valid())
+ ctx.destroy();
+ else
+ tkey_out->d_error = 20; // BADNAME (because we have no support for anything here)
+ } else {
+ if (p->d_havetsig == false && tkey_in.d_mode != 2) { // unauthenticated
+ if (p->d.opcode == Opcode::Update)
+ r->setRcode(RCode::Refused);
+ else
+ r->setRcode(RCode::NotAuth);
+ return;
+ }
+ tkey_out->d_error = 19; // BADMODE
+ }
+
+ tkey_out->d_keysize = tkey_out->d_key.size();
+ tkey_out->d_othersize = tkey_out->d_other.size();
+
+ DNSRecord rec;
+ rec.d_name = name;
+ rec.d_ttl = 0;
+ rec.d_type = QType::TKEY;
+ rec.d_class = QClass::ANY;
+ rec.d_content = tkey_out;
+ rec.d_place = DNSResourceRecord::ANSWER;
+
+ DNSResourceRecord rr(rec);
+ rr.qclass = QClass::ANY;
+ rr.qtype = QType::TKEY;
+ rr.d_place = DNSResourceRecord::ANSWER;
+ r->addRecord(rr);
+
+ if (sign)
+ {
+ TSIGRecordContent trc;
+ trc.d_algoName = DNSName("gss-tsig");
+ trc.d_time = tkey_out->d_inception;
+ trc.d_fudge = 300;
+ trc.d_mac = "";
+ trc.d_origID = p->d.id;
+ trc.d_eRcode = 0;
+ trc.d_otherData = "";
+ // this should cause it to lookup name context
+ r->setTSIGDetails(trc, name, name.toStringNoDot(), "", false);
+ }
+
+ r->commitD();
+}
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "rec-lua-conf.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "ednssubnet.hh"
+#include "dnssecinfra.hh"
+#include "recursor_cache.hh"
+#include "base32.hh"
+#include "root-dnssec.hh"
+
+#include "validate.hh"
+StatBag S;
+
+class TCPResolver : public boost::noncopyable
+{
+public:
+ TCPResolver(ComboAddress addr) : d_rsock(AF_INET, SOCK_STREAM)
+ {
+ d_rsock.connect(addr);
+ }
+
+ string query(const DNSName& qname, uint16_t qtype)
+ {
+ cerr<<"Q "<<qname<<"/"<<DNSRecordContent::NumberToType(qtype)<<endl;
+ vector<uint8_t> packet;
+ DNSPacketWriter pw(packet, qname, qtype);
+
+ // recurse
+ pw.getHeader()->rd=true;
+
+ // we'll do the validation
+ pw.getHeader()->cd=true;
+ pw.getHeader()->ad=true;
+
+ // we do require DNSSEC records to do that!
+ pw.addOpt(2800, 0, EDNSOpts::DNSSECOK);
+ pw.commit();
+
+ uint16_t len;
+ len = htons(packet.size());
+ if(d_rsock.write((char *) &len, 2) != 2)
+ throw PDNSException("tcp write failed");
+
+ d_rsock.writen(string((char*)&*packet.begin(), (char*)&*packet.end()));
+
+ int bread=d_rsock.read((char *) &len, 2);
+ if( bread <0)
+ throw PDNSException("tcp read failed: "+std::string(strerror(errno)));
+ if(bread != 2)
+ throw PDNSException("EOF on TCP read");
+
+ len=ntohs(len);
+ char *creply = new char[len];
+ int n=0;
+ int numread;
+ while(n<len) {
+ numread=d_rsock.read(creply+n, len-n);
+ if(numread<0) {
+ delete[] creply;
+ throw PDNSException("tcp read failed: "+std::string(strerror(errno)));
+ }
+ n+=numread;
+ }
+
+ string reply(creply, len);
+ delete[] creply;
+
+ return reply;
+ }
+
+ Socket d_rsock;
+};
+
+
+class TCPRecordOracle : public DNSRecordOracle
+{
+public:
+ TCPRecordOracle(const ComboAddress& dest) : d_dest(dest) {}
+ vector<DNSRecord> get(const DNSName& qname, uint16_t qtype) override
+ {
+ TCPResolver tr(d_dest);
+ string resp=tr.query(qname, qtype);
+ MOADNSParser mdp(false, resp);
+ vector<DNSRecord> ret;
+ ret.reserve(mdp.d_answers.size());
+ for(const auto& a : mdp.d_answers) {
+ ret.push_back(a.first);
+ }
+ return ret;
+ }
+private:
+ ComboAddress d_dest;
+};
+
+GlobalStateHolder<LuaConfigItems> g_luaconfs;
+LuaConfigItems::LuaConfigItems()
+{
+ for (const auto &dsRecord : rootDSs) {
+ auto ds=unique_ptr<DSRecordContent>(dynamic_cast<DSRecordContent*>(DSRecordContent::make(dsRecord)));
+ dsAnchors[DNSName(".")].insert(*ds);
+ }
+}
+
+DNSFilterEngine::DNSFilterEngine() {}
+
+int main(int argc, char** argv)
+try
+{
+ reportAllTypes();
+// g_rootDS = "19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5";
+
+// if(argv[5])
+// g_rootDS = argv[5];
+
+ // g_anchors.insert(DSRecordContent("19036 8 2 49aac11d7b6f6446702e54a1607371607a1a41855200fd2ce1cdde32f24e8fb5"));
+ if(argc < 4) {
+ cerr<<"Syntax: toysdig IP-address port question question-type [rootDS]\n";
+ exit(EXIT_FAILURE);
+ }
+ ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
+ TCPRecordOracle tro(dest);
+ DNSName qname(argv[3]);
+ uint16_t qtype=DNSRecordContent::TypeToNumber(argv[4]);
+ cout<<"digraph oneshot {"<<endl;
+
+ auto recs=tro.get(qname, qtype);
+
+ cspmap_t cspmap=harvestCSPFromRecs(recs);
+ cerr<<"Got "<<cspmap.size()<<" RRSETs: ";
+ int numsigs=0;
+ for(const auto& csp : cspmap) {
+ cerr<<" "<<csp.first.first<<'/'<<DNSRecordContent::NumberToType(csp.first.second)<<": "<<csp.second.signatures.size()<<" sigs for "<<csp.second.records.size()<<" records"<<endl;
+ numsigs+= csp.second.signatures.size();
+ }
+
+ set<DNSKEYRecordContent> keys;
+ cspmap_t validrrsets;
+
+ if(numsigs) {
+ for(const auto& csp : cspmap) {
+ for(const auto& sig : csp.second.signatures) {
+ cerr<<"got rrsig "<<sig->d_signer<<"/"<<sig->d_tag<<endl;
+ vState state = getKeysFor(tro, sig->d_signer, keys);
+ cerr<<"! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys at "<<qname<<endl;
+ // dsmap.insert(make_pair(dsrc.d_tag, dsrc));
+ }
+ }
+
+ validateWithKeySet(cspmap, validrrsets, keys);
+ }
+ else {
+ cerr<<"no sigs, hoping for Insecure"<<endl;
+ vState state = getKeysFor(tro, qname, keys);
+ cerr<<"! state = "<<vStates[state]<<", now have "<<keys.size()<<" keys at "<<qname<<endl;
+ }
+ cerr<<"! validated "<<validrrsets.size()<<" RRsets out of "<<cspmap.size()<<endl;
+
+ cerr<<"% validated RRs:"<<endl;
+ for(auto i=validrrsets.begin(); i!=validrrsets.end(); i++) {
+ cerr<<"% "<<i->first.first<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<endl;
+ for(auto j=i->second.records.begin(); j!=i->second.records.end(); j++) {
+ cerr<<"\t% > "<<(*j)->getZoneRepresentation()<<endl;
+ }
+ }
+
+ cout<<"}"<<endl;
+ exit(0);
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+}
+catch(PDNSException &pe)
+{
+ cerr<<"Fatal: "<<pe.reason<<endl;
+}
+
--- /dev/null
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "dnswriter.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "statbag.hh"
+#include "md5.hh"
+#include "base64.hh"
+#include "dnssecinfra.hh"
+#include "resolver.hh"
+#include "arguments.hh"
+#include "dns_random.hh"
+
+StatBag S;
+
+ArgvMap& arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+int main(int argc, char** argv)
+try
+{
+ ::arg().set("query-local-address","Source IP address for sending queries")="0.0.0.0";
+ ::arg().set("query-local-address6","Source IPv6 address for sending queries")="::";
+
+ reportAllTypes();
+
+ if(argc < 4) {
+ cerr<<"tsig-tests: ask a TSIG signed question, verify the TSIG signed answer"<<endl;
+ cerr<<"Syntax: tsig IP-address port question question-type\n";
+ exit(EXIT_FAILURE);
+ }
+
+ vector<uint8_t> packet;
+
+ DNSPacketWriter pw(packet, DNSName(argv[3]), DNSRecordContent::TypeToNumber(argv[4]));
+
+ pw.getHeader()->id=htons(0x4831);
+
+ string key;
+ B64Decode("Syq9L9WrBWdxBC+HxKok2g==", key);
+
+ DNSName keyname("pdns-b-aa");
+
+ TSIGRecordContent trc;
+ trc.d_algoName=DNSName("hmac-md5.sig-alg.reg.int");
+ trc.d_time=time(0);
+ trc.d_fudge=300;
+ trc.d_origID=ntohs(pw.getHeader()->id);
+ trc.d_eRcode=0;
+
+ addTSIG(pw, &trc, keyname, key, "", false);
+
+ Socket sock(AF_INET, SOCK_DGRAM);
+ ComboAddress dest(argv[1] + (*argv[1]=='@'), atoi(argv[2]));
+#if 0
+ sock.sendTo(string((char*)&*packet.begin(), (char*)&*packet.end()), dest);
+
+ string reply;
+ sock.recvFrom(reply, dest);
+
+ MOADNSParser mdp(false, reply);
+ cout<<"Reply to question for qname='"<<mdp.d_qname<<"', qtype="<<DNSRecordContent::NumberToType(mdp.d_qtype)<<endl;
+ cout<<"Rcode: "<<mdp.d_header.rcode<<", RD: "<<mdp.d_header.rd<<", QR: "<<mdp.d_header.qr;
+ cout<<", TC: "<<mdp.d_header.tc<<", AA: "<<mdp.d_header.aa<<", opcode: "<<mdp.d_header.opcode<<endl;
+
+ shared_ptr<TSIGRecordContent> trc2;
+
+ for(MOADNSParser::answers_t::const_iterator i=mdp.d_answers.begin(); i!=mdp.d_answers.end(); ++i) {
+ cout<<i->first.d_place-1<<"\t"<<i->first.d_label<<"\tIN\t"<<DNSRecordContent::NumberToType(i->first.d_type, i->first.d_class);
+ cout<<"\t"<<i->first.d_ttl<<"\t"<< i->first.d_content->getZoneRepresentation()<<"\n";
+
+ if(i->first.d_type == QType::TSIG)
+ trc2 = std::dynamic_pointer_cast<TSIGRecordContent>(i->first.d_content);
+ }
+
+ if(mdp.getTSIGPos()) {
+ string message = makeTSIGMessageFromTSIGPacket(reply, mdp.getTSIGPos(), keyname, trc, trc.d_mac, false); // insert our question MAC
+
+ string hmac2=calculateMD5HMAC(key, message);
+ cerr<<"Calculated mac: "<<Base64Encode(hmac2)<<endl;
+ if(hmac2 == trc2->d_mac)
+ cerr<<"MATCH!"<<endl;
+ else
+ cerr<<"Mismatch!"<<endl;
+ }
+#endif
+ seedRandom("/dev/urandom");
+ cerr<<"Keyname: '"<<keyname.toString()<<"', algo: '"<<trc.d_algoName.toString()<<"', key: '"<<Base64Encode(key)<<"'\n";
+ TSIGTriplet tt;
+ tt.name=keyname;
+ tt.algo=DNSName("hmac-md5");
+ tt.secret=key;
+ AXFRRetriever axfr(dest, DNSName("b.aa"), tt);
+ vector<DNSResourceRecord> res;
+ while(axfr.getChunk(res)) {
+ }
+ return 0;
+}
+catch(std::exception &e)
+{
+ cerr<<"Fatal: "<<e.what()<<endl;
+ return 1;
+}
+catch(PDNSException& ae)
+{
+ cerr<<"Fatal 2: "<<ae.reason<<endl;
+ return 1;
+}
--- /dev/null
+
+#include "tsigverifier.hh"
+#include "dnssecinfra.hh"
+#include "gss_context.hh"
+
+bool TSIGTCPVerifier::check(const string& data, const MOADNSParser& mdp)
+{
+ if(d_tt.name.empty()) { // TSIG verify message
+ return true;
+ }
+
+ string theirMac;
+ bool checkTSIG = false;
+ // If we have multiple messages, we need to concatenate them together. We also need to make sure we know the location of
+ // the TSIG record so we can remove it in makeTSIGMessageFromTSIGPacket
+ d_signData.append(data);
+ if (mdp.getTSIGPos() == 0) {
+ d_tsigPos += data.size();
+ }
+ else {
+ d_tsigPos += mdp.getTSIGPos();
+ }
+
+ for(const auto& answer : mdp.d_answers) {
+ if (answer.first.d_type == QType::SOA) {
+ // A SOA is either the first or the last record. We need to check TSIG if that's the case.
+ checkTSIG = true;
+ }
+
+ if(answer.first.d_type == QType::TSIG) {
+ shared_ptr<TSIGRecordContent> trc = getRR<TSIGRecordContent>(answer.first);
+ if(trc) {
+ theirMac = trc->d_mac;
+ d_trc.d_time = trc->d_time;
+ d_trc.d_fudge = trc->d_fudge;
+ checkTSIG = true;
+ }
+ }
+ }
+
+ if(!checkTSIG && d_nonSignedMessages > 99) { // We're allowed to get 100 digest without a TSIG.
+ throw std::runtime_error("No TSIG message received in last 100 messages of AXFR transfer.");
+ }
+
+ if (checkTSIG) {
+ if (theirMac.empty()) {
+ throw std::runtime_error("No TSIG on AXFR response from "+d_remote.toStringWithPort()+" , should be signed with TSIG key '"+d_tt.name.toString()+"'");
+ }
+
+ uint64_t delta = std::abs((int64_t)d_trc.d_time - (int64_t)time(nullptr));
+ if(delta > d_trc.d_fudge) {
+ throw std::runtime_error("Invalid TSIG time delta " + std::to_string(delta) + " > fudge " + std::to_string(d_trc.d_fudge));
+ }
+ string message;
+ if (!d_prevMac.empty()) {
+ message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_prevMac, true, d_signData.size()-data.size());
+ } else {
+ message = makeTSIGMessageFromTSIGPacket(d_signData, d_tsigPos, d_tt.name, d_trc, d_trc.d_mac, false);
+ }
+
+ TSIGHashEnum algo;
+ if (!getTSIGHashEnum(d_trc.d_algoName, algo)) {
+ throw std::runtime_error("Unsupported TSIG HMAC algorithm " + d_trc.d_algoName.toString());
+ }
+
+ if (algo == TSIG_GSS) {
+ GssContext gssctx(d_tt.name);
+ if (!gss_verify_signature(d_tt.name, message, theirMac)) {
+ throw std::runtime_error("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'");
+ }
+ } else {
+ string ourMac=calculateHMAC(d_tt.secret, message, algo);
+
+ if(!constantTimeStringEquals(ourMac, theirMac)) {
+ throw std::runtime_error("Signature failed to validate on AXFR response from "+d_remote.toStringWithPort()+" signed with TSIG key '"+d_tt.name.toString()+"'");
+ }
+ }
+
+ // Reset and store some values for the next chunks.
+ d_prevMac = theirMac;
+ d_nonSignedMessages = 0;
+ d_signData.clear();
+ d_tsigPos = 0;
+ }
+ else
+ d_nonSignedMessages++;
+
+ return true;
+}
--- /dev/null
+
+#pragma once
+
+#include "dnsrecords.hh"
+#include "iputils.hh"
+
+class TSIGTCPVerifier
+{
+public:
+ TSIGTCPVerifier(const TSIGTriplet& tt, const ComboAddress& remote, TSIGRecordContent& trc): d_tt(tt), d_remote(remote), d_trc(trc)
+ {
+ }
+ bool check(const string& data, const MOADNSParser& mdp);
+private:
+ const TSIGTriplet& d_tt;
+ const ComboAddress& d_remote;
+ TSIGRecordContent& d_trc;
+ string d_prevMac; // RFC2845 4.4
+ string d_signData;
+ size_t d_tsigPos{0};
+ uint8_t d_nonSignedMessages{0}; // RFC2845 4.4
+};
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2005 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <boost/archive/binary_iarchive.hpp>
+#include <boost/archive/binary_oarchive.hpp>
+
+#include "packetcache.hh"
+#include "utility.hh"
+
+
+#include <string>
+#include <map>
+#include <sys/types.h>
+#include <sstream>
+#include <errno.h>
+#include <iostream>
+#include <sstream>
+#include <functional>
+
+#include "dns.hh"
+#include "arguments.hh"
+#include "dnsbackend.hh"
+#include "ueberbackend.hh"
+#include "dnspacket.hh"
+#include "logger.hh"
+#include "statbag.hh"
+
+extern StatBag S;
+
+vector<UeberBackend *>UeberBackend::instances;
+pthread_mutex_t UeberBackend::instances_lock=PTHREAD_MUTEX_INITIALIZER;
+
+sem_t UeberBackend::d_dynserialize;
+
+// initially we are blocked
+bool UeberBackend::d_go=false;
+pthread_mutex_t UeberBackend::d_mut = PTHREAD_MUTEX_INITIALIZER;
+pthread_cond_t UeberBackend::d_cond = PTHREAD_COND_INITIALIZER;
+
+//! Loads a module and reports it to all UeberBackend threads
+bool UeberBackend::loadmodule(const string &name)
+{
+ L<<Logger::Warning <<"Loading '"<<name<<"'" << endl;
+
+ void *dlib=dlopen(name.c_str(), RTLD_NOW);
+
+ if(dlib == NULL) {
+ L<<Logger::Error <<"Unable to load module '"<<name<<"': "<<dlerror() << endl;
+ return false;
+ }
+
+ return true;
+}
+
+void UeberBackend::go(void)
+{
+ pthread_mutex_lock(&d_mut);
+ d_go=true;
+ pthread_cond_broadcast(&d_cond);
+ pthread_mutex_unlock(&d_mut);
+}
+
+bool UeberBackend::getDomainInfo(const DNSName &domain, DomainInfo &di)
+{
+ for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
+ if((*i)->getDomainInfo(domain, di))
+ return true;
+ return false;
+}
+
+bool UeberBackend::createDomain(const DNSName &domain)
+{
+ for(DNSBackend* mydb : backends) {
+ if(mydb->createDomain(domain)) {
+ return true;
+ }
+ }
+ return false;
+}
+
+bool UeberBackend::doesDNSSEC()
+{
+ for(auto* db : backends) {
+ if(db->doesDNSSEC())
+ return true;
+ }
+ return false;
+}
+
+int UeberBackend::addDomainKey(const DNSName& name, const DNSBackend::KeyData& key)
+{
+ int ret;
+ for(DNSBackend* db : backends) {
+ if((ret = db->addDomainKey(name, key)) >= 0)
+ return ret;
+ }
+ return -1;
+}
+bool UeberBackend::getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys)
+{
+ for(DNSBackend* db : backends) {
+ if(db->getDomainKeys(name, kind, keys))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta)
+{
+ for(DNSBackend* db : backends) {
+ if(db->getAllDomainMetadata(name, meta))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta)
+{
+ for(DNSBackend* db : backends) {
+ if(db->getDomainMetadata(name, kind, meta))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta)
+{
+ for(DNSBackend* db : backends) {
+ if(db->setDomainMetadata(name, kind, meta))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::activateDomainKey(const DNSName& name, unsigned int id)
+{
+ for(DNSBackend* db : backends) {
+ if(db->activateDomainKey(name, id))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::deactivateDomainKey(const DNSName& name, unsigned int id)
+{
+ for(DNSBackend* db : backends) {
+ if(db->deactivateDomainKey(name, id))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::removeDomainKey(const DNSName& name, unsigned int id)
+{
+ for(DNSBackend* db : backends) {
+ if(db->removeDomainKey(name, id))
+ return true;
+ }
+ return false;
+}
+
+
+bool UeberBackend::getTSIGKey(const DNSName& name, DNSName* algorithm, string* content)
+{
+ for(DNSBackend* db : backends) {
+ if(db->getTSIGKey(name, algorithm, content))
+ return true;
+ }
+ return false;
+}
+
+
+bool UeberBackend::setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content)
+{
+ for(DNSBackend* db : backends) {
+ if(db->setTSIGKey(name, algorithm, content))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::deleteTSIGKey(const DNSName& name)
+{
+ for(DNSBackend* db : backends) {
+ if(db->deleteTSIGKey(name))
+ return true;
+ }
+ return false;
+}
+
+bool UeberBackend::getTSIGKeys(std::vector< struct TSIGKey > &keys)
+{
+ for(DNSBackend* db : backends) {
+ db->getTSIGKeys(keys);
+ }
+ return true;
+}
+
+void UeberBackend::reload()
+{
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ ( *i )->reload();
+ }
+}
+
+void UeberBackend::rediscover(string *status)
+{
+
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ string tmpstr;
+ ( *i )->rediscover(&tmpstr);
+ if(status)
+ *status+=tmpstr + (i!=backends.begin() ? "\n" : "");
+ }
+}
+
+
+void UeberBackend::getUnfreshSlaveInfos(vector<DomainInfo>* domains)
+{
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ ( *i )->getUnfreshSlaveInfos( domains );
+ }
+}
+
+
+
+void UeberBackend::getUpdatedMasters(vector<DomainInfo>* domains)
+{
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ ( *i )->getUpdatedMasters( domains );
+ }
+}
+
+bool UeberBackend::getAuth(DNSPacket *p, SOAData *sd, const DNSName &target)
+{
+ bool found = false;
+ int cstat;
+ DNSName choppedOff(target);
+ vector<pair<size_t, SOAData> > bestmatch (backends.size(), make_pair(target.wirelength()+1, SOAData()));
+ do {
+
+ // Check cache
+ if(sd->db != (DNSBackend *)-1 && (d_cache_ttl || d_negcache_ttl)) {
+ d_question.qtype = QType::SOA;
+ d_question.qname = choppedOff;
+ d_question.zoneId = -1;
+
+ cstat = cacheHas(d_question,d_answers);
+
+ if(cstat == 1 && !d_answers.empty() && d_cache_ttl) {
+ DLOG(L<<Logger::Error<<"has pos cache entry: "<<choppedOff<<endl);
+ fillSOAData(d_answers[0].content, *sd);
+ sd->domain_id = d_answers[0].domain_id;
+ sd->ttl = d_answers[0].ttl;
+ sd->db = 0;
+ sd->qname = choppedOff;
+ goto found;
+ } else if(cstat == 0 && d_negcache_ttl) {
+ DLOG(L<<Logger::Error<<"has neg cache entry: "<<choppedOff<<endl);
+ continue;
+ }
+ }
+
+ // Check backends
+ // A backend can respond to our SOA request with the 'best'
+ // match it has. For example, when asked the SOA for a.b.c.powerdns.com.
+ // it might respond with the SOA for powerdns.com.
+ // We then store that, keep querying the other backends in case
+ // one of them has a more specific SOA but don't bother
+ // asking this specific backend again for b.c.powerdns.com. or c.powerdns.com.
+ {
+ vector<DNSBackend *>::const_iterator i = backends.begin();
+ vector<pair<size_t, SOAData> >::iterator j = bestmatch.begin();
+ for(; i != backends.end() && j != bestmatch.end(); ++i, ++j) {
+
+ DLOG(L<<Logger::Error<<"backend: "<<i-backends.begin()<<", qname: "<<choppedOff<<endl);
+
+ if(j->first < choppedOff.wirelength()) {
+ DLOG(L<<Logger::Error<<"skip this backend, we already know the 'higher' match: "<<j->second.qname<<endl);
+ continue;
+ } else if(j->first == choppedOff.wirelength()) {
+ DLOG(L<<Logger::Error<<"use 'higher' match: "<<j->second.qname<<endl);
+ *sd = j->second;
+ break;
+ } else {
+ DLOG(L<<Logger::Error<<"lookup: "<<choppedOff<<endl);
+ if((*i)->getAuth(p, sd, choppedOff)) {
+ DLOG(L<<Logger::Error<<"got: "<<sd->qname<<endl);
+ j->first = sd->qname.wirelength();
+ j->second = *sd;
+ if(sd->qname == choppedOff) {
+ break;
+ }
+ } else {
+ DLOG(L<<Logger::Error<<"no match for: "<<choppedOff<<endl);
+ }
+ }
+ }
+
+ // Add to cache
+ if(i == backends.end()) {
+ if(d_negcache_ttl) {
+ DLOG(L<<Logger::Error<<"add neg cache entry:"<<choppedOff<<endl);
+ d_question.qname=choppedOff;
+ addNegCache(d_question);
+ }
+ continue;
+ } else if(d_cache_ttl) {
+ DLOG(L<<Logger::Error<<"add pos cache entry: "<<sd->qname<<endl);
+ d_question.qtype = QType::SOA;
+ d_question.qname = sd->qname;
+ d_question.zoneId = -1;
+
+ DNSResourceRecord rr;
+ rr.qname = sd->qname;
+ rr.qtype = QType::SOA;
+ rr.content = serializeSOAData(*sd);
+ rr.ttl = sd->ttl;
+ rr.domain_id = sd->domain_id;
+ vector<DNSResourceRecord> rrs;
+ rrs.push_back(rr);
+ addCache(d_question, rrs);
+ }
+ }
+
+found:
+ if(found == (p->qtype == QType::DS)){
+ DLOG(L<<Logger::Error<<"found: "<<sd->qname<<endl);
+ return true;
+ } else {
+ DLOG(L<<Logger::Error<<"chasing next: "<<sd->qname<<endl);
+ found = true;
+ }
+
+ } while(choppedOff.chopOff());
+ return found;
+}
+
+bool UeberBackend::getSOA(const DNSName &domain, SOAData &sd, DNSPacket *p)
+{
+ d_question.qtype=QType::SOA;
+ d_question.qname=domain;
+ d_question.zoneId=-1;
+
+ int cstat=cacheHas(d_question,d_answers);
+ if(cstat==0) { // negative
+ return false;
+ }
+ else if(cstat==1 && !d_answers.empty()) {
+ fillSOAData(d_answers[0].content,sd);
+ sd.domain_id=d_answers[0].domain_id;
+ sd.ttl=d_answers[0].ttl;
+ sd.db=0;
+ return true;
+ }
+
+ // not found in neg. or pos. cache, look it up
+ return getSOAUncached(domain, sd, p);
+}
+
+bool UeberBackend::getSOAUncached(const DNSName &domain, SOAData &sd, DNSPacket *p)
+{
+ d_question.qtype=QType::SOA;
+ d_question.qname=domain;
+ d_question.zoneId=-1;
+
+ for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
+ if((*i)->getSOA(domain, sd, p)) {
+ if( d_cache_ttl ) {
+ DNSResourceRecord rr;
+ rr.qname=domain;
+ rr.qtype=QType::SOA;
+ rr.content=serializeSOAData(sd);
+ rr.ttl=sd.ttl;
+ rr.domain_id=sd.domain_id;
+ vector<DNSResourceRecord> rrs;
+ rrs.push_back(rr);
+ addCache(d_question, rrs);
+ }
+ return true;
+ }
+
+ if(d_negcache_ttl)
+ addNegCache(d_question);
+ return false;
+}
+
+bool UeberBackend::superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db)
+{
+ for(vector<DNSBackend *>::const_iterator i=backends.begin();i!=backends.end();++i)
+ if((*i)->superMasterBackend(ip, domain, nsset, nameserver, account, db))
+ return true;
+ return false;
+}
+
+UeberBackend::UeberBackend(const string &pname)
+{
+ pthread_mutex_lock(&instances_lock);
+ instances.push_back(this); // report to the static list of ourself
+ pthread_mutex_unlock(&instances_lock);
+
+ d_negcached=0;
+ d_ancount=0;
+ domain_id=-1;
+ d_cached=0;
+ d_cache_ttl = ::arg().asNum("query-cache-ttl");
+ d_negcache_ttl = ::arg().asNum("negquery-cache-ttl");
+
+ tid=pthread_self();
+ stale=false;
+
+ backends=BackendMakers().all(pname=="key-only");
+}
+
+void del(DNSBackend* d)
+{
+ delete d;
+}
+
+void UeberBackend::cleanup()
+{
+ pthread_mutex_lock(&instances_lock);
+
+ remove(instances.begin(),instances.end(),this);
+ instances.resize(instances.size()-1);
+
+ pthread_mutex_unlock(&instances_lock);
+
+ for_each(backends.begin(),backends.end(),del);
+}
+
+// silly Solaris fix
+#undef PC
+
+// returns -1 for miss, 0 for negative match, 1 for hit
+int UeberBackend::cacheHas(const Question &q, vector<DNSResourceRecord> &rrs)
+{
+ extern PacketCache PC;
+ static AtomicCounter *qcachehit=S.getPointer("query-cache-hit");
+ static AtomicCounter *qcachemiss=S.getPointer("query-cache-miss");
+
+ if(!d_cache_ttl && ! d_negcache_ttl) {
+ (*qcachemiss)++;
+ return -1;
+ }
+
+ rrs.clear();
+ // L<<Logger::Warning<<"looking up: '"<<q.qname+"'|N|"+q.qtype.getName()+"|"+itoa(q.zoneId)<<endl;
+
+ bool ret=PC.getEntry(q.qname, q.qtype, PacketCache::QUERYCACHE, rrs, q.zoneId); // think about lowercasing here
+ if(!ret) {
+ (*qcachemiss)++;
+ return -1;
+ }
+ (*qcachehit)++;
+ if(rrs.empty()) // negatively cached
+ return 0;
+
+ return 1;
+}
+
+void UeberBackend::addNegCache(const Question &q)
+{
+ extern PacketCache PC;
+ if(!d_negcache_ttl)
+ return;
+ // we should also not be storing negative answers if a pipebackend does scopeMask, but we can't pass a negative scopeMask in an empty set!
+ PC.insert(q.qname, q.qtype, PacketCache::QUERYCACHE, vector<DNSResourceRecord>(), d_negcache_ttl, q.zoneId);
+}
+
+void UeberBackend::addCache(const Question &q, const vector<DNSResourceRecord> &rrs)
+{
+ extern PacketCache PC;
+
+ if(!d_cache_ttl)
+ return;
+
+ unsigned int store_ttl = d_cache_ttl;
+ for(const DNSResourceRecord& rr : rrs) {
+ if (rr.ttl < d_cache_ttl)
+ store_ttl = rr.ttl;
+ if (rr.scopeMask)
+ return;
+ }
+
+ PC.insert(q.qname, q.qtype, PacketCache::QUERYCACHE, rrs, store_ttl, q.zoneId);
+}
+
+void UeberBackend::alsoNotifies(const DNSName &domain, set<string> *ips)
+{
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); i != backends.end(); ++i )
+ (*i)->alsoNotifies(domain,ips);
+}
+
+UeberBackend::~UeberBackend()
+{
+ DLOG(L<<Logger::Error<<"UeberBackend destructor called, removing ourselves from instances, and deleting our backends"<<endl);
+ cleanup();
+}
+
+// this handle is more magic than most
+void UeberBackend::lookup(const QType &qtype,const DNSName &qname, DNSPacket *pkt_p, int zoneId)
+{
+ if(stale) {
+ L<<Logger::Error<<"Stale ueberbackend received question, signalling that we want to be recycled"<<endl;
+ throw PDNSException("We are stale, please recycle");
+ }
+
+ DLOG(L<<"UeberBackend received question for "<<qtype.getName()<<" of "<<qname<<endl);
+ if(!d_go) {
+ pthread_mutex_lock(&d_mut);
+ while (d_go==false) {
+ L<<Logger::Error<<"UeberBackend is blocked, waiting for 'go'"<<endl;
+ pthread_cond_wait(&d_cond, &d_mut);
+ L<<Logger::Error<<"Broadcast received, unblocked"<<endl;
+ }
+ pthread_mutex_unlock(&d_mut);
+ }
+
+ domain_id=zoneId;
+
+ d_handle.i=0;
+ d_handle.qtype=qtype;
+ d_handle.qname=qname;
+ d_handle.pkt_p=pkt_p;
+ d_ancount=0;
+
+ if(!backends.size()) {
+ L<<Logger::Error<<"No database backends available - unable to answer questions."<<endl;
+ stale=true; // please recycle us!
+ throw PDNSException("We are stale, please recycle");
+ }
+ else {
+ d_question.qtype=qtype;
+ d_question.qname=qname;
+ d_question.zoneId=zoneId;
+ int cstat=cacheHas(d_question, d_answers);
+ if(cstat<0) { // nothing
+ d_negcached=d_cached=false;
+ d_answers.clear();
+ (d_handle.d_hinterBackend=backends[d_handle.i++])->lookup(qtype, qname,pkt_p,zoneId);
+ }
+ else if(cstat==0) {
+ d_negcached=true;
+ d_cached=false;
+ d_answers.clear();
+ }
+ else {
+ d_negcached=false;
+ d_cached=true;
+ d_cachehandleiter = d_answers.begin();
+ }
+ }
+
+ d_handle.parent=this;
+}
+
+void UeberBackend::getAllDomains(vector<DomainInfo> *domains, bool include_disabled) {
+ for (vector<DNSBackend*>::iterator i = backends.begin(); i != backends.end(); ++i )
+ {
+ (*i)->getAllDomains(domains, include_disabled);
+ }
+}
+
+bool UeberBackend::get(DNSResourceRecord &rr)
+{
+ if(d_negcached) {
+ return false;
+ }
+
+ if(d_cached) {
+ if(d_cachehandleiter != d_answers.end()) {
+ rr=*d_cachehandleiter++;;
+ return true;
+ }
+ return false;
+ }
+ if(!d_handle.get(rr)) {
+ if(!d_ancount && d_handle.qname.countLabels()) // don't cache axfr
+ addNegCache(d_question);
+
+ addCache(d_question, d_answers);
+ d_answers.clear();
+ return false;
+ }
+ d_ancount++;
+ d_answers.push_back(rr);
+ return true;
+}
+
+bool UeberBackend::list(const DNSName &target, int domain_id, bool include_disabled)
+{
+ L<<Logger::Error<<"UeberBackend::list called, should NEVER EVER HAPPEN"<<endl;
+ exit(1);
+ return false;
+}
+
+bool UeberBackend::searchRecords(const string& pattern, int maxResults, vector<DNSResourceRecord>& result)
+{
+ bool rc = false;
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<DNSResourceRecord>::size_type>(maxResults) && i != backends.end(); ++i )
+ if ((*i)->searchRecords(pattern, maxResults - result.size(), result)) rc = true;
+ return rc;
+}
+
+bool UeberBackend::searchComments(const string& pattern, int maxResults, vector<Comment>& result)
+{
+ bool rc = false;
+ for ( vector< DNSBackend * >::iterator i = backends.begin(); result.size() < static_cast<vector<Comment>::size_type>(maxResults) && i != backends.end(); ++i )
+ if ((*i)->searchComments(pattern, maxResults - result.size(), result)) rc = true;
+ return rc;
+}
+
+AtomicCounter UeberBackend::handle::instances(0);
+
+UeberBackend::handle::handle()
+{
+ // L<<Logger::Warning<<"Handle instances: "<<instances<<endl;
+ ++instances;
+ parent=NULL;
+ d_hinterBackend=NULL;
+ pkt_p=NULL;
+ i=0;
+}
+
+UeberBackend::handle::~handle()
+{
+ --instances;
+}
+
+bool UeberBackend::handle::get(DNSResourceRecord &r)
+{
+ DLOG(L << "Ueber get() was called for a "<<qtype.getName()<<" record" << endl);
+ bool isMore=false;
+ while(d_hinterBackend && !(isMore=d_hinterBackend->get(r))) { // this backend out of answers
+ if(i<parent->backends.size()) {
+ DLOG(L<<"Backend #"<<i<<" of "<<parent->backends.size()
+ <<" out of answers, taking next"<<endl);
+
+ d_hinterBackend=parent->backends[i++];
+ d_hinterBackend->lookup(qtype,qname,pkt_p,parent->domain_id);
+ }
+ else
+ break;
+
+ DLOG(L<<"Now asking backend #"<<i<<endl);
+ }
+
+ if(!isMore && i==parent->backends.size()) {
+ DLOG(L<<"UeberBackend reached end of backends"<<endl);
+ return false;
+ }
+
+ DLOG(L<<"Found an answering backend - will not try another one"<<endl);
+ i=parent->backends.size(); // don't go on to the next backend
+ return true;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef UEBERBACKEND_HH
+#define UEBERBACKEND_HH
+
+#include <vector>
+#include <map>
+#include <string>
+#include <algorithm>
+#include <pthread.h>
+#include <semaphore.h>
+
+#include <sys/un.h>
+#include <dlfcn.h>
+#include <unistd.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <boost/utility.hpp>
+#include "dnspacket.hh"
+#include "dnsbackend.hh"
+
+#include "namespaces.hh"
+
+/** This is a very magic backend that allows us to load modules dynamically,
+ and query them in order. This is persistent over all UeberBackend instantiations
+ across multiple threads.
+
+ The UeberBackend is transparent for exceptions, which should fall straight through.
+*/
+
+class UeberBackend : public boost::noncopyable
+{
+public:
+ UeberBackend(const string &pname="default");
+ ~UeberBackend();
+ typedef DNSBackend *BackendMaker(); //!< typedef for functions returning pointers to new backends
+
+ bool superMasterBackend(const string &ip, const DNSName &domain, const vector<DNSResourceRecord>&nsset, string *nameserver, string *account, DNSBackend **db);
+
+ /** Tracks all created UeberBackend instances for us. We use this vector to notify
+ existing threads of new modules
+ */
+ static vector<UeberBackend *>instances;
+ static pthread_mutex_t instances_lock;
+
+ static bool loadmodule(const string &name);
+
+ static void go(void);
+
+ /** This contains all registered backends. The DynListener modifies this list for us when
+ new modules are loaded */
+ vector<DNSBackend*> backends;
+
+ void cleanup();
+
+ //! the very magic handle for UeberBackend questions
+ class handle
+ {
+ public:
+ bool get(DNSResourceRecord &r);
+ handle();
+ ~handle();
+
+ //! The UeberBackend class where this handle belongs to
+ UeberBackend *parent;
+ //! The current real backend, which is answering questions
+ DNSBackend *d_hinterBackend;
+
+ //! DNSPacket who asked this question
+ DNSPacket *pkt_p;
+ DNSName qname;
+
+ //! Index of the current backend within the backends vector
+ unsigned int i;
+ QType qtype;
+
+ private:
+
+ static AtomicCounter instances;
+ };
+
+ void lookup(const QType &, const DNSName &qdomain, DNSPacket *pkt_p=0, int zoneId=-1);
+
+ bool getAuth(DNSPacket *p, SOAData *sd, const DNSName &target);
+ bool getSOA(const DNSName &domain, SOAData &sd, DNSPacket *p=0);
+ bool getSOAUncached(const DNSName &domain, SOAData &sd, DNSPacket *p=0); // same, but ignores cache
+ bool list(const DNSName &target, int domain_id, bool include_disabled=false);
+ bool get(DNSResourceRecord &r);
+ void getAllDomains(vector<DomainInfo> *domains, bool include_disabled=false);
+
+ static DNSBackend *maker(const map<string,string> &);
+ void getUnfreshSlaveInfos(vector<DomainInfo>* domains);
+ void getUpdatedMasters(vector<DomainInfo>* domains);
+ bool getDomainInfo(const DNSName &domain, DomainInfo &di);
+ bool createDomain(const DNSName &domain);
+
+ bool doesDNSSEC();
+ int addDomainKey(const DNSName& name, const DNSBackend::KeyData& key);
+ bool getDomainKeys(const DNSName& name, unsigned int kind, std::vector<DNSBackend::KeyData>& keys);
+ bool getAllDomainMetadata(const DNSName& name, std::map<std::string, std::vector<std::string> >& meta);
+ bool getDomainMetadata(const DNSName& name, const std::string& kind, std::vector<std::string>& meta);
+ bool setDomainMetadata(const DNSName& name, const std::string& kind, const std::vector<std::string>& meta);
+
+ bool removeDomainKey(const DNSName& name, unsigned int id);
+ bool activateDomainKey(const DNSName& name, unsigned int id);
+ bool deactivateDomainKey(const DNSName& name, unsigned int id);
+
+ bool getTSIGKey(const DNSName& name, DNSName* algorithm, string* content);
+ bool setTSIGKey(const DNSName& name, const DNSName& algorithm, const string& content);
+ bool deleteTSIGKey(const DNSName& name);
+ bool getTSIGKeys(std::vector< struct TSIGKey > &keys);
+
+ void alsoNotifies(const DNSName &domain, set<string> *ips);
+ void rediscover(string* status=0);
+ void reload();
+ bool searchRecords(const string &pattern, int maxResults, vector<DNSResourceRecord>& result);
+ bool searchComments(const string &pattern, int maxResults, vector<Comment>& result);
+private:
+ pthread_t tid;
+ handle d_handle;
+ vector<DNSResourceRecord> d_answers;
+ vector<DNSResourceRecord>::const_iterator d_cachehandleiter;
+
+ static pthread_mutex_t d_mut;
+ static pthread_cond_t d_cond;
+ static sem_t d_dynserialize;
+
+ struct Question
+ {
+ DNSName qname;
+ int zoneId;
+ QType qtype;
+ }d_question;
+
+ unsigned int d_cache_ttl, d_negcache_ttl;
+ int domain_id;
+ int d_ancount;
+
+ bool d_negcached;
+ bool d_cached;
+ static bool d_go;
+ bool stale;
+
+ int cacheHas(const Question &q, vector<DNSResourceRecord> &rrs);
+ void addNegCache(const Question &q);
+ void addCache(const Question &q, const vector<DNSResourceRecord> &rrs);
+
+};
+
+#endif
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2005 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pdnsexception.hh"
+#include "logger.hh"
+#include "misc.hh"
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+
+
+#if defined(_AIX) || defined(__APPLE__)
+
+// Darwin 6.0 Compatible implementation, uses pthreads so it portable across more platforms.
+
+#define SEM_VALUE_MAX 32767
+#define SEM_MAGIC ((uint32_t) 0x09fa4012)
+
+Semaphore::Semaphore(unsigned int value)
+{
+ if (value > SEM_VALUE_MAX) {
+ throw PDNSException("Cannot create semaphore: value too large");
+ }
+
+ // Initialize
+
+ if (pthread_mutex_init(&m_lock, NULL) != 0) {
+ throw PDNSException("Cannot create semaphore: cannot allocate mutex");
+ }
+
+ if (pthread_cond_init(&m_gtzero, NULL) != 0) {
+ pthread_mutex_destroy(&m_lock);
+ throw PDNSException("Cannot create semaphore: cannot allocate condition");
+ }
+
+ m_count = (uint32_t) value;
+ m_nwaiters = 0;
+ m_magic = SEM_MAGIC;
+}
+
+int Semaphore::post()
+{
+ pthread_mutex_lock(&m_lock);
+
+ m_count++;
+ if (m_nwaiters > 0) {
+ pthread_cond_signal(&m_gtzero);
+ }
+
+ pthread_mutex_unlock(&m_lock);
+
+ return 0;
+}
+
+int Semaphore::wait()
+{
+ pthread_mutex_lock(&m_lock);
+
+ while (m_count == 0) {
+ m_nwaiters++;
+ pthread_cond_wait(&m_gtzero, &m_lock);
+ m_nwaiters--;
+ }
+
+ m_count--;
+
+ pthread_mutex_unlock(&m_lock);
+
+ return 0;
+}
+
+int Semaphore::tryWait()
+{
+ int retval = 0;
+
+ pthread_mutex_lock(&m_lock);
+
+ if (m_count > 0) {
+ m_count--;
+ } else {
+ errno = EAGAIN;
+ retval = -1;
+ }
+
+ pthread_mutex_unlock(&m_lock);
+
+ return retval;
+}
+
+int Semaphore::getValue(Semaphore::sem_value_t *sval)
+{
+ pthread_mutex_lock(&m_lock);
+ *sval = m_count;
+ pthread_mutex_unlock(&m_lock);
+
+ return 0;
+}
+
+Semaphore::~Semaphore()
+{
+ // Make sure there are no waiters.
+
+ pthread_mutex_lock(&m_lock);
+ if (m_nwaiters > 0) {
+ pthread_mutex_unlock(&m_lock);
+ //errno = EBUSY;
+ //return -1;
+ }
+ pthread_mutex_unlock(&m_lock);
+
+ // Destroy it.
+
+ pthread_mutex_destroy(&m_lock);
+ pthread_cond_destroy(&m_gtzero);
+ m_magic = 0;
+
+ //return 0;
+}
+
+#else /* not DARWIN from here on */
+
+
+Semaphore::Semaphore(unsigned int value)
+{
+ m_pSemaphore=new sem_t;
+ if (sem_init(m_pSemaphore, 0, value) == -1) {
+ theL() << Logger::Error << "Cannot create semaphore: " << stringerror() << endl;
+ exit(1);
+ }
+}
+
+int Semaphore::post()
+{
+ return sem_post(m_pSemaphore);
+}
+
+int Semaphore::wait()
+{
+ int ret;
+ do
+ ret = sem_wait(m_pSemaphore);
+ while (ret == -1 && errno == EINTR);
+ return ret;
+}
+int Semaphore::tryWait()
+{
+ return sem_trywait(m_pSemaphore);
+}
+
+int Semaphore::getValue(Semaphore::sem_value_t *sval)
+{
+ return sem_getvalue(m_pSemaphore, sval);
+}
+
+Semaphore::~Semaphore()
+{
+ delete m_pSemaphore;
+}
+
+#endif
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2 as
+ published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include <cstring>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include "pdnsexception.hh"
+#include "logger.hh"
+#include "misc.hh"
+#include <pwd.h>
+#include <grp.h>
+#include <sys/types.h>
+#include <sys/select.h>
+
+#ifdef NEED_INET_NTOP_PROTO
+extern "C" {
+const char *inet_ntop(int af, const void *src, char *dst, size_t cnt);
+}
+#endif
+
+
+#include "namespaces.hh"
+
+
+// Connects to socket with timeout
+int Utility::timed_connect( Utility::sock_t sock,
+ const sockaddr *addr,
+ Utility::socklen_t sockaddr_size,
+ int timeout_sec,
+ int timeout_usec )
+{
+ fd_set set;
+ struct timeval timeout;
+ int ret;
+
+ timeout.tv_sec = timeout_sec;
+ timeout.tv_usec = timeout_usec;
+
+ FD_ZERO(&set);
+ FD_SET(sock, &set);
+
+ setNonBlocking(sock);
+
+ if ((ret = connect (sock, addr, sockaddr_size)) < 0) {
+ if (errno != EINPROGRESS)
+ return ret;
+ }
+
+ ret = select(sock + 1, NULL, &set, NULL, &timeout);
+ setBlocking(sock);
+
+ return ret;
+}
+
+
+
+void Utility::setBindAny(int af, sock_t sock)
+{
+ const int one = 1;
+
+ (void) one; // avoids 'unused var' warning on systems that have none of the defines checked below
+#ifdef IP_FREEBIND
+ if (setsockopt(sock, IPPROTO_IP, IP_FREEBIND, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IP_FREEBIND setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+
+#ifdef IP_BINDANY
+ if (af == AF_INET)
+ if (setsockopt(sock, IPPROTO_IP, IP_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IP_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+#ifdef IPV6_BINDANY
+ if (af == AF_INET6)
+ if (setsockopt(sock, IPPROTO_IPV6, IPV6_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: IPV6_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+#ifdef SO_BINDANY
+ if (setsockopt(sock, SOL_SOCKET, SO_BINDANY, &one, sizeof(one)) < 0)
+ theL()<<Logger::Warning<<"Warning: SO_BINDANY setsockopt failed: "<<strerror(errno)<<endl;
+#endif
+}
+
+const char *Utility::inet_ntop(int af, const char *src, char *dst, size_t size)
+{
+ return ::inet_ntop(af,src,dst,size);
+}
+
+unsigned int Utility::sleep(unsigned int sec)
+{
+ return ::sleep(sec);
+}
+
+void Utility::usleep(unsigned long usec)
+{
+ struct timespec ts;
+ ts.tv_sec = usec / 1000000;
+ ts.tv_nsec = (usec % 1000000) * 1000;
+ // POSIX.1 recommends using nanosleep instead of usleep
+ ::nanosleep(&ts, NULL);
+}
+
+
+// Drops the program's group privileges.
+void Utility::dropGroupPrivs( int uid, int gid )
+{
+ if(gid) {
+ if(setgid(gid)<0) {
+ theL()<<Logger::Critical<<"Unable to set effective group id to "<<gid<<": "<<stringerror()<<endl;
+ exit(1);
+ }
+ else
+ theL()<<Logger::Info<<"Set effective group id to "<<gid<<endl;
+
+ struct passwd *pw=getpwuid(uid);
+ if(!pw) {
+ theL()<<Logger::Warning<<"Unable to determine user name for uid "<<uid<<endl;
+ if (setgroups(0, NULL)<0) {
+ theL()<<Logger::Critical<<"Unable to drop supplementary gids: "<<stringerror()<<endl;
+ exit(1);
+ }
+ } else {
+ if (initgroups(pw->pw_name, gid)<0) {
+ theL()<<Logger::Critical<<"Unable to set supplementary groups: "<<stringerror()<<endl;
+ exit(1);
+ }
+ }
+ }
+}
+
+
+// Drops the program's user privileges.
+void Utility::dropUserPrivs( int uid )
+{
+ if(uid) {
+ if(setuid(uid)<0) {
+ theL()<<Logger::Critical<<"Unable to set effective user id to "<<uid<<": "<<stringerror()<<endl;
+ exit(1);
+ }
+ else
+ theL()<<Logger::Info<<"Set effective user id to "<<uid<<endl;
+ }
+}
+
+
+// Returns the current process id.
+Utility::pid_t Utility::getpid( void )
+{
+ return ::getpid();
+}
+
+
+// Returns the current time.
+int Utility::gettimeofday( struct timeval *tv, void *tz )
+{
+ return ::gettimeofday(tv,0);
+}
+
+
+
+// Retrieves a gid using a groupname.
+int Utility::makeGidNumeric(const string &group)
+{
+ int newgid;
+ if(!(newgid=atoi(group.c_str()))) {
+ errno=0;
+ struct group *gr=getgrnam(group.c_str());
+ if(!gr) {
+ theL()<<Logger::Critical<<"Unable to look up gid of group '"<<group<<"': "<< (errno ? strerror(errno) : "not found") <<endl;
+ exit(1);
+ }
+ newgid=gr->gr_gid;
+ }
+ return newgid;
+}
+
+
+// Retrieves an uid using a username.
+int Utility::makeUidNumeric(const string &username)
+{
+ int newuid;
+ if(!(newuid=atoi(username.c_str()))) {
+ struct passwd *pw=getpwnam(username.c_str());
+ if(!pw) {
+ theL()<<Logger::Critical<<"Unable to look up uid of user '"<<username<<"': "<< (errno ? strerror(errno) : "not found") <<endl;
+ exit(1);
+ }
+ newuid=pw->pw_uid;
+ }
+ return newuid;
+}
+
+
+// Returns a random number.
+long int Utility::random( void )
+{
+ return rand();
+}
+
+// Sets the random seed.
+void Utility::srandom( unsigned int seed )
+{
+ ::srandom(seed);
+}
+
+
+// Writes a vector.
+int Utility::writev(int socket, const iovec *vector, size_t count )
+{
+ return ::writev(socket,vector,count);
+}
+
+/* this is cut and pasted from dietlibc, gratefully copied! */
+static int isleap(int year) {
+ /* every fourth year is a leap year except for century years that are
+ * not divisible by 400. */
+ return (!(year%4) && ((year%100) || !(year%400)));
+}
+
+time_t Utility::timegm(struct tm *const t)
+{
+ const static short spm[13] = /* days per month -- nonleap! */
+ { 0,
+ (31),
+ (31+28),
+ (31+28+31),
+ (31+28+31+30),
+ (31+28+31+30+31),
+ (31+28+31+30+31+30),
+ (31+28+31+30+31+30+31),
+ (31+28+31+30+31+30+31+31),
+ (31+28+31+30+31+30+31+31+30),
+ (31+28+31+30+31+30+31+31+30+31),
+ (31+28+31+30+31+30+31+31+30+31+30),
+ (31+28+31+30+31+30+31+31+30+31+30+31),
+ };
+
+ time_t day;
+ time_t i;
+ time_t years = t->tm_year - 70;
+
+ if (t->tm_sec>60) { t->tm_min += t->tm_sec/60; t->tm_sec%=60; }
+ if (t->tm_min>60) { t->tm_hour += t->tm_min/60; t->tm_min%=60; }
+ if (t->tm_hour>60) { t->tm_mday += t->tm_hour/60; t->tm_hour%=60; }
+ if (t->tm_mon>11) { t->tm_year += t->tm_mon/12; t->tm_mon%=12; }
+
+ while (t->tm_mday>spm[1+t->tm_mon]) {
+ if (t->tm_mon==1 && isleap(t->tm_year+1900)) {
+ if (t->tm_mon==31+29) break;
+ --t->tm_mday;
+ }
+ t->tm_mday-=spm[t->tm_mon];
+ ++t->tm_mon;
+ if (t->tm_mon>11) { t->tm_mon=0; ++t->tm_year; }
+ }
+
+ if (t->tm_year < 70)
+ return (time_t) -1;
+ /* Days since 1970 is 365 * number of years + number of leap years since 1970 */
+ day = years * 365 + (years + 1) / 4;
+
+ /* After 2100 we have to subtract 3 leap years for every 400 years
+ This is not intuitive. Most mktime implementations do not support
+ dates after 2059, anyway, so we might leave this out for its
+ bloat. */
+ if ((years -= 131) >= 0) {
+ years /= 100;
+ day -= (years >> 2) * 3 + 1;
+ if ((years &= 3) == 3) years--;
+ day -= years;
+ }
+
+ day += t->tm_yday = spm [t->tm_mon] + t->tm_mday-1 + ( isleap (t->tm_year+1900) & (t->tm_mon > 1) );
+
+ /* day is now the number of days since 'Jan 1 1970' */
+ i = 7;
+ t->tm_wday = (day + 4) % i; /* Sunday=0, Monday=1, ..., Saturday=6 */
+
+ i = 24;
+ day *= i;
+ i = 60;
+ return ((day + t->tm_hour) * i + t->tm_min) * i + t->tm_sec;
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+// Utility class specification.
+
+#ifndef UTILITY_HH
+#define UTILITY_HH
+
+#ifdef NEED_POSIX_TYPEDEF
+typedef unsigned char uint8_t;
+typedef unsigned short int uint16_t;
+typedef unsigned int uint32_t;
+typedef unsigned long long uint64_t;
+#endif
+
+#include <arpa/inet.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <sys/uio.h>
+#include <signal.h>
+#include <pthread.h>
+#include <semaphore.h>
+#include <signal.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string>
+
+#include "namespaces.hh"
+
+//! A semaphore class.
+class Semaphore
+{
+private:
+ typedef int sem_value_t;
+
+#if defined(_AIX) || defined(__APPLE__)
+ uint32_t m_magic;
+ pthread_mutex_t m_lock;
+ pthread_cond_t m_gtzero;
+ sem_value_t m_count;
+ uint32_t m_nwaiters;
+#else
+ sem_t *m_pSemaphore;
+#endif
+
+protected:
+public:
+ //! Default constructor.
+ Semaphore( unsigned int value = 0 );
+
+ //! Destructor.
+ ~Semaphore( void );
+
+ //! Posts to a semaphore.
+ int post( void );
+
+ //! Waits for a semaphore.
+ int wait( void );
+
+ //! Tries to wait for a semaphore.
+ int tryWait( void );
+
+ //! Retrieves the semaphore value.
+ int getValue( Semaphore::sem_value_t *sval );
+};
+
+//! This is a utility class used for platform independent abstraction.
+class Utility
+{
+public:
+ typedef ::iovec iovec;
+ typedef ::pid_t pid_t;
+ typedef int sock_t;
+ typedef ::socklen_t socklen_t;
+
+ //! Connect with timeout
+ // Returns:
+ // > 0 on success
+ // -1 on error
+ // 0 on timeout
+ static int timed_connect(sock_t sock,
+ const sockaddr *addr,
+ socklen_t sockaddr_size,
+ int timeout_sec,
+ int timeout_usec);
+
+ //! Returns the process id of the current process.
+ static pid_t getpid( void );
+
+ //! Gets the current time.
+ static int gettimeofday( struct timeval *tv, void *tz = NULL );
+
+ //! Converts an address from dot and numbers format to binary data.
+ static int inet_aton( const char *cp, struct in_addr *inp );
+
+ //! Converts an address from presentation format to network format.
+ static int inet_pton( int af, const char *src, void *dst );
+
+ //! The inet_ntop() function converts an address from network format (usually a struct in_addr or some other binary form, in network byte order) to presentation format.
+ static const char *inet_ntop( int af, const char *src, char *dst, size_t size );
+
+ //! Retrieves a gid using a groupname.
+ static int makeGidNumeric( const string & group );
+
+ //! Retrieves an uid using an username.
+ static int makeUidNumeric( const string & username );
+
+ //! Writes a vector.
+ static int writev( Utility::sock_t socket, const iovec *vector, size_t count );
+ //! Returns a random number.
+ static long int random( void );
+
+ //! Sets the random seed.
+ static void srandom( unsigned int seed );
+
+ //! Drops the program's group privileges.
+ static void dropGroupPrivs( int uid, int gid );
+
+ //! Drops the program's user privileges.
+ static void dropUserPrivs( int uid );
+
+ //! Sets the socket into Bind-any mode
+ static void setBindAny ( int af, Utility::sock_t socket );
+
+ //! Sleeps for a number of seconds.
+ static unsigned int sleep( unsigned int seconds );
+
+ //! Sleeps for a number of microseconds.
+ static void usleep( unsigned long usec );
+
+ static time_t timegm(struct tm *tm);
+
+};
+
+
+#endif // UTILITY_HH
--- /dev/null
+#include "validate.hh"
+#include "misc.hh"
+#include "dnssecinfra.hh"
+#include "rec-lua-conf.hh"
+#include "base32.hh"
+#include "logger.hh"
+bool g_dnssecLOG{false};
+
+#define LOG(x) if(g_dnssecLOG) { L <<Logger::Warning << x; }
+void dotEdge(DNSName zone, string type1, DNSName name1, string tag1, string type2, DNSName name2, string tag2, string color="");
+void dotNode(string type, DNSName name, string tag, string content);
+string dotName(string type, DNSName name, string tag);
+string dotEscape(string name);
+
+const char *dStates[]={"nodata", "nxdomain", "empty non-terminal", "insecure (no-DS proof)"};
+const char *vStates[]={"Indeterminate", "Bogus", "Insecure", "Secure", "NTA"};
+
+typedef set<DNSKEYRecordContent> keyset_t;
+vector<DNSKEYRecordContent> getByTag(const keyset_t& keys, uint16_t tag)
+{
+ vector<DNSKEYRecordContent> ret;
+ for(const auto& key : keys)
+ if(key.getTag() == tag)
+ ret.push_back(key);
+ return ret;
+}
+
+
+static string nsec3Hash(const DNSName &qname, const NSEC3RecordContent& nrc)
+{
+ NSEC3PARAMRecordContent ns3pr;
+ ns3pr.d_iterations = nrc.d_iterations;
+ ns3pr.d_salt = nrc.d_salt;
+ return toBase32Hex(hashQNameWithSalt(ns3pr, qname));
+}
+
+
+// FIXME: needs a zone argument, to avoid things like 6840 4.1
+static dState getDenial(cspmap_t &validrrsets, DNSName qname, uint16_t qtype)
+{
+ std::multimap<DNSName, NSEC3RecordContent> nsec3s;
+
+ for(auto i=validrrsets.begin(); i!=validrrsets.end(); ++i)
+ {
+ // FIXME also support NSEC
+ if(i->first.second != QType::NSEC3) continue;
+
+ for(auto j=i->second.records.begin(); j!=i->second.records.end(); ++j) {
+ NSEC3RecordContent ns3r = dynamic_cast<NSEC3RecordContent&> (**j);
+ // nsec3.insert(new nsec3()
+ // cerr<<toBase32Hex(r.d_nexthash)<<endl;
+ nsec3s.insert(make_pair(i->first.first, ns3r));
+ }
+ }
+ // cerr<<"got "<<nsec3s.size()<<" NSEC3s"<<endl;
+ for(auto i=nsec3s.begin(); i != nsec3s.end(); ++i) {
+ vector<string> parts = i->first.getRawLabels();
+
+ string base=toLower(parts[0]);
+ string next=toLower(toBase32Hex(i->second.d_nexthash));
+ string hashed = nsec3Hash(qname, i->second);
+ // cerr<<base<<" .. ? "<<hashed<<" ("<<qname<<") ? .. "<<next<<endl;
+ if(base==hashed) {
+ // positive name proof, need to check type
+ // cerr<<"positive name proof, checking type bitmap"<<endl;
+ // cerr<<"d_set.count("<<qtype<<"): "<<i->second.d_set.count(qtype)<<endl;
+ if(qtype == QType::DS && i->second.d_set.count(qtype) == 0) return INSECURE; // FIXME need to require 'NS in bitmap' here, otherwise no delegation! (but first, make sure this is reliable - does not work that way for direct auth queries)
+ } else if ((hashed > base && hashed < next) ||
+ (next < base && (hashed < next || hashed > base))) {
+ bool optout=(1 & i->second.d_flags);
+ // cerr<<"negative name proof, optout = "<<optout<<endl;
+ if(qtype == QType::DS && optout) return INSECURE;
+ }
+ }
+ /* NODATA is not really appropriate here, but we
+ just need to return something else than INSECURE.
+ */
+ dState ret = NODATA;
+ return ret;
+}
+
+void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const keyset_t& keys)
+{
+ validated.clear();
+ /* cerr<<"Validating an rrset with following keys: "<<endl;
+ for(auto& key : keys) {
+ cerr<<"\tTag: "<<key.getTag()<<" -> "<<key.getZoneRepresentation()<<endl;
+ }
+ */
+ for(auto i=rrsets.begin(); i!=rrsets.end(); i++) {
+ LOG("validating "<<(i->first.first)<<"/"<<DNSRecordContent::NumberToType(i->first.second)<<" with "<<i->second.signatures.size()<<" sigs"<<endl);
+ for(const auto& signature : i->second.signatures) {
+ vector<shared_ptr<DNSRecordContent> > toSign = i->second.records;
+
+ if(getByTag(keys,signature->d_tag).empty()) {
+ LOG("No key provided for "<<signature->d_tag<<endl;);
+ continue;
+ }
+
+ string msg=getMessageForRRSET(i->first.first, *signature, toSign, true);
+ auto r = getByTag(keys,signature->d_tag); // FIXME: also take algorithm into account? right now we wrongly validate unknownalgorithm.bad-dnssec.wb.sidnlabs.nl
+ for(const auto& l : r) {
+ bool isValid = false;
+ try {
+ unsigned int now=time(0);
+ if(signature->d_siginception < now && signature->d_sigexpire > now) {
+ std::shared_ptr<DNSCryptoKeyEngine> dke = shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromPublicKeyString(l.d_algorithm, l.d_key));
+ isValid = dke->verify(msg, signature->d_signature);
+ LOG("signature by key with tag "<<signature->d_tag<<" was " << (isValid ? "" : "NOT ")<<"valid"<<endl);
+ }
+ else {
+ LOG("signature is expired/not yet valid"<<endl);
+ }
+ }
+ catch(std::exception& e) {
+ LOG("Error validating with engine: "<<e.what()<<endl);
+ }
+ if(isValid) {
+ validated[i->first] = i->second;
+ LOG("Validated "<<i->first.first<<"/"<<DNSRecordContent::NumberToType(signature->d_type)<<endl);
+ // cerr<<"valid"<<endl;
+ // cerr<<"! validated "<<i->first.first<<"/"<<)<<endl;
+ }
+ else {
+ LOG("signature invalid"<<endl);
+ }
+ if(signature->d_type != QType::DNSKEY) {
+ dotEdge(signature->d_signer,
+ "DNSKEY", signature->d_signer, std::to_string(signature->d_tag),
+ DNSRecordContent::NumberToType(signature->d_type), i->first.first, "", isValid ? "green" : "red");
+
+ }
+ // FIXME: break out enough levels
+ }
+ }
+ }
+}
+
+
+// returns vState
+// should return vState, zone cut and validated keyset
+// i.e. www.7bits.nl -> insecure/7bits.nl/[]
+// www.powerdnssec.org -> secure/powerdnssec.org/[keys]
+// www.dnssec-failed.org -> bogus/dnssec-failed.org/[]
+
+const char *g_rootDS;
+
+cspmap_t harvestCSPFromRecs(const vector<DNSRecord>& recs)
+{
+ cspmap_t cspmap;
+ for(const auto& rec : recs) {
+ // cerr<<"res "<<rec.d_name<<"/"<<rec.d_type<<endl;
+ if(rec.d_type == QType::OPT) continue;
+
+ if(rec.d_type == QType::RRSIG) {
+ auto rrc = getRR<RRSIGRecordContent>(rec);
+ if (rrc) {
+ cspmap[{rec.d_name,rrc->d_type}].signatures.push_back(rrc);
+ }
+ }
+ else {
+ cspmap[{rec.d_name, rec.d_type}].records.push_back(rec.d_content);
+ }
+ }
+ return cspmap;
+}
+
+vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, keyset_t &keyset)
+{
+ auto luaLocal = g_luaconfs.getLocal();
+ auto anchors = luaLocal->dsAnchors;
+ // Determine the lowest (i.e. with the most labels) Trust Anchor for zone
+ DNSName lowestTA(".");
+ for (auto const &anchor : anchors)
+ if (zone.isPartOf(anchor.first) && lowestTA.countLabels() < anchor.first.countLabels())
+ lowestTA = anchor.first;
+
+ // Before searching for the keys, see if we have a Negative Trust Anchor. If
+ // so, test if the NTA is valid and return an NTA state
+ auto negAnchors = luaLocal->negAnchors;
+
+ if (!negAnchors.empty()) {
+ DNSName lowestNTA;
+
+ for (auto const &negAnchor : negAnchors)
+ if (zone.isPartOf(negAnchor.first) && lowestNTA.countLabels() < negAnchor.first.countLabels())
+ lowestNTA = negAnchor.first;
+
+ if(!lowestNTA.empty()) {
+ LOG("Found a Negative Trust Anchor for "<<lowestNTA.toStringRootDot()<<", which was added with reason '"<<negAnchors[lowestNTA]<<"', ");
+
+ /* RFC 7646 section 2.1 tells us that we SHOULD still validate if there
+ * is a Trust Anchor below the Negative Trust Anchor for the name we
+ * attempt validation for. However, section 3 tells us this positive
+ * Trust Anchor MUST be *below* the name and not the name itself
+ */
+ if(lowestTA.countLabels() < lowestNTA.countLabels()) {
+ LOG("marking answer Insecure"<<endl);
+ return NTA; // Not Insecure, this way validateRecords() can shortcut
+ }
+ LOG("but a Trust Anchor for "<<lowestTA.toStringRootDot()<<" is configured, continuing validation."<<endl);
+ }
+ }
+
+ vector<string> labels = zone.getRawLabels();
+
+ dsmap_t dsmap;
+ keyset_t validkeys;
+
+ DNSName qname = lowestTA;
+ vState state = Secure; // the lowest Trust Anchor is secure
+
+ while(zone.isPartOf(qname))
+ {
+ dsmap_t* tmp = (dsmap_t*) rplookup(luaLocal->dsAnchors, qname);
+ if (tmp)
+ dsmap = *tmp;
+
+ vector<RRSIGRecordContent> sigs;
+ vector<shared_ptr<DNSRecordContent> > toSign;
+ vector<uint16_t> toSignTags;
+
+ keyset_t tkeys; // tentative keys
+ validkeys.clear();
+
+ // start of this iteration
+ // we can trust that dsmap has valid DS records for qname
+
+ // cerr<<"got DS for ["<<qname<<"], grabbing DNSKEYs"<<endl;
+ auto recs=dro.get(qname, (uint16_t)QType::DNSKEY);
+ // this should use harvest perhaps
+ for(const auto& rec : recs) {
+ if(rec.d_name != qname)
+ continue;
+
+ if(rec.d_type == QType::RRSIG)
+ {
+ auto rrc=getRR<RRSIGRecordContent> (rec);
+ LOG("Got signature: "<<rrc->getZoneRepresentation()<<" with tag "<<rrc->d_tag<<", for type "<<DNSRecordContent::NumberToType(rrc->d_type)<<endl);
+ if(rrc && rrc->d_type != QType::DNSKEY)
+ continue;
+ sigs.push_back(*rrc);
+ }
+ else if(rec.d_type == QType::DNSKEY)
+ {
+ auto drc=getRR<DNSKEYRecordContent> (rec);
+ if(drc) {
+ tkeys.insert(*drc);
+ LOG("Inserting key with tag "<<drc->getTag()<<": "<<drc->getZoneRepresentation()<<endl);
+ // dotNode("DNSKEY", qname, std::to_string(drc->getTag()), (boost::format("tag=%d, algo=%d") % drc->getTag() % static_cast<int>(drc->d_algorithm)).str());
+
+ toSign.push_back(rec.d_content);
+ toSignTags.push_back(drc->getTag());
+ }
+ }
+ }
+ LOG("got "<<tkeys.size()<<" keys and "<<sigs.size()<<" sigs from server"<<endl);
+
+ for(auto const& dsrc : dsmap)
+ {
+ auto r = getByTag(tkeys, dsrc.d_tag);
+ // cerr<<"looking at DS with tag "<<dsrc.d_tag<<"/"<<i->first<<", got "<<r.size()<<" DNSKEYs for tag"<<endl;
+
+ for(const auto& drc : r)
+ {
+ bool isValid = false;
+ DSRecordContent dsrc2;
+ try {
+ dsrc2=makeDSFromDNSKey(qname, drc, dsrc.d_digesttype);
+ isValid = dsrc == dsrc2;
+ }
+ catch(std::exception &e) {
+ LOG("Unable to make DS from DNSKey: "<<e.what()<<endl);
+ }
+
+ if(isValid) {
+ LOG("got valid DNSKEY (it matches the DS) with tag "<<dsrc.d_tag<<" for "<<qname<<endl);
+
+ validkeys.insert(drc);
+ dotNode("DS", qname, "" /*std::to_string(dsrc.d_tag)*/, (boost::format("tag=%d, digest algo=%d, algo=%d") % dsrc.d_tag % static_cast<int>(dsrc.d_digesttype) % static_cast<int>(dsrc.d_algorithm)).str());
+ }
+ else {
+ LOG("DNSKEY did not match the DS, parent DS: "<<drc.getZoneRepresentation() << " ! = "<<dsrc2.getZoneRepresentation()<<endl);
+ }
+ // cout<<" subgraph "<<dotEscape("cluster "+qname)<<" { "<<dotEscape("DS "+qname)<<" -> "<<dotEscape("DNSKEY "+qname)<<" [ label = \""<<dsrc.d_tag<<"/"<<static_cast<int>(dsrc.d_digesttype)<<"\" ]; label = \"zone: "<<qname<<"\"; }"<<endl;
+ dotEdge(DNSName("."), "DS", qname, "" /*std::to_string(dsrc.d_tag)*/, "DNSKEY", qname, std::to_string(drc.getTag()), isValid ? "green" : "red");
+ // dotNode("DNSKEY", qname, (boost::format("tag=%d, algo=%d") % drc.getTag() % static_cast<int>(drc.d_algorithm)).str());
+ }
+ }
+
+ // cerr<<"got "<<validkeys.size()<<"/"<<tkeys.size()<<" valid/tentative keys"<<endl;
+ // these counts could be off if we somehow ended up with
+ // duplicate keys. Should switch to a type that prevents that.
+ if(validkeys.size() < tkeys.size())
+ {
+ // this should mean that we have one or more DS-validated DNSKEYs
+ // but not a fully validated DNSKEY set, yet
+ // one of these valid DNSKEYs should be able to validate the
+ // whole set
+ for(auto i=sigs.begin(); i!=sigs.end(); i++)
+ {
+ // cerr<<"got sig for keytag "<<i->d_tag<<" matching "<<getByTag(tkeys, i->d_tag).size()<<" keys of which "<<getByTag(validkeys, i->d_tag).size()<<" valid"<<endl;
+ string msg=getMessageForRRSET(qname, *i, toSign);
+ auto bytag = getByTag(validkeys, i->d_tag);
+ for(const auto& j : bytag) {
+ // cerr<<"validating : ";
+ bool isValid = false;
+ try {
+ unsigned int now = time(0);
+ if(i->d_siginception < now && i->d_sigexpire > now) {
+ std::shared_ptr<DNSCryptoKeyEngine> dke = shared_ptr<DNSCryptoKeyEngine>(DNSCryptoKeyEngine::makeFromPublicKeyString(j.d_algorithm, j.d_key));
+ isValid = dke->verify(msg, i->d_signature);
+ }
+ else {
+ LOG("Signature on DNSKEY expired"<<endl);
+ }
+ }
+ catch(std::exception& e) {
+ LOG("Could not make a validator for signature: "<<e.what()<<endl);
+ }
+ for(uint16_t tag : toSignTags) {
+ dotEdge(qname,
+ "DNSKEY", qname, std::to_string(i->d_tag),
+ "DNSKEY", qname, std::to_string(tag), isValid ? "green" : "red");
+ }
+
+ if(isValid)
+ {
+ LOG("validation succeeded - whole DNSKEY set is valid"<<endl);
+ // cout<<" "<<dotEscape("DNSKEY "+stripDot(i->d_signer))<<" -> "<<dotEscape("DNSKEY "+qname)<<";"<<endl;
+ validkeys=tkeys;
+ break;
+ }
+ else {
+ LOG("Validation did not succeed!"<<endl);
+ }
+ }
+ // if(validkeys.empty()) cerr<<"did not manage to validate DNSKEY set based on DS-validated KSK, only passing KSK on"<<endl;
+ }
+ }
+
+ if(validkeys.empty())
+ {
+ LOG("ended up with zero valid DNSKEYs, going Bogus"<<endl);
+ state=Bogus;
+ break;
+ }
+ LOG("situation: we have one or more valid DNSKEYs for ["<<qname<<"] (want ["<<zone<<"])"<<endl);
+ if(qname == zone) {
+ LOG("requested keyset found! returning Secure for the keyset"<<endl);
+ keyset.insert(validkeys.begin(), validkeys.end());
+ return Secure;
+ }
+ // cerr<<"walking downwards to find DS"<<endl;
+ DNSName keyqname=qname;
+ do {
+ qname=DNSName(labels.back())+qname;
+ labels.pop_back();
+ LOG("next name ["<<qname<<"], trying to get DS"<<endl);
+
+ dsmap_t tdsmap; // tentative DSes
+ dsmap.clear();
+ toSign.clear();
+ toSignTags.clear();
+
+ auto recs=dro.get(qname, QType::DS);
+
+ cspmap_t cspmap=harvestCSPFromRecs(recs);
+
+ cspmap_t validrrsets;
+ validateWithKeySet(cspmap, validrrsets, validkeys);
+
+ LOG("got "<<cspmap.count(make_pair(qname,QType::DS))<<" records for DS query of which "<<validrrsets.count(make_pair(qname,QType::DS))<<" valid "<<endl);
+
+ auto r = validrrsets.equal_range(make_pair(qname, QType::DS));
+ if(r.first == r.second) {
+ LOG("No DS for "<<qname<<", now look for a secure denial"<<endl);
+
+ for(const auto& v : validrrsets) {
+ LOG("Do have: "<<v.first.first<<"/"<<DNSRecordContent::NumberToType(v.first.second)<<endl);
+ if(v.first.second==QType::CNAME) {
+ LOG("Found CNAME for "<< v.first.first << ", ignoring records at this level."<<endl);
+ goto skipLevel;
+ }
+ else if(v.first.second==QType::NSEC) { // check that it covers us!
+ for(const auto& r : v.second.records) {
+ LOG("\t"<<r->getZoneRepresentation()<<endl);
+ auto nsec = std::dynamic_pointer_cast<NSECRecordContent>(r);
+ if(nsec) {
+ if(v.first.first == qname && !nsec->d_set.count(QType::DS)) {
+ LOG("Denies existence of DS!"<<endl);
+ return Insecure;
+ }
+ else if(v.first.first.canonCompare(qname) && qname.canonCompare(nsec->d_next) ) {
+ LOG("Did not find DS for this level, trying one lower"<<endl);
+ goto skipLevel;
+ }
+ else {
+ LOG("Did not deny existence of DS, "<<v.first.first<<"?="<<qname<<", "<<nsec->d_set.count(QType::DS)<<", next: "<<nsec->d_next<<endl);
+ }
+ }
+ }
+
+ }
+ else if(v.first.second==QType::NSEC3) {
+ for(const auto& r : v.second.records) {
+ LOG("\t"<<r->getZoneRepresentation()<<endl);
+
+ auto nsec3 = std::dynamic_pointer_cast<NSEC3RecordContent>(r);
+ string h = hashQNameWithSalt(nsec3->d_salt, nsec3->d_iterations, qname);
+ // cerr<<"Salt length: "<<nsec3->d_salt.length()<<", iterations: "<<nsec3->d_iterations<<", hashed: "<<qname<<endl;
+ LOG("\tquery hash: "<<toBase32Hex(h)<<endl);
+ string beginHash=fromBase32Hex(v.first.first.getRawLabels()[0]);
+ if( (beginHash < h && h < nsec3->d_nexthash) ||
+ (nsec3->d_nexthash > h && beginHash > nsec3->d_nexthash) || // wrap // HASH --- END --- BEGINNING
+ (nsec3->d_nexthash < beginHash && beginHash < h) || // wrap other case // END -- BEGINNING -- HASH
+ beginHash == nsec3->d_nexthash) // "we have only 1 NSEC3 record, LOL!"
+ {
+ LOG("Denies existence of DS!"<<endl);
+ return Insecure;
+ }
+ else if(beginHash == h && !nsec3->d_set.count(QType::DS)) {
+ LOG("Denies existence of DS (not opt-out)"<<endl);
+ return Insecure;
+ }
+ else {
+ LOG("Did not cover us, start="<<v.first.first<<", us="<<toBase32Hex(h)<<", end="<<toBase32Hex(nsec3->d_nexthash)<<endl);
+ }
+ }
+ }
+ }
+ return Bogus;
+ }
+ for(auto cspiter =r.first; cspiter!=r.second; cspiter++) {
+ for(auto j=cspiter->second.records.cbegin(); j!=cspiter->second.records.cend(); j++)
+ {
+ const auto dsrc=std::dynamic_pointer_cast<DSRecordContent>(*j);
+ if(dsrc) {
+ dsmap.insert(*dsrc);
+ // dotEdge(keyqname,
+ // "DNSKEY", keyqname, ,
+ // "DS", qname, std::to_string(dsrc.d_tag));
+ // cout<<" "<<dotEscape("DNSKEY "+keyqname)<<" -> "<<dotEscape("DS "+qname)<<";"<<endl;
+ }
+ }
+ }
+ if(!dsmap.size()) {
+ // cerr<<"no DS at this level, checking for denials"<<endl;
+ dState dres = getDenial(validrrsets, qname, QType::DS);
+ if(dres == INSECURE) return Insecure;
+ }
+ skipLevel:;
+ } while(!dsmap.size() && labels.size());
+
+ // break;
+ }
+
+ return state;
+}
+
+
+
+
+string dotEscape(string name)
+{
+ return "\"" + boost::replace_all_copy(name, "\"", "\\\"") + "\"";
+}
+
+string dotName(string type, DNSName name, string tag)
+{
+ if(tag == "")
+ return type+" "+name.toString();
+ else
+ return type+" "+name.toString()+"/"+tag;
+}
+void dotNode(string type, DNSName name, string tag, string content)
+{
+#ifdef GRAPHVIZ
+ cout<<" "
+ <<dotEscape(dotName(type, name, tag))
+ <<" [ label="<<dotEscape(dotName(type, name, tag)+"\\n"+content)<<" ];"<<endl;
+#endif
+}
+
+void dotEdge(DNSName zone, string type1, DNSName name1, string tag1, string type2, DNSName name2, string tag2, string color)
+{
+#ifdef GRAPHVIZ
+ cout<<" ";
+ if(zone != DNSName(".")) cout<<"subgraph "<<dotEscape("cluster "+zone.toString())<<" { ";
+ cout<<dotEscape(dotName(type1, name1, tag1))
+ <<" -> "
+ <<dotEscape(dotName(type2, name2, tag2));
+ if(color != "") cout<<" [ color=\""<<color<<"\" ]; ";
+ else cout<<"; ";
+ if(zone != DNSName(".")) cout<<"label = "<<dotEscape("zone: "+zone.toString())<<";"<<"}";
+ cout<<endl;
+#endif
+}
+
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#pragma once
+
+#include "dnsparser.hh"
+#include "dnsname.hh"
+#include <vector>
+#include "namespaces.hh"
+#include "dnsrecords.hh"
+
+extern bool g_dnssecLOG;
+
+// 4033 5
+enum vState { Indeterminate, Bogus, Insecure, Secure, NTA };
+extern const char *vStates[];
+
+// NSEC(3) results
+enum dState { NODATA, NXDOMAIN, ENT, INSECURE };
+extern const char *dStates[];
+
+
+class DNSRecordOracle
+{
+public:
+ virtual std::vector<DNSRecord> get(const DNSName& qname, uint16_t qtype)=0;
+};
+
+
+struct ContentSigPair
+{
+ vector<shared_ptr<DNSRecordContent>> records;
+ vector<shared_ptr<RRSIGRecordContent>> signatures;
+ // ponder adding a validate method that accepts a key
+};
+typedef map<pair<DNSName,uint16_t>, ContentSigPair> cspmap_t;
+typedef std::set<DSRecordContent> dsmap_t;
+void validateWithKeySet(const cspmap_t& rrsets, cspmap_t& validated, const std::set<DNSKEYRecordContent>& keys);
+cspmap_t harvestCSPFromRecs(const vector<DNSRecord>& recs);
+vState getKeysFor(DNSRecordOracle& dro, const DNSName& zone, std::set<DNSKEYRecordContent> &keyset);
+
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2016 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "logger.hh"
+#include "version.hh"
+
+static ProductType productType;
+
+string compilerVersion()
+{
+#if defined(__clang__)
+ return string("clang " __clang_version__ );
+#elif defined(__GNUC__)
+ return string("gcc " __VERSION__ );
+#else // add other compilers here
+ return string("Unknown compiler");
+#endif
+}
+
+// Human-readable product name
+string productName() {
+ switch (productType) {
+ case ProductAuthoritative:
+ return "PowerDNS Authoritative Server";
+ case ProductRecursor:
+ return "PowerDNS Recursor";
+ };
+ return "Unknown";
+}
+
+string getPDNSVersion()
+{
+ return VERSION;
+}
+
+// REST API product type
+string productTypeApiType() {
+ switch (productType) {
+ case ProductAuthoritative:
+ return "authoritative";
+ case ProductRecursor:
+ return "recursor";
+ };
+ return "unknown";
+}
+
+void showProductVersion()
+{
+ theL()<<Logger::Warning<<productName()<<" "<< VERSION << " (C) 2001-2016 "
+ "PowerDNS.COM BV" << endl;
+ theL()<<Logger::Warning<<"Using "<<(sizeof(unsigned long)*8)<<"-bits mode. "
+ "Built using " << compilerVersion()
+#ifndef REPRODUCIBLE
+ <<" on " __DATE__ " " __TIME__ " by " BUILD_HOST
+#endif
+ <<"."<< endl;
+ theL()<<Logger::Warning<<"PowerDNS comes with ABSOLUTELY NO WARRANTY. "
+ "This is free software, and you are welcome to redistribute it "
+ "according to the terms of the GPL version 2." << endl;
+}
+
+void showBuildConfiguration()
+{
+ theL()<<Logger::Warning<<"Features: "<<
+#ifdef HAVE_BOTAN110
+ "botan1.10 " <<
+#endif
+#ifdef HAVE_LIBSODIUM
+ "sodium " <<
+#endif
+#ifdef HAVE_LIBDECAF
+ "decaf " <<
+#endif
+ "openssl " <<
+#ifdef HAVE_LIBDL
+ "libdl " <<
+#endif
+#ifdef HAVE_LUA
+ "lua " <<
+#endif
+#ifdef REMOTEBACKEND_ZEROMQ
+ "remotebackend-zeromq" <<
+#endif
+#ifdef VERBOSELOG
+ "verboselog" <<
+#endif
+ endl;
+#ifdef PDNS_MODULES
+ // Auth only
+ theL()<<Logger::Warning<<"Built-in modules: "<<PDNS_MODULES<<endl;
+#endif
+#ifdef PDNS_CONFIG_ARGS
+#define double_escape(s) #s
+#define escape_quotes(s) double_escape(s)
+ theL()<<Logger::Warning<<"Configured with: "<<escape_quotes(PDNS_CONFIG_ARGS)<<endl;
+#undef escape_quotes
+#undef double_escape
+#endif
+}
+
+string fullVersionString()
+{
+ ostringstream s;
+ s<<productName()<<" " VERSION;
+#ifndef REPRODUCIBLE
+ s<<" (built " __DATE__ " " __TIME__ " by " BUILD_HOST ")";
+#endif
+ return s.str();
+}
+
+void versionSetProduct(ProductType pt)
+{
+ productType = pt;
+}
+
+ProductType versionGetProduct()
+{
+ return productType;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef VERSION_HH
+#define VERSION_HH
+
+#include "namespaces.hh"
+
+enum ProductType { ProductAuthoritative, ProductRecursor };
+
+string compilerVersion();
+void showProductVersion();
+void showBuildConfiguration();
+string fullVersionString();
+string getPDNSVersion();
+string productName();
+string productTypeApiType();
+void versionSetProduct(ProductType pt);
+ProductType versionGetProduct();
+
+#endif //!VERSION_HH
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002-2016 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "webserver.hh"
+#include "misc.hh"
+#include <vector>
+#include "logger.hh"
+#include <stdio.h>
+#include "dns.hh"
+#include "base64.hh"
+#include "json.hh"
+#include "arguments.hh"
+#include <yahttp/router.hpp>
+
+struct connectionThreadData {
+ WebServer* webServer{nullptr};
+ Socket* client{nullptr};
+};
+
+json11::Json HttpRequest::json()
+{
+ string err;
+ if(this->body.empty()) {
+ L<<Logger::Debug<<"HTTP: JSON document expected in request body, but body was empty" << endl;
+ throw HttpBadRequestException();
+ }
+ json11::Json doc = json11::Json::parse(this->body, err);
+ if (doc.is_null()) {
+ L<<Logger::Debug<<"HTTP: parsing of JSON document failed:" << err << endl;
+ throw HttpBadRequestException();
+ }
+ return doc;
+}
+
+bool HttpRequest::compareAuthorization(const string &expected_password)
+{
+ // validate password
+ YaHTTP::strstr_map_t::iterator header = headers.find("authorization");
+ bool auth_ok = false;
+ if (header != headers.end() && toLower(header->second).find("basic ") == 0) {
+ string cookie = header->second.substr(6);
+
+ string plain;
+ B64Decode(cookie, plain);
+
+ vector<string> cparts;
+ stringtok(cparts, plain, ":");
+
+ // this gets rid of terminating zeros
+ auth_ok = (cparts.size()==2 && (0==strcmp(cparts[1].c_str(), expected_password.c_str())));
+ }
+ return auth_ok;
+}
+
+bool HttpRequest::compareHeader(const string &header_name, const string &expected_value)
+{
+ YaHTTP::strstr_map_t::iterator header = headers.find(header_name);
+ if (header == headers.end())
+ return false;
+
+ // this gets rid of terminating zeros
+ return (0==strcmp(header->second.c_str(), expected_value.c_str()));
+}
+
+
+void HttpResponse::setBody(const json11::Json& document)
+{
+ document.dump(this->body);
+}
+
+void HttpResponse::setErrorResult(const std::string& message, const int status)
+{
+ setBody(json11::Json::object { { "error", message } });
+ this->status = status;
+}
+
+void HttpResponse::setSuccessResult(const std::string& message, const int status)
+{
+ setBody(json11::Json::object { { "result", message } });
+ this->status = status;
+}
+
+static void bareHandlerWrapper(WebServer::HandlerFunction handler, YaHTTP::Request* req, YaHTTP::Response* resp)
+{
+ // wrapper to convert from YaHTTP::* to our subclasses
+ handler(static_cast<HttpRequest*>(req), static_cast<HttpResponse*>(resp));
+}
+
+void WebServer::registerBareHandler(const string& url, HandlerFunction handler)
+{
+ YaHTTP::THandlerFunction f = boost::bind(&bareHandlerWrapper, handler, _1, _2);
+ YaHTTP::Router::Any(url, f);
+}
+
+static bool optionsHandler(HttpRequest* req, HttpResponse* resp) {
+ if (req->method == "OPTIONS") {
+ resp->headers["access-control-allow-origin"] = "*";
+ resp->headers["access-control-allow-headers"] = "Content-Type, X-API-Key";
+ resp->headers["access-control-allow-methods"] = "GET, POST, PUT, PATCH, DELETE, OPTIONS";
+ resp->headers["access-control-max-age"] = "3600";
+ resp->status = 200;
+ resp->headers["content-type"]= "text/plain";
+ resp->body = "";
+ return true;
+ }
+ return false;
+}
+
+static void apiWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) {
+ const string& api_key = arg()["api-key"];
+
+ if (optionsHandler(req, resp)) return;
+
+ resp->headers["access-control-allow-origin"] = "*";
+
+ if (api_key.empty()) {
+ L<<Logger::Error<<"HTTP API Request \"" << req->url.path << "\": Authentication failed, API Key missing in config" << endl;
+ throw HttpUnauthorizedException("X-API-Key");
+ }
+ bool auth_ok = req->compareHeader("x-api-key", api_key) || req->getvars["api-key"]==api_key;
+
+ if (!auth_ok) {
+ L<<Logger::Error<<"HTTP Request \"" << req->url.path << "\": Authentication by API Key failed" << endl;
+ throw HttpUnauthorizedException("X-API-Key");
+ }
+
+ resp->headers["Content-Type"] = "application/json";
+
+ // security headers
+ resp->headers["X-Content-Type-Options"] = "nosniff";
+ resp->headers["X-Frame-Options"] = "deny";
+ resp->headers["X-Permitted-Cross-Domain-Policies"] = "none";
+ resp->headers["X-XSS-Protection"] = "1; mode=block";
+ resp->headers["Content-Security-Policy"] = "default-src 'self'; style-src 'self' 'unsafe-inline'";
+
+ req->getvars.erase("_"); // jQuery cache buster
+
+ try {
+ resp->status = 200;
+ handler(req, resp);
+ } catch (ApiException &e) {
+ resp->setErrorResult(e.what(), 422);
+ return;
+ } catch (JsonException &e) {
+ resp->setErrorResult(e.what(), 422);
+ return;
+ }
+
+ if (resp->status == 204) {
+ // No Content -> no Content-Type.
+ resp->headers.erase("Content-Type");
+ }
+}
+
+void WebServer::registerApiHandler(const string& url, HandlerFunction handler) {
+ HandlerFunction f = boost::bind(&apiWrapper, handler, _1, _2);
+ registerBareHandler(url, f);
+}
+
+static void webWrapper(WebServer::HandlerFunction handler, HttpRequest* req, HttpResponse* resp) {
+ const string& web_password = arg()["webserver-password"];
+
+ if (!web_password.empty()) {
+ bool auth_ok = req->compareAuthorization(web_password);
+ if (!auth_ok) {
+ L<<Logger::Debug<<"HTTP Request \"" << req->url.path << "\": Web Authentication failed" << endl;
+ throw HttpUnauthorizedException("Basic");
+ }
+ }
+
+ handler(req, resp);
+}
+
+void WebServer::registerWebHandler(const string& url, HandlerFunction handler) {
+ HandlerFunction f = boost::bind(&webWrapper, handler, _1, _2);
+ registerBareHandler(url, f);
+}
+
+static void *WebServerConnectionThreadStart(void *p) {
+ connectionThreadData* data = static_cast<connectionThreadData*>(p);
+ pthread_detach(pthread_self());
+ data->webServer->serveConnection(data->client);
+
+ delete data->client; // close socket
+ delete data;
+
+ return NULL;
+}
+
+void WebServer::handleRequest(HttpRequest& req, HttpResponse& resp)
+{
+ // set default headers
+ resp.headers["Content-Type"] = "text/html; charset=utf-8";
+
+ try {
+ if (!req.complete) {
+ L<<Logger::Debug<<"HTTP: Incomplete request" << endl;
+ throw HttpBadRequestException();
+ }
+
+ L<<Logger::Debug<<"HTTP: Handling request \"" << req.url.path << "\"" << endl;
+
+ YaHTTP::strstr_map_t::iterator header;
+
+ if ((header = req.headers.find("accept")) != req.headers.end()) {
+ // json wins over html
+ if (header->second.find("application/json") != std::string::npos) {
+ req.accept_json = true;
+ } else if (header->second.find("text/html") != std::string::npos) {
+ req.accept_html = true;
+ }
+ }
+
+ YaHTTP::THandlerFunction handler;
+ if (!YaHTTP::Router::Route(&req, handler)) {
+ L<<Logger::Debug<<"HTTP: No route found for \"" << req.url.path << "\"" << endl;
+ throw HttpNotFoundException();
+ }
+
+ try {
+ handler(&req, &resp);
+ L<<Logger::Debug<<"HTTP: Result for \"" << req.url.path << "\": " << resp.status << ", body length: " << resp.body.size() << endl;
+ }
+ catch(HttpException&) {
+ throw;
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"HTTP ISE for \""<< req.url.path << "\": Exception: " << e.reason << endl;
+ throw HttpInternalServerErrorException();
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"HTTP ISE for \""<< req.url.path << "\": STL Exception: " << e.what() << endl;
+ throw HttpInternalServerErrorException();
+ }
+ catch(...) {
+ L<<Logger::Error<<"HTTP ISE for \""<< req.url.path << "\": Unknown Exception" << endl;
+ throw HttpInternalServerErrorException();
+ }
+ }
+ catch(HttpException &e) {
+ resp = e.response();
+ L<<Logger::Debug<<"HTTP: Error result for \"" << req.url.path << "\": " << resp.status << endl;
+ string what = YaHTTP::Utility::status2text(resp.status);
+ if(req.accept_html) {
+ resp.headers["Content-Type"] = "text/html; charset=utf-8";
+ resp.body = "<!html><title>" + what + "</title><h1>" + what + "</h1>";
+ } else if (req.accept_json) {
+ resp.headers["Content-Type"] = "application/json";
+ resp.setErrorResult(what, resp.status);
+ } else {
+ resp.headers["Content-Type"] = "text/plain; charset=utf-8";
+ resp.body = what;
+ }
+ }
+
+ // always set these headers
+ resp.headers["Server"] = "PowerDNS/" VERSION;
+ resp.headers["Connection"] = "close";
+
+ if (req.method == "HEAD") {
+ resp.body = "";
+ } else {
+ resp.headers["Content-Length"] = std::to_string(resp.body.size());
+ }
+}
+
+void WebServer::serveConnection(Socket *client)
+try {
+ HttpRequest req;
+ YaHTTP::AsyncRequestLoader yarl;
+ yarl.initialize(&req);
+ int timeout = 5;
+ client->setNonBlocking();
+
+ try {
+ while(!req.complete) {
+ int bytes;
+ char buf[1024];
+ bytes = client->readWithTimeout(buf, sizeof(buf), timeout);
+ if (bytes > 0) {
+ string data = string(buf, bytes);
+ req.complete = yarl.feed(data);
+ } else {
+ // read error OR EOF
+ break;
+ }
+ }
+ yarl.finalize();
+ } catch (YaHTTP::ParseError &e) {
+ // request stays incomplete
+ }
+
+ HttpResponse resp;
+ WebServer::handleRequest(req, resp);
+ ostringstream ss;
+ resp.write(ss);
+ string reply = ss.str();
+
+ client->writenWithTimeout(reply.c_str(), reply.size(), timeout);
+}
+catch(PDNSException &e) {
+ L<<Logger::Error<<"HTTP Exception: "<<e.reason<<endl;
+}
+catch(std::exception &e) {
+ if(strstr(e.what(), "timeout")==0)
+ L<<Logger::Error<<"HTTP STL Exception: "<<e.what()<<endl;
+}
+catch(...) {
+ L<<Logger::Error<<"HTTP: Unknown exception"<<endl;
+}
+
+WebServer::WebServer(const string &listenaddress, int port) : d_server(NULL)
+{
+ d_listenaddress=listenaddress;
+ d_port=port;
+}
+
+void WebServer::bind()
+{
+ try {
+ d_server = createServer();
+ L<<Logger::Warning<<"Listening for HTTP requests on "<<d_server->d_local.toStringWithPort()<<endl;
+ }
+ catch(NetworkError &e) {
+ L<<Logger::Error<<"Listening on HTTP socket failed: "<<e.what()<<endl;
+ d_server = NULL;
+ }
+}
+
+void WebServer::go()
+{
+ if(!d_server)
+ return;
+ try {
+ pthread_t tid;
+
+ NetmaskGroup acl;
+ acl.toMasks(::arg()["webserver-allow-from"]);
+
+ while(true) {
+ // data and data->client will be freed by thread
+ connectionThreadData *data = new connectionThreadData;
+ data->webServer = this;
+ try {
+ data->client = d_server->accept();
+ if (data->client->acl(acl)) {
+ pthread_create(&tid, 0, &WebServerConnectionThreadStart, (void *)data);
+ } else {
+ ComboAddress remote;
+ if (data->client->getRemote(remote))
+ L<<Logger::Error<<"Webserver closing socket: remote ("<< remote.toString() <<") does not match 'webserver-allow-from'"<<endl;
+ delete data->client; // close socket
+ delete data;
+ }
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"PDNSException while accepting a connection in main webserver thread: "<<e.reason<<endl;
+ delete data->client;
+ delete data;
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"STL Exception while accepting a connection in main webserver thread: "<<e.what()<<endl;
+ delete data->client;
+ delete data;
+ }
+ catch(...) {
+ L<<Logger::Error<<"Unknown exception while accepting a connection in main webserver thread"<<endl;
+ delete data->client;
+ delete data;
+ }
+ }
+ }
+ catch(PDNSException &e) {
+ L<<Logger::Error<<"PDNSException in main webserver thread: "<<e.reason<<endl;
+ }
+ catch(std::exception &e) {
+ L<<Logger::Error<<"STL Exception in main webserver thread: "<<e.what()<<endl;
+ }
+ catch(...) {
+ L<<Logger::Error<<"Unknown exception in main webserver thread"<<endl;
+ }
+ exit(1);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef WEBSERVER_HH
+#define WEBSERVER_HH
+#include <map>
+#include <string>
+#include <list>
+#include <boost/utility.hpp>
+#include <yahttp/yahttp.hpp>
+#include "json11.hpp"
+#include "namespaces.hh"
+#include "sstuff.hh"
+
+class WebServer;
+
+class HttpRequest : public YaHTTP::Request {
+public:
+ HttpRequest() : YaHTTP::Request(), accept_json(false), accept_html(false), complete(false) { };
+
+ bool accept_json;
+ bool accept_html;
+ bool complete;
+ json11::Json json();
+
+ // checks password _only_.
+ bool compareAuthorization(const string &expected_password);
+ bool compareHeader(const string &header_name, const string &expected_value);
+};
+
+class HttpResponse: public YaHTTP::Response {
+public:
+ HttpResponse() : YaHTTP::Response() { };
+ HttpResponse(const YaHTTP::Response &resp) : YaHTTP::Response(resp) { };
+
+ void setBody(const json11::Json& document);
+ void setErrorResult(const std::string& message, const int status);
+ void setSuccessResult(const std::string& message, const int status = 200);
+};
+
+
+class HttpException
+{
+public:
+ HttpException(int status) : d_response()
+ {
+ d_response.status = status;
+ };
+
+ HttpResponse response()
+ {
+ return d_response;
+ }
+
+protected:
+ HttpResponse d_response;
+};
+
+class HttpBadRequestException : public HttpException {
+public:
+ HttpBadRequestException() : HttpException(400) { };
+};
+
+class HttpUnauthorizedException : public HttpException {
+public:
+ HttpUnauthorizedException(string const &scheme) : HttpException(401)
+ {
+ d_response.headers["WWW-Authenticate"] = scheme + " realm=\"PowerDNS\"";
+ }
+};
+
+class HttpForbiddenException : public HttpException {
+public:
+ HttpForbiddenException() : HttpException(403) { };
+};
+
+class HttpNotFoundException : public HttpException {
+public:
+ HttpNotFoundException() : HttpException(404) { };
+};
+
+class HttpMethodNotAllowedException : public HttpException {
+public:
+ HttpMethodNotAllowedException() : HttpException(405) { };
+};
+
+class HttpInternalServerErrorException : public HttpException {
+public:
+ HttpInternalServerErrorException() : HttpException(500) { };
+};
+
+class ApiException : public runtime_error
+{
+public:
+ ApiException(const string& what) : runtime_error(what) {
+ }
+};
+
+class Server
+{
+public:
+ Server(const string &localaddress, int port) : d_local(localaddress.empty() ? "0.0.0.0" : localaddress, port), d_server_socket(d_local.sin4.sin_family, SOCK_STREAM, 0) {
+ d_server_socket.setReuseAddr();
+ d_server_socket.bind(d_local);
+ d_server_socket.listen();
+ }
+
+ ComboAddress d_local;
+
+ Socket *accept() {
+ return d_server_socket.accept();
+ }
+
+protected:
+ Socket d_server_socket;
+};
+
+class WebServer : public boost::noncopyable
+{
+public:
+ WebServer(const string &listenaddress, int port);
+ void bind();
+ void go();
+
+ void serveConnection(Socket *client);
+ void handleRequest(HttpRequest& request, HttpResponse& resp);
+
+ typedef boost::function<void(HttpRequest* req, HttpResponse* resp)> HandlerFunction;
+ void registerApiHandler(const string& url, HandlerFunction handler);
+ void registerWebHandler(const string& url, HandlerFunction handler);
+
+protected:
+ void registerBareHandler(const string& url, HandlerFunction handler);
+
+ virtual Server* createServer() {
+ return new Server(d_listenaddress, d_port);
+ }
+
+ string d_listenaddress;
+ int d_port;
+ string d_password;
+ Server* d_server;
+};
+
+#endif /* WEBSERVER_HH */
--- /dev/null
+/*
+ Copyright (C) 2002 - 2014 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <boost/tokenizer.hpp>
+#include <boost/circular_buffer.hpp>
+#include "namespaces.hh"
+#include "ws-api.hh"
+#include "json.hh"
+#include "version.hh"
+#include "arguments.hh"
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+#include <sys/types.h>
+#include <iomanip>
+
+extern string s_programname;
+using json11::Json;
+
+#ifndef HAVE_STRCASESTR
+
+/*
+ * strcasestr() locates the first occurrence in the string s1 of the
+ * sequence of characters (excluding the terminating null character)
+ * in the string s2, ignoring case. strcasestr() returns a pointer
+ * to the located string, or a null pointer if the string is not found.
+ * If s2 is empty, the function returns s1.
+ */
+
+static char *
+strcasestr(const char *s1, const char *s2)
+{
+ int *cm = __trans_lower;
+ const uchar_t *us1 = (const uchar_t *)s1;
+ const uchar_t *us2 = (const uchar_t *)s2;
+ const uchar_t *tptr;
+ int c;
+
+ if (us2 == NULL || *us2 == '\0')
+ return ((char *)us1);
+
+ c = cm[*us2];
+ while (*us1 != '\0') {
+ if (c == cm[*us1++]) {
+ tptr = us1;
+ while (cm[c = *++us2] == cm[*us1++] && c != '\0')
+ continue;
+ if (c == '\0')
+ return ((char *)tptr - 1);
+ us1 = tptr;
+ us2 = (const uchar_t *)s2;
+ c = cm[*us2];
+ }
+ }
+
+ return (NULL);
+}
+
+#endif // HAVE_STRCASESTR
+
+static Json getServerDetail() {
+ return Json::object {
+ { "type", "Server" },
+ { "id", "localhost" },
+ { "url", "/api/v1/servers/localhost" },
+ { "daemon_type", productTypeApiType() },
+ { "version", getPDNSVersion() },
+ { "config_url", "/api/v1/servers/localhost/config{/config_setting}" },
+ { "zones_url", "/api/v1/servers/localhost/zones{/zone}" }
+ };
+}
+
+/* Return information about the supported API versions.
+ * The format of this MUST NEVER CHANGE at it's not versioned.
+ */
+void apiDiscovery(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ Json version1 = Json::object {
+ { "version", 1 },
+ { "url", "/api/v1" }
+ };
+ Json doc = Json::array { version1 };
+
+ resp->setBody(doc);
+}
+
+void apiServer(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ Json doc = Json::array {getServerDetail()};
+ resp->setBody(doc);
+}
+
+void apiServerDetail(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ resp->setBody(getServerDetail());
+}
+
+void apiServerConfig(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ vector<string> items = ::arg().list();
+ string value;
+ Json::array doc;
+ for(const string& item : items) {
+ if(item.find("password") != string::npos || item.find("api-key") != string::npos)
+ value = "***";
+ else
+ value = ::arg()[item];
+
+ doc.push_back(Json::object {
+ { "type", "ConfigSetting" },
+ { "name", item },
+ { "value", value },
+ });
+ }
+ resp->setBody(doc);
+}
+
+static Json logGrep(const string& q, const string& fname, const string& prefix)
+{
+ FILE* ptr = fopen(fname.c_str(), "r");
+ if(!ptr) {
+ throw ApiException("Opening \"" + fname + "\" failed: " + stringerror());
+ }
+ std::shared_ptr<FILE> fp(ptr, fclose);
+
+ string line;
+ string needle = q;
+ trim_right(needle);
+
+ boost::replace_all(needle, "%20", " ");
+ boost::replace_all(needle, "%22", "\"");
+
+ boost::tokenizer<boost::escaped_list_separator<char> > t(needle, boost::escaped_list_separator<char>("\\", " ", "\""));
+ vector<string> matches(t.begin(), t.end());
+ matches.push_back(prefix);
+
+ boost::circular_buffer<string> lines(200);
+ while(stringfgets(fp.get(), line)) {
+ vector<string>::const_iterator iter;
+ for(iter = matches.begin(); iter != matches.end(); ++iter) {
+ if(!strcasestr(line.c_str(), iter->c_str()))
+ break;
+ }
+ if(iter == matches.end()) {
+ trim_right(line);
+ lines.push_front(line);
+ }
+ }
+
+ Json::array items;
+ for(const string& line : lines) {
+ items.push_back(line);
+ }
+ return items;
+}
+
+void apiServerSearchLog(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ string prefix = " " + s_programname + "[";
+ resp->setBody(logGrep(req->getvars["q"], ::arg()["api-logfile"], prefix));
+}
+
+void apiServerStatistics(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ map<string,string> items;
+ productServerStatisticsFetch(items);
+
+ Json::array doc;
+ typedef map<string, string> items_t;
+ for(const items_t::value_type& item : items) {
+ doc.push_back(Json::object {
+ { "type", "StatisticItem" },
+ { "name", item.first },
+ { "value", item.second },
+ });
+ }
+
+ resp->setBody(doc);
+}
+
+DNSName apiNameToDNSName(const string& name) {
+ if (!isCanonical(name)) {
+ throw ApiException("DNS Name '" + name + "' is not canonical");
+ }
+ try {
+ return DNSName(name);
+ } catch (...) {
+ throw ApiException("Unable to parse DNS Name '" + name + "'");
+ }
+}
+
+DNSName apiZoneIdToName(const string& id) {
+ string zonename;
+ ostringstream ss;
+
+ if(id.empty())
+ throw HttpBadRequestException();
+
+ std::size_t lastpos = 0, pos = 0;
+ while ((pos = id.find('=', lastpos)) != string::npos) {
+ ss << id.substr(lastpos, pos-lastpos);
+ char c;
+ // decode tens
+ if (id[pos+1] >= '0' && id[pos+1] <= '9') {
+ c = id[pos+1] - '0';
+ } else if (id[pos+1] >= 'A' && id[pos+1] <= 'F') {
+ c = id[pos+1] - 'A' + 10;
+ } else {
+ throw HttpBadRequestException();
+ }
+ c = c * 16;
+
+ // decode unit place
+ if (id[pos+2] >= '0' && id[pos+2] <= '9') {
+ c += id[pos+2] - '0';
+ } else if (id[pos+2] >= 'A' && id[pos+2] <= 'F') {
+ c += id[pos+2] - 'A' + 10;
+ } else {
+ throw HttpBadRequestException();
+ }
+
+ ss << c;
+
+ lastpos = pos+3;
+ }
+ if (lastpos < pos) {
+ ss << id.substr(lastpos, pos-lastpos);
+ }
+
+ zonename = ss.str();
+
+ try {
+ return DNSName(zonename);
+ } catch (...) {
+ throw ApiException("Unable to parse DNS Name '" + zonename + "'");
+ }
+}
+
+string apiZoneNameToId(const DNSName& dname) {
+ string name=dname.toString();
+ ostringstream ss;
+
+ for(string::const_iterator iter = name.begin(); iter != name.end(); ++iter) {
+ if ((*iter >= 'A' && *iter <= 'Z') ||
+ (*iter >= 'a' && *iter <= 'z') ||
+ (*iter >= '0' && *iter <= '9') ||
+ (*iter == '.') || (*iter == '-')) {
+ ss << *iter;
+ } else {
+ ss << (boost::format("=%02X") % (int)(*iter));
+ }
+ }
+
+ string id = ss.str();
+
+ // add trailing dot
+ if (id.size() == 0 || id.substr(id.size()-1) != ".") {
+ id += ".";
+ }
+
+ // special handling for the root zone, as a dot on it's own doesn't work
+ // everywhere.
+ if (id == ".") {
+ id = (boost::format("=%02X") % (int)('.')).str();
+ }
+ return id;
+}
+
+void apiCheckNameAllowedCharacters(const string& name) {
+ if (name.find_first_not_of("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234567890_/.-") != std::string::npos)
+ throw ApiException("Name '"+name+"' contains unsupported characters");
+}
+
+void apiCheckQNameAllowedCharacters(const string& qname) {
+ if (qname.compare(0, 2, "*.") == 0) apiCheckNameAllowedCharacters(qname.substr(2));
+ else apiCheckNameAllowedCharacters(qname);
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef PDNS_WSAPI_HH
+#define PDNS_WSAPI_HH
+
+#include <map>
+#include "webserver.hh"
+
+void apiDiscovery(HttpRequest* req, HttpResponse* resp);
+void apiServer(HttpRequest* req, HttpResponse* resp);
+void apiServerDetail(HttpRequest* req, HttpResponse* resp);
+void apiServerConfig(HttpRequest* req, HttpResponse* resp);
+void apiServerSearchLog(HttpRequest* req, HttpResponse* resp);
+void apiServerStatistics(HttpRequest* req, HttpResponse* resp);
+
+// helpers
+DNSName apiZoneIdToName(const string& id);
+string apiZoneNameToId(const DNSName& name);
+void apiCheckNameAllowedCharacters(const string& name);
+void apiCheckQNameAllowedCharacters(const string& name);
+DNSName apiNameToDNSName(const string& name);
+
+// To be provided by product code.
+void productServerStatisticsFetch(std::map<string,string>& out);
+
+#endif /* PDNS_WSAPI_HH */
--- /dev/null
+/*
+ Copyright (C) 2002 - 2016 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "utility.hh"
+#include "dynlistener.hh"
+#include "ws-auth.hh"
+#include "json.hh"
+#include "webserver.hh"
+#include "logger.hh"
+#include "packetcache.hh"
+#include "statbag.hh"
+#include "misc.hh"
+#include "arguments.hh"
+#include "dns.hh"
+#include "comment.hh"
+#include "ueberbackend.hh"
+#include <boost/format.hpp>
+
+#include "namespaces.hh"
+#include "ws-api.hh"
+#include "version.hh"
+#include "dnsseckeeper.hh"
+#include <iomanip>
+#include "zoneparser-tng.hh"
+#include "common_startup.hh"
+
+
+using json11::Json;
+
+extern StatBag S;
+extern PacketCache PC;
+
+static void patchZone(HttpRequest* req, HttpResponse* resp);
+static void storeChangedPTRs(UeberBackend& B, vector<DNSResourceRecord>& new_ptrs);
+static void makePtr(const DNSResourceRecord& rr, DNSResourceRecord* ptr);
+
+AuthWebServer::AuthWebServer()
+{
+ d_start=time(0);
+ d_min10=d_min5=d_min1=0;
+ d_ws = 0;
+ d_tid = 0;
+ if(arg().mustDo("webserver")) {
+ d_ws = new WebServer(arg()["webserver-address"], arg().asNum("webserver-port"));
+ d_ws->bind();
+ }
+}
+
+void AuthWebServer::go()
+{
+ if(arg().mustDo("webserver"))
+ {
+ S.doRings();
+ pthread_create(&d_tid, 0, webThreadHelper, this);
+ pthread_create(&d_tid, 0, statThreadHelper, this);
+ }
+}
+
+void AuthWebServer::statThread()
+{
+ try {
+ for(;;) {
+ d_queries.submit(S.read("udp-queries"));
+ d_cachehits.submit(S.read("packetcache-hit"));
+ d_cachemisses.submit(S.read("packetcache-miss"));
+ d_qcachehits.submit(S.read("query-cache-hit"));
+ d_qcachemisses.submit(S.read("query-cache-miss"));
+ Utility::sleep(1);
+ }
+ }
+ catch(...) {
+ L<<Logger::Error<<"Webserver statThread caught an exception, dying"<<endl;
+ exit(1);
+ }
+}
+
+void *AuthWebServer::statThreadHelper(void *p)
+{
+ AuthWebServer *self=static_cast<AuthWebServer *>(p);
+ self->statThread();
+ return 0; // never reached
+}
+
+void *AuthWebServer::webThreadHelper(void *p)
+{
+ AuthWebServer *self=static_cast<AuthWebServer *>(p);
+ self->webThread();
+ return 0; // never reached
+}
+
+static string htmlescape(const string &s) {
+ string result;
+ for(string::const_iterator it=s.begin(); it!=s.end(); ++it) {
+ switch (*it) {
+ case '&':
+ result += "&";
+ break;
+ case '<':
+ result += "<";
+ break;
+ case '>':
+ result += ">";
+ break;
+ case '"':
+ result += """;
+ break;
+ default:
+ result += *it;
+ }
+ }
+ return result;
+}
+
+void printtable(ostringstream &ret, const string &ringname, const string &title, int limit=10)
+{
+ int tot=0;
+ int entries=0;
+ vector<pair <string,unsigned int> >ring=S.getRing(ringname);
+
+ for(vector<pair<string, unsigned int> >::const_iterator i=ring.begin(); i!=ring.end();++i) {
+ tot+=i->second;
+ entries++;
+ }
+
+ ret<<"<div class=\"panel\">";
+ ret<<"<span class=resetring><i></i><a href=\"?resetring="<<htmlescape(ringname)<<"\">Reset</a></span>"<<endl;
+ ret<<"<h2>"<<title<<"</h2>"<<endl;
+ ret<<"<div class=ringmeta>";
+ ret<<"<a class=topXofY href=\"?ring="<<htmlescape(ringname)<<"\">Showing: Top "<<limit<<" of "<<entries<<"</a>"<<endl;
+ ret<<"<span class=resizering>Resize: ";
+ unsigned int sizes[]={10,100,500,1000,10000,500000,0};
+ for(int i=0;sizes[i];++i) {
+ if(S.getRingSize(ringname)!=sizes[i])
+ ret<<"<a href=\"?resizering="<<htmlescape(ringname)<<"&size="<<sizes[i]<<"\">"<<sizes[i]<<"</a> ";
+ else
+ ret<<"("<<sizes[i]<<") ";
+ }
+ ret<<"</span></div>";
+
+ ret<<"<table class=\"data\">";
+ int printed=0;
+ int total=max(1,tot);
+ for(vector<pair<string,unsigned int> >::const_iterator i=ring.begin();limit && i!=ring.end();++i,--limit) {
+ ret<<"<tr><td>"<<htmlescape(i->first)<<"</td><td>"<<i->second<<"</td><td align=right>"<< AuthWebServer::makePercentage(i->second*100.0/total)<<"</td>"<<endl;
+ printed+=i->second;
+ }
+ ret<<"<tr><td colspan=3></td></tr>"<<endl;
+ if(printed!=tot)
+ ret<<"<tr><td><b>Rest:</b></td><td><b>"<<tot-printed<<"</b></td><td align=right><b>"<< AuthWebServer::makePercentage((tot-printed)*100.0/total)<<"</b></td>"<<endl;
+
+ ret<<"<tr><td><b>Total:</b></td><td><b>"<<tot<<"</b></td><td align=right><b>100%</b></td>";
+ ret<<"</table></div>"<<endl;
+}
+
+void AuthWebServer::printvars(ostringstream &ret)
+{
+ ret<<"<div class=panel><h2>Variables</h2><table class=\"data\">"<<endl;
+
+ vector<string>entries=S.getEntries();
+ for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i) {
+ ret<<"<tr><td>"<<*i<<"</td><td>"<<S.read(*i)<<"</td><td>"<<S.getDescrip(*i)<<"</td>"<<endl;
+ }
+
+ ret<<"</table></div>"<<endl;
+}
+
+void AuthWebServer::printargs(ostringstream &ret)
+{
+ ret<<"<table border=1><tr><td colspan=3 bgcolor=\"#0000ff\"><font color=\"#ffffff\">Arguments</font></td>"<<endl;
+
+ vector<string>entries=arg().list();
+ for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i) {
+ ret<<"<tr><td>"<<*i<<"</td><td>"<<arg()[*i]<<"</td><td>"<<arg().getHelp(*i)<<"</td>"<<endl;
+ }
+}
+
+string AuthWebServer::makePercentage(const double& val)
+{
+ return (boost::format("%.01f%%") % val).str();
+}
+
+void AuthWebServer::indexfunction(HttpRequest* req, HttpResponse* resp)
+{
+ if(!req->getvars["resetring"].empty()) {
+ if (S.ringExists(req->getvars["resetring"]))
+ S.resetRing(req->getvars["resetring"]);
+ resp->status = 301;
+ resp->headers["Location"] = req->url.path;
+ return;
+ }
+ if(!req->getvars["resizering"].empty()){
+ int size=std::stoi(req->getvars["size"]);
+ if (S.ringExists(req->getvars["resizering"]) && size > 0 && size <= 500000)
+ S.resizeRing(req->getvars["resizering"], std::stoi(req->getvars["size"]));
+ resp->status = 301;
+ resp->headers["Location"] = req->url.path;
+ return;
+ }
+
+ ostringstream ret;
+
+ ret<<"<!DOCTYPE html>"<<endl;
+ ret<<"<html><head>"<<endl;
+ ret<<"<title>PowerDNS Authoritative Server Monitor</title>"<<endl;
+ ret<<"<link rel=\"stylesheet\" href=\"style.css\"/>"<<endl;
+ ret<<"</head><body>"<<endl;
+
+ ret<<"<div class=\"row\">"<<endl;
+ ret<<"<div class=\"headl columns\">";
+ ret<<"<a href=\"/\" id=\"appname\">PowerDNS "<<htmlescape(VERSION);
+ if(!arg()["config-name"].empty()) {
+ ret<<" ["<<htmlescape(arg()["config-name"])<<"]";
+ }
+ ret<<"</a></div>"<<endl;
+ ret<<"<div class=\"headr columns\"></div></div>";
+ ret<<"<div class=\"row\"><div class=\"all columns\">";
+
+ time_t passed=time(0)-s_starttime;
+
+ ret<<"<p>Uptime: "<<
+ humanDuration(passed)<<
+ "<br>"<<endl;
+
+ ret<<"Queries/second, 1, 5, 10 minute averages: "<<std::setprecision(3)<<
+ d_queries.get1()<<", "<<
+ d_queries.get5()<<", "<<
+ d_queries.get10()<<". Max queries/second: "<<d_queries.getMax()<<
+ "<br>"<<endl;
+
+ if(d_cachemisses.get10()+d_cachehits.get10()>0)
+ ret<<"Cache hitrate, 1, 5, 10 minute averages: "<<
+ makePercentage((d_cachehits.get1()*100.0)/((d_cachehits.get1())+(d_cachemisses.get1())))<<", "<<
+ makePercentage((d_cachehits.get5()*100.0)/((d_cachehits.get5())+(d_cachemisses.get5())))<<", "<<
+ makePercentage((d_cachehits.get10()*100.0)/((d_cachehits.get10())+(d_cachemisses.get10())))<<
+ "<br>"<<endl;
+
+ if(d_qcachemisses.get10()+d_qcachehits.get10()>0)
+ ret<<"Backend query cache hitrate, 1, 5, 10 minute averages: "<<std::setprecision(2)<<
+ makePercentage((d_qcachehits.get1()*100.0)/((d_qcachehits.get1())+(d_qcachemisses.get1())))<<", "<<
+ makePercentage((d_qcachehits.get5()*100.0)/((d_qcachehits.get5())+(d_qcachemisses.get5())))<<", "<<
+ makePercentage((d_qcachehits.get10()*100.0)/((d_qcachehits.get10())+(d_qcachemisses.get10())))<<
+ "<br>"<<endl;
+
+ ret<<"Backend query load, 1, 5, 10 minute averages: "<<std::setprecision(3)<<
+ d_qcachemisses.get1()<<", "<<
+ d_qcachemisses.get5()<<", "<<
+ d_qcachemisses.get10()<<". Max queries/second: "<<d_qcachemisses.getMax()<<
+ "<br>"<<endl;
+
+ ret<<"Total queries: "<<S.read("udp-queries")<<". Question/answer latency: "<<S.read("latency")/1000.0<<"ms</p><br>"<<endl;
+ if(req->getvars["ring"].empty()) {
+ vector<string>entries=S.listRings();
+ for(vector<string>::const_iterator i=entries.begin();i!=entries.end();++i)
+ printtable(ret,*i,S.getRingTitle(*i));
+
+ printvars(ret);
+ if(arg().mustDo("webserver-print-arguments"))
+ printargs(ret);
+ }
+ else if(S.ringExists(req->getvars["ring"]))
+ printtable(ret,req->getvars["ring"],S.getRingTitle(req->getvars["ring"]),100);
+
+ ret<<"</div></div>"<<endl;
+ ret<<"<footer class=\"row\">"<<fullVersionString()<<"<br>© 2013 - 2016 <a href=\"http://www.powerdns.com/\">PowerDNS.COM BV</a>.</footer>"<<endl;
+ ret<<"</body></html>"<<endl;
+
+ resp->body = ret.str();
+ resp->status = 200;
+}
+
+/** Helper to build a record content as needed. */
+static inline string makeRecordContent(const QType& qtype, const string& content, bool noDot) {
+ // noDot: for backend storage, pass true. for API users, pass false.
+ std::unique_ptr<DNSRecordContent> drc(DNSRecordContent::mastermake(qtype.getCode(), 1, content));
+ return drc->getZoneRepresentation(noDot);
+}
+
+/** "Normalize" record content for API consumers. */
+static inline string makeApiRecordContent(const QType& qtype, const string& content) {
+ return makeRecordContent(qtype, content, false);
+}
+
+/** "Normalize" record content for backend storage. */
+static inline string makeBackendRecordContent(const QType& qtype, const string& content) {
+ return makeRecordContent(qtype, content, true);
+}
+
+static Json::object getZoneInfo(const DomainInfo& di) {
+ DNSSECKeeper dk;
+ string zoneId = apiZoneNameToId(di.zone);
+ return Json::object {
+ // id is the canonical lookup key, which doesn't actually match the name (in some cases)
+ { "id", zoneId },
+ { "url", "api/v1/servers/localhost/zones/" + zoneId },
+ { "name", di.zone.toString() },
+ { "kind", di.getKindString() },
+ { "dnssec", dk.isSecuredZone(di.zone) },
+ { "account", di.account },
+ { "masters", di.masters },
+ { "serial", (double)di.serial },
+ { "notified_serial", (double)di.notified_serial },
+ { "last_check", (double)di.last_check }
+ };
+}
+
+static void fillZone(const DNSName& zonename, HttpResponse* resp) {
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ Json::object doc = getZoneInfo(di);
+ // extra stuff getZoneInfo doesn't do for us (more expensive)
+ string soa_edit_api;
+ di.backend->getDomainMetadataOne(zonename, "SOA-EDIT-API", soa_edit_api);
+ doc["soa_edit_api"] = soa_edit_api;
+ string soa_edit;
+ di.backend->getDomainMetadataOne(zonename, "SOA-EDIT", soa_edit);
+ doc["soa_edit"] = soa_edit;
+
+ vector<DNSResourceRecord> records;
+ vector<Comment> comments;
+
+ // load all records + sort
+ {
+ DNSResourceRecord rr;
+ di.backend->list(zonename, di.id, true); // incl. disabled
+ while(di.backend->get(rr)) {
+ if (!rr.qtype.getCode())
+ continue; // skip empty non-terminals
+ records.push_back(rr);
+ }
+ sort(records.begin(), records.end(), [](const DNSResourceRecord& a, const DNSResourceRecord& b) {
+ if (a.qname == b.qname) {
+ return b.qtype < a.qtype;
+ }
+ return b.qname < a.qname;
+ });
+ }
+
+ // load all comments + sort
+ {
+ Comment comment;
+ di.backend->listComments(di.id);
+ while(di.backend->getComment(comment)) {
+ comments.push_back(comment);
+ }
+ sort(comments.begin(), comments.end(), [](const Comment& a, const Comment& b) {
+ if (a.qname == b.qname) {
+ return b.qtype < a.qtype;
+ }
+ return b.qname < a.qname;
+ });
+ }
+
+ Json::array rrsets;
+ Json::object rrset;
+ Json::array rrset_records;
+ Json::array rrset_comments;
+ DNSName current_qname;
+ QType current_qtype;
+ uint32_t ttl;
+ auto rit = records.begin();
+ auto cit = comments.begin();
+
+ while (rit != records.end() || cit != comments.end()) {
+ if (cit == comments.end() || (rit != records.end() && (cit->qname.toString() <= rit->qname.toString() || cit->qtype < rit->qtype || cit->qtype == rit->qtype))) {
+ current_qname = rit->qname;
+ current_qtype = rit->qtype;
+ ttl = rit->ttl;
+ } else {
+ current_qname = cit->qname;
+ current_qtype = cit->qtype;
+ ttl = 0;
+ }
+
+ while(rit != records.end() && rit->qname == current_qname && rit->qtype == current_qtype) {
+ ttl = min(ttl, rit->ttl);
+ rrset_records.push_back(Json::object {
+ { "disabled", rit->disabled },
+ { "content", makeApiRecordContent(rit->qtype, rit->content) }
+ });
+ rit++;
+ }
+ while (cit != comments.end() && cit->qname == current_qname && cit->qtype == current_qtype) {
+ rrset_comments.push_back(Json::object {
+ { "modified_at", (double)cit->modified_at },
+ { "account", cit->account },
+ { "content", cit->content }
+ });
+ cit++;
+ }
+
+ rrset["name"] = current_qname.toString();
+ rrset["type"] = current_qtype.getName();
+ rrset["records"] = rrset_records;
+ rrset["comments"] = rrset_comments;
+ rrset["ttl"] = (double)ttl;
+ rrsets.push_back(rrset);
+ rrset.clear();
+ rrset_records.clear();
+ rrset_comments.clear();
+ }
+
+ doc["rrsets"] = rrsets;
+
+ resp->setBody(doc);
+}
+
+void productServerStatisticsFetch(map<string,string>& out)
+{
+ vector<string> items = S.getEntries();
+ for(const string& item : items) {
+ out[item] = std::to_string(S.read(item));
+ }
+
+ // add uptime
+ out["uptime"] = std::to_string(time(0) - s_starttime);
+}
+
+static void gatherRecords(const Json container, const DNSName& qname, const QType qtype, const int ttl, vector<DNSResourceRecord>& new_records, vector<DNSResourceRecord>& new_ptrs) {
+ UeberBackend B;
+ DNSResourceRecord rr;
+ rr.qname = qname;
+ rr.qtype = qtype;
+ rr.auth = 1;
+ rr.ttl = ttl;
+ for(auto record : container["records"].array_items()) {
+ string content = stringFromJson(record, "content");
+ rr.disabled = boolFromJson(record, "disabled");
+
+ // validate that the client sent something we can actually parse, and require that data to be dotted.
+ try {
+ if (rr.qtype.getCode() != QType::AAAA) {
+ string tmp = makeApiRecordContent(rr.qtype, content);
+ if (!pdns_iequals(tmp, content)) {
+ throw std::runtime_error("Not in expected format (parsed as '"+tmp+"')");
+ }
+ } else {
+ struct in6_addr tmpbuf;
+ if (inet_pton(AF_INET6, content.c_str(), &tmpbuf) != 1 || content.find('.') != string::npos) {
+ throw std::runtime_error("Invalid IPv6 address");
+ }
+ }
+ rr.content = makeBackendRecordContent(rr.qtype, content);
+ }
+ catch(std::exception& e)
+ {
+ throw ApiException("Record "+rr.qname.toString()+"/"+rr.qtype.getName()+" '"+content+"': "+e.what());
+ }
+
+ if ((rr.qtype.getCode() == QType::A || rr.qtype.getCode() == QType::AAAA) &&
+ boolFromJson(record, "set-ptr", false) == true) {
+ DNSResourceRecord ptr;
+ makePtr(rr, &ptr);
+
+ // verify that there's a zone for the PTR
+ DNSPacket fakePacket(false);
+ SOAData sd;
+ fakePacket.qtype = QType::PTR;
+ if (!B.getAuth(&fakePacket, &sd, ptr.qname))
+ throw ApiException("Could not find domain for PTR '"+ptr.qname.toString()+"' requested for '"+ptr.content+"'");
+
+ ptr.domain_id = sd.domain_id;
+ new_ptrs.push_back(ptr);
+ }
+
+ new_records.push_back(rr);
+ }
+}
+
+static void gatherComments(const Json container, const DNSName& qname, const QType qtype, vector<Comment>& new_comments) {
+ Comment c;
+ c.qname = qname;
+ c.qtype = qtype;
+
+ time_t now = time(0);
+ for (auto comment : container["comments"].array_items()) {
+ c.modified_at = intFromJson(comment, "modified_at", now);
+ c.content = stringFromJson(comment, "content");
+ c.account = stringFromJson(comment, "account");
+ new_comments.push_back(c);
+ }
+}
+
+static void updateDomainSettingsFromDocument(const DomainInfo& di, const DNSName& zonename, const Json document) {
+ string zonemaster;
+ for(auto value : document["masters"].array_items()) {
+ string master = value.string_value();
+ if (master.empty())
+ throw ApiException("Master can not be an empty string");
+ zonemaster += master + " ";
+ }
+
+ di.backend->setKind(zonename, DomainInfo::stringToKind(stringFromJson(document, "kind")));
+ di.backend->setMaster(zonename, zonemaster);
+
+ if (document["soa_edit_api"].is_string()) {
+ di.backend->setDomainMetadataOne(zonename, "SOA-EDIT-API", document["soa_edit_api"].string_value());
+ }
+ if (document["soa_edit"].is_string()) {
+ di.backend->setDomainMetadataOne(zonename, "SOA-EDIT", document["soa_edit"].string_value());
+ }
+ if (document["account"].is_string()) {
+ di.backend->setAccount(zonename, document["account"].string_value());
+ }
+}
+
+static void apiZoneCryptokeys(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw ApiException("Only GET is implemented");
+
+ bool inquireSingleKey = false;
+ unsigned int inquireKeyId = 0;
+ if (req->parameters.count("key_id")) {
+ inquireSingleKey = true;
+ inquireKeyId = std::stoi(req->parameters["key_id"]);
+ }
+
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+
+ UeberBackend B;
+ DNSSECKeeper dk(&B);
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw HttpNotFoundException();
+
+ DNSSECKeeper::keyset_t keyset=dk.getKeys(zonename, false);
+
+ Json::array doc;
+ for(const auto& value : keyset) {
+ if (inquireSingleKey && inquireKeyId != value.second.id) {
+ continue;
+ }
+
+ string keyType;
+ switch(value.second.keyType){
+ case DNSSECKeeper::KSK: keyType="ksk"; break;
+ case DNSSECKeeper::ZSK: keyType="zsk"; break;
+ case DNSSECKeeper::CSK: keyType="csk"; break;
+ }
+
+ Json::object key {
+ { "type", "Cryptokey" },
+ { "id", (int)value.second.id },
+ { "active", value.second.active },
+ { "keytype", keyType },
+ { "flags", (uint16_t)value.first.d_flags },
+ { "dnskey", value.first.getDNSKEY().getZoneRepresentation() }
+ };
+
+ if (value.second.keyType == DNSSECKeeper::KSK || value.second.keyType == DNSSECKeeper::CSK) {
+ Json::array dses;
+ for(const int keyid : { 1, 2, 3, 4 })
+ try {
+ dses.push_back(makeDSFromDNSKey(zonename, value.first.getDNSKEY(), keyid).getZoneRepresentation());
+ } catch (...) {}
+ key["ds"] = dses;
+ }
+
+ if (inquireSingleKey) {
+ key["privatekey"] = value.first.getKey()->convertToISC();
+ resp->setBody(key);
+ return;
+ }
+ doc.push_back(key);
+ }
+
+ if (inquireSingleKey) {
+ // we came here because we couldn't find the requested key.
+ throw HttpNotFoundException();
+ }
+ resp->setBody(doc);
+}
+
+static void gatherRecordsFromZone(const std::string& zonestring, vector<DNSResourceRecord>& new_records, DNSName zonename) {
+ DNSResourceRecord rr;
+ vector<string> zonedata;
+ stringtok(zonedata, zonestring, "\r\n");
+
+ ZoneParserTNG zpt(zonedata, zonename);
+
+ bool seenSOA=false;
+
+ string comment = "Imported via the API";
+
+ try {
+ while(zpt.get(rr, &comment)) {
+ if(seenSOA && rr.qtype.getCode() == QType::SOA)
+ continue;
+ if(rr.qtype.getCode() == QType::SOA)
+ seenSOA=true;
+
+ new_records.push_back(rr);
+ }
+ }
+ catch(std::exception& ae) {
+ throw ApiException("An error occurred while parsing the zonedata: "+string(ae.what()));
+ }
+}
+
+static void apiServerZones(HttpRequest* req, HttpResponse* resp) {
+ UeberBackend B;
+ DNSSECKeeper dk(&B);
+ if (req->method == "POST" && !::arg().mustDo("api-readonly")) {
+ DomainInfo di;
+ auto document = req->json();
+ DNSName zonename = apiNameToDNSName(stringFromJson(document, "name"));
+ apiCheckNameAllowedCharacters(zonename.toString());
+
+ bool exists = B.getDomainInfo(zonename, di);
+ if(exists)
+ throw ApiException("Domain '"+zonename.toString()+"' already exists");
+
+ // validate 'kind' is set
+ DomainInfo::DomainKind zonekind = DomainInfo::stringToKind(stringFromJson(document, "kind"));
+
+ string zonestring = document["zone"].string_value();
+ auto rrsets = document["rrsets"];
+ if (rrsets.is_array() && zonestring != "")
+ throw ApiException("You cannot give rrsets AND zone data as text");
+
+ auto nameservers = document["nameservers"];
+ if (!nameservers.is_array() && zonekind != DomainInfo::Slave)
+ throw ApiException("Nameservers list must be given (but can be empty if NS records are supplied)");
+
+ string soa_edit_api_kind;
+ if (document["soa_edit_api"].is_string()) {
+ soa_edit_api_kind = document["soa_edit_api"].string_value();
+ }
+ else {
+ soa_edit_api_kind = "DEFAULT";
+ }
+ string soa_edit_kind = document["soa_edit"].string_value();
+
+ // if records/comments are given, load and check them
+ bool have_soa = false;
+ vector<DNSResourceRecord> new_records;
+ vector<Comment> new_comments;
+ vector<DNSResourceRecord> new_ptrs;
+
+ if (rrsets.is_array()) {
+ for (const auto& rrset : rrsets.array_items()) {
+ DNSName qname = apiNameToDNSName(stringFromJson(rrset, "name"));
+ apiCheckQNameAllowedCharacters(qname.toString());
+ QType qtype;
+ qtype = stringFromJson(rrset, "type");
+ if (qtype.getCode() == 0) {
+ throw ApiException("RRset "+qname.toString()+" IN "+stringFromJson(rrset, "type")+": unknown type given");
+ }
+ if (rrset["records"].is_array()) {
+ int ttl = intFromJson(rrset, "ttl");
+ gatherRecords(rrset, qname, qtype, ttl, new_records, new_ptrs);
+ }
+ if (rrset["comments"].is_array()) {
+ gatherComments(rrset, qname, qtype, new_comments);
+ }
+ }
+ } else if (zonestring != "") {
+ gatherRecordsFromZone(zonestring, new_records, zonename);
+ }
+
+ for(auto& rr : new_records) {
+ if (!rr.qname.isPartOf(zonename) && rr.qname != zonename)
+ throw ApiException("RRset "+rr.qname.toString()+" IN "+rr.qtype.getName()+": Name is out of zone");
+ apiCheckQNameAllowedCharacters(rr.qname.toString());
+
+ if (rr.qtype.getCode() == QType::SOA && rr.qname==zonename) {
+ have_soa = true;
+ increaseSOARecord(rr, soa_edit_api_kind, soa_edit_kind);
+ // fixup dots after serializeSOAData/increaseSOARecord
+ rr.content = makeBackendRecordContent(rr.qtype, rr.content);
+ }
+ }
+
+ // synthesize RRs as needed
+ DNSResourceRecord autorr;
+ autorr.qname = zonename;
+ autorr.auth = 1;
+ autorr.ttl = ::arg().asNum("default-ttl");
+
+ if (!have_soa && zonekind != DomainInfo::Slave) {
+ // synthesize a SOA record so the zone "really" exists
+ string soa = (boost::format("%s %s %lu")
+ % ::arg()["default-soa-name"]
+ % (::arg().isEmpty("default-soa-mail") ? (DNSName("hostmaster.") + zonename).toString() : ::arg()["default-soa-mail"])
+ % document["serial"].int_value()
+ ).str();
+ SOAData sd;
+ fillSOAData(soa, sd); // fills out default values for us
+ autorr.qtype = "SOA";
+ autorr.content = serializeSOAData(sd);
+ increaseSOARecord(autorr, soa_edit_api_kind, soa_edit_kind);
+ // fixup dots after serializeSOAData/increaseSOARecord
+ autorr.content = makeBackendRecordContent(autorr.qtype, autorr.content);
+ new_records.push_back(autorr);
+ }
+
+ // create NS records if nameservers are given
+ for (auto value : nameservers.array_items()) {
+ string nameserver = value.string_value();
+ if (nameserver.empty())
+ throw ApiException("Nameservers must be non-empty strings");
+ if (!isCanonical(nameserver))
+ throw ApiException("Nameserver is not canonical: '" + nameserver + "'");
+ try {
+ // ensure the name parses
+ autorr.content = DNSName(nameserver).toStringRootDot();
+ } catch (...) {
+ throw ApiException("Unable to parse DNS Name for NS '" + nameserver + "'");
+ }
+ autorr.qtype = "NS";
+ new_records.push_back(autorr);
+ }
+
+ // no going back after this
+ if(!B.createDomain(zonename))
+ throw ApiException("Creating domain '"+zonename.toString()+"' failed");
+
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Creating domain '"+zonename.toString()+"' failed: lookup of domain ID failed");
+
+ // updateDomainSettingsFromDocument does NOT fill out the default we've established above.
+ if (!soa_edit_api_kind.empty()) {
+ di.backend->setDomainMetadataOne(zonename, "SOA-EDIT-API", soa_edit_api_kind);
+ }
+
+ di.backend->startTransaction(zonename, di.id);
+
+ for(auto rr : new_records) {
+ rr.domain_id = di.id;
+ di.backend->feedRecord(rr);
+ }
+ for(Comment& c : new_comments) {
+ c.domain_id = di.id;
+ di.backend->feedComment(c);
+ }
+
+ updateDomainSettingsFromDocument(di, zonename, document);
+
+ di.backend->commitTransaction();
+
+ storeChangedPTRs(B, new_ptrs);
+
+ fillZone(zonename, resp);
+ resp->status = 201;
+ return;
+ }
+
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ vector<DomainInfo> domains;
+ B.getAllDomains(&domains, true); // incl. disabled
+
+ Json::array doc;
+ for(const DomainInfo& di : domains) {
+ doc.push_back(getZoneInfo(di));
+ }
+ resp->setBody(doc);
+}
+
+static void apiServerZoneDetail(HttpRequest* req, HttpResponse* resp) {
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+
+ if(req->method == "PUT" && !::arg().mustDo("api-readonly")) {
+ // update domain settings
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ updateDomainSettingsFromDocument(di, zonename, req->json());
+
+ resp->body = "";
+ resp->status = 204; // No Content, but indicate success
+ return;
+ }
+ else if(req->method == "DELETE" && !::arg().mustDo("api-readonly")) {
+ // delete domain
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ if(!di.backend->deleteDomain(zonename))
+ throw ApiException("Deleting domain '"+zonename.toString()+"' failed: backend delete failed/unsupported");
+
+ // empty body on success
+ resp->body = "";
+ resp->status = 204; // No Content: declare that the zone is gone now
+ return;
+ } else if (req->method == "PATCH" && !::arg().mustDo("api-readonly")) {
+ patchZone(req, resp);
+ return;
+ } else if (req->method == "GET") {
+ fillZone(zonename, resp);
+ return;
+ }
+
+ throw HttpMethodNotAllowedException();
+}
+
+static void apiServerZoneExport(HttpRequest* req, HttpResponse* resp) {
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ ostringstream ss;
+
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ DNSResourceRecord rr;
+ SOAData sd;
+ di.backend->list(zonename, di.id);
+ while(di.backend->get(rr)) {
+ if (!rr.qtype.getCode())
+ continue; // skip empty non-terminals
+
+ ss <<
+ rr.qname.toString() << "\t" <<
+ rr.ttl << "\t" <<
+ rr.qtype.getName() << "\t" <<
+ makeApiRecordContent(rr.qtype, rr.content) <<
+ endl;
+ }
+
+ if (req->accept_json) {
+ resp->setBody(Json::object { { "zone", ss.str() } });
+ } else {
+ resp->headers["Content-Type"] = "text/plain; charset=us-ascii";
+ resp->body = ss.str();
+ }
+}
+
+static void apiServerZoneAxfrRetrieve(HttpRequest* req, HttpResponse* resp) {
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+
+ if(req->method != "PUT")
+ throw HttpMethodNotAllowedException();
+
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ if(di.masters.empty())
+ throw ApiException("Domain '"+zonename.toString()+"' is not a slave domain (or has no master defined)");
+
+ random_shuffle(di.masters.begin(), di.masters.end());
+ Communicator.addSuckRequest(zonename, di.masters.front());
+ resp->setSuccessResult("Added retrieval request for '"+zonename.toString()+"' from master "+di.masters.front());
+}
+
+static void apiServerZoneNotify(HttpRequest* req, HttpResponse* resp) {
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+
+ if(req->method != "PUT")
+ throw HttpMethodNotAllowedException();
+
+ UeberBackend B;
+ DomainInfo di;
+ if(!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ if(!Communicator.notifyDomain(zonename))
+ throw ApiException("Failed to add to the queue - see server log");
+
+ resp->setSuccessResult("Notification queued");
+}
+
+static void makePtr(const DNSResourceRecord& rr, DNSResourceRecord* ptr) {
+ if (rr.qtype.getCode() == QType::A) {
+ uint32_t ip;
+ if (!IpToU32(rr.content, &ip)) {
+ throw ApiException("PTR: Invalid IP address given");
+ }
+ ptr->qname = DNSName((boost::format("%u.%u.%u.%u.in-addr.arpa.")
+ % ((ip >> 24) & 0xff)
+ % ((ip >> 16) & 0xff)
+ % ((ip >> 8) & 0xff)
+ % ((ip ) & 0xff)
+ ).str());
+ } else if (rr.qtype.getCode() == QType::AAAA) {
+ ComboAddress ca(rr.content);
+ char buf[3];
+ ostringstream ss;
+ for (int octet = 0; octet < 16; ++octet) {
+ if (snprintf(buf, sizeof(buf), "%02x", ca.sin6.sin6_addr.s6_addr[octet]) != (sizeof(buf)-1)) {
+ // this should be impossible: no byte should give more than two digits in hex format
+ throw PDNSException("Formatting IPv6 address failed");
+ }
+ ss << buf[0] << '.' << buf[1] << '.';
+ }
+ string tmp = ss.str();
+ tmp.resize(tmp.size()-1); // remove last dot
+ // reverse and append arpa domain
+ ptr->qname = DNSName(string(tmp.rbegin(), tmp.rend())) + DNSName("ip6.arpa.");
+ } else {
+ throw ApiException("Unsupported PTR source '" + rr.qname.toString() + "' type '" + rr.qtype.getName() + "'");
+ }
+
+ ptr->qtype = "PTR";
+ ptr->ttl = rr.ttl;
+ ptr->disabled = rr.disabled;
+ ptr->content = rr.qname.toStringRootDot();
+}
+
+static void storeChangedPTRs(UeberBackend& B, vector<DNSResourceRecord>& new_ptrs) {
+ for(const DNSResourceRecord& rr : new_ptrs) {
+ DNSPacket fakePacket(false);
+ SOAData sd;
+ sd.db = (DNSBackend *)-1; // getAuth() cache bypass
+ fakePacket.qtype = QType::PTR;
+
+ if (!B.getAuth(&fakePacket, &sd, rr.qname))
+ throw ApiException("Could not find domain for PTR '"+rr.qname.toString()+"' requested for '"+rr.content+"' (while saving)");
+
+ string soa_edit_api_kind;
+ string soa_edit_kind;
+ bool soa_changed = false;
+ DNSResourceRecord soarr;
+ sd.db->getDomainMetadataOne(sd.qname, "SOA-EDIT-API", soa_edit_api_kind);
+ sd.db->getDomainMetadataOne(sd.qname, "SOA-EDIT", soa_edit_kind);
+ if (!soa_edit_api_kind.empty()) {
+ soarr.qname = sd.qname;
+ soarr.content = serializeSOAData(sd);
+ soarr.qtype = "SOA";
+ soarr.domain_id = sd.domain_id;
+ soarr.auth = 1;
+ soarr.ttl = sd.ttl;
+ increaseSOARecord(soarr, soa_edit_api_kind, soa_edit_kind);
+ // fixup dots after serializeSOAData/increaseSOARecord
+ soarr.content = makeBackendRecordContent(soarr.qtype, soarr.content);
+ soa_changed = true;
+ }
+
+ sd.db->startTransaction(sd.qname);
+ if (!sd.db->replaceRRSet(sd.domain_id, rr.qname, rr.qtype, vector<DNSResourceRecord>(1, rr))) {
+ sd.db->abortTransaction();
+ throw ApiException("PTR-Hosting backend for "+rr.qname.toString()+"/"+rr.qtype.getName()+" does not support editing records.");
+ }
+
+ if (soa_changed) {
+ sd.db->replaceRRSet(sd.domain_id, soarr.qname, soarr.qtype, vector<DNSResourceRecord>(1, soarr));
+ }
+
+ sd.db->commitTransaction();
+ PC.purgeExact(rr.qname);
+ }
+}
+
+static void patchZone(HttpRequest* req, HttpResponse* resp) {
+ UeberBackend B;
+ DomainInfo di;
+ DNSName zonename = apiZoneIdToName(req->parameters["id"]);
+ if (!B.getDomainInfo(zonename, di))
+ throw ApiException("Could not find domain '"+zonename.toString()+"'");
+
+ vector<DNSResourceRecord> new_records;
+ vector<Comment> new_comments;
+ vector<DNSResourceRecord> new_ptrs;
+
+ Json document = req->json();
+
+ auto rrsets = document["rrsets"];
+ if (!rrsets.is_array())
+ throw ApiException("No rrsets given in update request");
+
+ di.backend->startTransaction(zonename);
+
+ try {
+ string soa_edit_api_kind;
+ string soa_edit_kind;
+ di.backend->getDomainMetadataOne(zonename, "SOA-EDIT-API", soa_edit_api_kind);
+ di.backend->getDomainMetadataOne(zonename, "SOA-EDIT", soa_edit_kind);
+ bool soa_edit_done = false;
+
+ for (const auto& rrset : rrsets.array_items()) {
+ string changetype = toUpper(stringFromJson(rrset, "changetype"));
+ DNSName qname = apiNameToDNSName(stringFromJson(rrset, "name"));
+ apiCheckQNameAllowedCharacters(qname.toString());
+ QType qtype;
+ qtype = stringFromJson(rrset, "type");
+ if (qtype.getCode() == 0) {
+ throw ApiException("RRset "+qname.toString()+" IN "+stringFromJson(rrset, "type")+": unknown type given");
+ }
+
+ if (changetype == "DELETE") {
+ // delete all matching qname/qtype RRs (and, implictly comments).
+ if (!di.backend->replaceRRSet(di.id, qname, qtype, vector<DNSResourceRecord>())) {
+ throw ApiException("Hosting backend does not support editing records.");
+ }
+ }
+ else if (changetype == "REPLACE") {
+ // we only validate for REPLACE, as DELETE can be used to "fix" out of zone records.
+ if (!qname.isPartOf(zonename) && qname != zonename)
+ throw ApiException("RRset "+qname.toString()+" IN "+qtype.getName()+": Name is out of zone");
+
+ bool replace_records = rrset["records"].is_array();
+ bool replace_comments = rrset["comments"].is_array();
+
+ if (!replace_records && !replace_comments) {
+ throw ApiException("No change for RRset " + qname.toString() + " IN " + qtype.getName());
+ }
+
+ new_records.clear();
+ new_comments.clear();
+
+ if (replace_records) {
+ // ttl shouldn't be part of DELETE, and it shouldn't be required if we don't get new records.
+ int ttl = intFromJson(rrset, "ttl");
+ // new_ptrs is merged.
+ gatherRecords(rrset, qname, qtype, ttl, new_records, new_ptrs);
+
+ for(DNSResourceRecord& rr : new_records) {
+ rr.domain_id = di.id;
+ if (rr.qtype.getCode() == QType::SOA && rr.qname==zonename) {
+ soa_edit_done = increaseSOARecord(rr, soa_edit_api_kind, soa_edit_kind);
+ rr.content = makeBackendRecordContent(rr.qtype, rr.content);
+ }
+ }
+ }
+
+ if (replace_comments) {
+ gatherComments(rrset, qname, qtype, new_comments);
+
+ for(Comment& c : new_comments) {
+ c.domain_id = di.id;
+ }
+ }
+
+ if (replace_records) {
+ if (!di.backend->replaceRRSet(di.id, qname, qtype, new_records)) {
+ throw ApiException("Hosting backend does not support editing records.");
+ }
+ }
+ if (replace_comments) {
+ if (!di.backend->replaceComments(di.id, qname, qtype, new_comments)) {
+ throw ApiException("Hosting backend does not support editing comments.");
+ }
+ }
+ }
+ else
+ throw ApiException("Changetype not understood");
+ }
+
+ // edit SOA (if needed)
+ if (!soa_edit_api_kind.empty() && !soa_edit_done) {
+ SOAData sd;
+ if (!B.getSOA(zonename, sd))
+ throw ApiException("No SOA found for domain '"+zonename.toString()+"'");
+
+ DNSResourceRecord rr;
+ rr.qname = zonename;
+ rr.content = serializeSOAData(sd);
+ rr.qtype = "SOA";
+ rr.domain_id = di.id;
+ rr.auth = 1;
+ rr.ttl = sd.ttl;
+ increaseSOARecord(rr, soa_edit_api_kind, soa_edit_kind);
+ // fixup dots after serializeSOAData/increaseSOARecord
+ rr.content = makeBackendRecordContent(rr.qtype, rr.content);
+
+ if (!di.backend->replaceRRSet(di.id, rr.qname, rr.qtype, vector<DNSResourceRecord>(1, rr))) {
+ throw ApiException("Hosting backend does not support editing records.");
+ }
+ }
+
+ } catch(...) {
+ di.backend->abortTransaction();
+ throw;
+ }
+ di.backend->commitTransaction();
+
+ PC.purgeExact(zonename);
+
+ // now the PTRs
+ storeChangedPTRs(B, new_ptrs);
+
+ resp->body = "";
+ resp->status = 204; // No Content, but indicate success
+ return;
+}
+
+static void apiServerSearchData(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "GET")
+ throw HttpMethodNotAllowedException();
+
+ string q = req->getvars["q"];
+ string sMax = req->getvars["max"];
+ int maxEnts = 100;
+ int ents = 0;
+
+ if (q.empty())
+ throw ApiException("Query q can't be blank");
+ if (sMax.empty() == false)
+ maxEnts = std::stoi(sMax);
+ if (maxEnts < 1)
+ throw ApiException("Maximum entries must be larger than 0");
+
+ SimpleMatch sm(q,true);
+ UeberBackend B;
+ vector<DomainInfo> domains;
+ vector<DNSResourceRecord> result_rr;
+ vector<Comment> result_c;
+ map<int,DomainInfo> zoneIdZone;
+ map<int,DomainInfo>::iterator val;
+ Json::array doc;
+
+ B.getAllDomains(&domains, true);
+
+ for(const DomainInfo di: domains)
+ {
+ if (ents < maxEnts && sm.match(di.zone)) {
+ doc.push_back(Json::object {
+ { "object_type", "zone" },
+ { "zone_id", apiZoneNameToId(di.zone) },
+ { "name", di.zone.toString() }
+ });
+ ents++;
+ }
+ zoneIdZone[di.id] = di; // populate cache
+ }
+
+ if (B.searchRecords(q, maxEnts, result_rr))
+ {
+ for(const DNSResourceRecord& rr: result_rr)
+ {
+ if (!rr.qtype.getCode())
+ continue; // skip empty non-terminals
+
+ auto object = Json::object {
+ { "object_type", "record" },
+ { "name", rr.qname.toString() },
+ { "type", rr.qtype.getName() },
+ { "ttl", (double)rr.ttl },
+ { "disabled", rr.disabled },
+ { "content", makeApiRecordContent(rr.qtype, rr.content) }
+ };
+ if ((val = zoneIdZone.find(rr.domain_id)) != zoneIdZone.end()) {
+ object["zone_id"] = apiZoneNameToId(val->second.zone);
+ object["zone"] = val->second.zone.toString();
+ }
+ doc.push_back(object);
+ }
+ }
+
+ if (B.searchComments(q, maxEnts, result_c))
+ {
+ for(const Comment &c: result_c)
+ {
+ auto object = Json::object {
+ { "object_type", "comment" },
+ { "name", c.qname.toString() },
+ { "content", c.content }
+ };
+ if ((val = zoneIdZone.find(c.domain_id)) != zoneIdZone.end()) {
+ object["zone_id"] = apiZoneNameToId(val->second.zone);
+ object["zone"] = val->second.zone.toString();
+ }
+ doc.push_back(object);
+ }
+ }
+
+ resp->setBody(doc);
+}
+
+void apiServerCacheFlush(HttpRequest* req, HttpResponse* resp) {
+ if(req->method != "PUT")
+ throw HttpMethodNotAllowedException();
+
+ DNSName canon = apiNameToDNSName(req->getvars["domain"]);
+
+ int count = PC.purgeExact(canon);
+ resp->setBody(Json::object {
+ { "count", count },
+ { "result", "Flushed cache." }
+ });
+}
+
+void AuthWebServer::cssfunction(HttpRequest* req, HttpResponse* resp)
+{
+ resp->headers["Cache-Control"] = "max-age=86400";
+ resp->headers["Content-Type"] = "text/css";
+
+ ostringstream ret;
+ ret<<"* { box-sizing: border-box; margin: 0; padding: 0; }"<<endl;
+ ret<<"body { color: black; background: white; margin-top: 1em; font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif; font-size: 10pt; position: relative; }"<<endl;
+ ret<<"a { color: #0959c2; }"<<endl;
+ ret<<"a:hover { color: #3B8EC8; }"<<endl;
+ ret<<".row { width: 940px; max-width: 100%; min-width: 768px; margin: 0 auto; }"<<endl;
+ ret<<".row:before, .row:after { display: table; content:\" \"; }"<<endl;
+ ret<<".row:after { clear: both; }"<<endl;
+ ret<<".columns { position: relative; min-height: 1px; float: left; }"<<endl;
+ ret<<".all { width: 100%; }"<<endl;
+ ret<<".headl { width: 60%; }"<<endl;
+ ret<<".headr { width: 39.5%; float: right; background-repeat: no-repeat; margin-top: 7px; ";
+ ret<<"background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAJoAAAAUCAYAAAB1RSS/AAAABHNCSVQICAgIfAhkiAAAAAlwSFlzAAACtgAAArYBAHIqtQAAABl0RVh0U29mdHdhcmUAd3d3Lmlua3NjYXBlLm9yZ5vuPBoAABBTSURBVGiBtVp7cFRVmv9u3763b7/f9It00iFACBohgCEyQYgKI49CLV3cWaoEZBcfo2shu7KOtZbjrqOuVQtVWFuOrPqPRU3NgOIDlkgyJEYJwUAqjzEJedFJupN0p9/v+9o/mtve7r790HF+VbeSPue7555zz+98z4ucOXNmgWVZBH4AK5PJGIPBQBqNxpTNZkthGMZCCUxMTBCDg4PyiYkJWTQaRc1mc7Kuri7a1NQU4ssxDAOffPKJAQCynvnII494ESTddO3aNaXT6SS4TplMRj/44IM+7ndXV5dqfn5ewh9306ZNQZqmobu7W11qri0tLX6tVkv19vYqpqampPw+BEFYtVpNGQwG0mKxpJYsWUIKjTE6OiodGBhQ8NcgkUgYjUZDORyOhM1mSxV6fjAYFF+6dEnLb9NoNOR9990X4H53dHSovV4vzpfZvn27T6FQ0Py2sbExorOzU+N2uwmWZUGv15N33nlnuLGxMZy7byyVQEJ//nd9Yuz/lJR/HBdrHSlJ9baIuuV1L4LJ8/Y49pc/KcJX39WRC4MEgskY3Lourmn5rQdbckfe2ijfOBZo+40xNXtNysR9KLZkdVK+9oBf0fBkCABA3NraamTZwjxSKpXUAw884G1paQkUIty5c+f0Fy5cWMIfx+l0Snt6ejTt7e26AwcOuKxWawoAQCQSQW9vr3pxcTHrJTY3Nwe5Tb18+bJ2bGxMzvWhKMpu27bNj6IoCwDQ1tamd7lcRM79genpaaK1tdVQcDG3sXbt2rBWq6X6+/sV3d3d2mKyy5cvj+7cudO7atWqGL99bGxMWuxZOp0utX37du+9994b5A4Qh2AwiObei6Ioe/fdd4eVSiUNAHD16lX1+Pi4nC+zadOmIJ9oZ8+eNeTu3/T0tLSvr0/V3d0dPXr0qJNrZ+KL6MKpjZWUbyxzQMmFIYJcGCISw5+qjE9+M4UqLJmx/RdeWBK+elKfGTjuR+OhWSxx86JS/9D/zsrufDzMdSXGv5J5/vBYBZuKiLi25HS3LDndLUuMX1IYHjvtynQUQjgcFp89e9b8zjvv2BmGyepjWRbeffdd2/nz55cUIqvT6ZSeOHHC7vf7xVyb3W6P58rNzc1liOfxeLJISNM04na7Me63z+fD+P1SqZQupHn+Wty8eVN+4sSJyv7+fnlp6R/g8/nw06dPW0+ePLmUJEmklDxN08iVK1dU5Y7f0dGhvnjxYkElQVFU1jP9Xz5j4pMsSzYwifvPPWnhfsdHPpdnkYwHlk4ivi9/baFDM2IAACYZEi1++qSVTzI+YkN/VEe++726JNE4TE1Nyc6cOWPkt3322Wf6/v7+ki8nEAhgH3zwQWYhDoejINGSyaQoFAphuf2zs7MSAIBIJIImEgmU32ez2RLlruOngGVZ+Oijj6w+n09cWjobg4ODyg8//NBSWhLgu+++K4toJEkin376qancObBkFIl/f7bo2ImxC0om5kUBACK9pzTFZJlEAI0O/kEJABAf+UJOh115+8VH5MZHGkGimc3mRK66BwBoa2szBAIBMUB6w1tbW415QgUwOjqqGB4elgIA1NTU5BGN02IulwsXOqUul0sCADA/P5+3qIqKip+NaARBMBiGMbnt0Wg0z68qF729vepr164pS8k5nU7ZwsJC0U0DAOjp6VHGYjE0t10kEgmqt5TrOwIYqqRWTbmuSQAASM9fiFKy5Fx/Wnaur7Ss53tC8IQ+/fTTM/F4HH3rrbcc/E1nWRYmJyeJtWvXRr7++mt1rnoGANi6devipk2bgsePH7dHIpGs8Ts7O7W1tbXxqqqqJIZhLN+keDweDADA7XbjuWPebpcAACwsLOT1V1VVFSSayWRKvvLKK5P8tmLBTVNTk//hhx/2vv/++5aBgYEsLeB0OqWF7gMAsFqtiYqKivj169c1ueaytbVVv2HDhnChewHS7/fKlSuqPXv2LBaTyw1gAABqa2sjhw4dck1PT0vOnz9v4O+NWFNdlluBqispAABUYSEp/6TgPmRkVba0rGppybFRpZksaDodDkeioqIiT/M4nU4JAMDIyEiez1JTUxN9/PHHFyoqKpJbtmzx5faPj4/LANKOr9VqzRqbi7D4vhof8/PzOMAPhMyZa948OSAIAjiOs/xLSFvzIZFImO3bt+fNn9OqhaDRaMiDBw/Obd26NY8oTqdTWmhtfPT29paMmkOhUJ6CkEgkjFKppOvq6mIvvviis76+PkNqVF1BiQ21yWJjoiobiRlWpQAACMeWaKk5EMu2RQEAiOr7YyBCi2YliMrN0aI+Wjwez+vn/KOZmZk8lbl69eoI97+QeQwEAhgXFFRVVWX1+/1+nGVZyE1bcPB6vRKWZSE35JdKpbTJZCp4qiiKQmZmZnDuEiKqEITWTtN0SfMDALBjx45FiUSSZ35HRkaKakQAgPn5ecnU1FRRQuv1+rz0Qn9/v+ry5ctqgPTh2rFjR9ZB0e78Hzcgedb2NhDQ7vq9C24fQNXm3/gww8qCxJTX/4OfcGyJAwBgS+pSqo3/XFADo0oLqdn2lkeQaAzDIB0dHWqPx5O3YK1WSzIMA7lmEQDAaDSSQv/zEQwGUQCA6urqLKJRFIV4PB6MH3GqVCqS3z83N4cvLi5mEaVUIOD1evHXX399GXedOnXKWkweIJ3r++abb/IcYqPRWDA3xodUKmWEyMCZ/1IolQvMfXcAabN7+vRp68cff2wS8nElVVvihl99cQtV27PmhapspOHvzzmJ5Tsy6RtELGGX7G+7JV2xIysHiqAYq/rFv3h0e96f57drHnjTo2n57TwiJrIOl6SyOWo6cPmWiNAwgj7am2++6Ugmk4IkrK2tjUWjUVRoMXK5PJOHkclkdJ4AAESjURQAYPny5YKRJ59odXV1EX6ea2ZmRpKbf/s5AwEAgO+//17+8ssv1/j9/jzNt3HjxmC542g0GjI318etXQgoirKcxrx+/brKYDAUJPW6desiFy5ciM/MzORpyM7OTl04HEYPHz7synURiJpfxizPj4+T8/0S0jOEiw2rUrh5TRJE+TRAFWba+KvPZung9Hxy9iohwpUMvnRjQkSo8zQ1ICJQbX7Zp2h8LpCa7ZEwUY8Yt21IiHXLMopCkEyFSFZZWRmz2+0FVSqXUL39v6AM5yTr9XpKrVZnab2RkRFZKpXKPHvlypUxvuM+PT0tCQaDWW+lWCDwUzA3N0cIkay2tjbS0tLiL3ccoYNWzPRWVVXFcBxnAACCwSAmRCIOCILA/v373QqFghLqv3Hjhrq9vb1gioIFBNLFoLI8gbKBILdHRNi8ocvOC6nVavLw4cOzAAAKhYJGEARytRo/5A6Hw4JMk8lkmRNht9vjAwMDmU0dGhril3TAbDanDAZD0u12EwAAw8PDCoZhspZQLBD4KRBa17Zt27wPPfSQVyQqO+0IQumHQloeIB0Jr169Onzjxg01QOHDzqGioiJ55MiRW8ePH68UCg6+/PJLY0tLS4Cv1RJjF2W+z5+2UEFnxiqgKhup2/muW7pyV1YAQEfmUN9n/2SOj57PRN4IirHKphe86q2vLSIozktHMBDq+p0u3PkfRpZKZOYtqWyOavd86BZrlxWOOjMTQVH2jjvuCL/wwgtOvV5PAaQ3QyqV5r20SCSSebmhUEiQaCqVKnNfLkk4QnEwmUyk2WzOaNDp6emsU14qEABIO87Hjh2b5K79+/e7i8kLVS0UCgXF19blINfEAwCoVCpBDcShsbExVKw/FzabLXXs2LFJIT81Go2K+YFPYqpDuvDx7ko+yQAA6NAs5jn9sD1+84KMa2OpJLLw0X2VfJIBALA0iYS6/svoO/ePWcni4KWXjKH2V0x8kgEAJG99Lfd8uLmSSfiFj+j999/v3bt3r/vgwYMzb7zxxthzzz03w9UqOVit1rzFjY6OZiY7NDSUl/4gCIIxmUyZcZYtW1ZQG0mlUloul9Nmszkjn1sCK6cigGEY63A4EtxlsViKOvQOhyOm0WiyyNve3q4vN+IESKeAhKJnISeej/r6+ijfzy2Evr4+Oad19Xo9dejQoVkhbev1ejNE83/xjAXYfPcqDRZ8nz9lhdtjhjr/U0d6RwoGLtH+j7WJyctSAADSM4SHu/9bsFwFAECHXVjwq381ChKtubk50NLSEmhsbAxrNBrBU7hixYq8XMvg4KByamqKmJubw7799ts8H6GqqirGV+XV1dWJQppCq9WSAABWq7WgT/hzBwIAaW3d0NCQpVkCgQDW1dVVVnnI5XLhp06dsuW24zjO1NTUFJ0viqJsfX19Sa3W09Ojfu+996xcCkapVNIoiuaxyGAwkAAAdHBaXIw4AGnNRnqHcQCAxOTlknXdxHirHAAgOXFJBkzxQ5ic6pD/6Nodh9uRT1YxPRaLoW+//XaVWCxmhXyMe+65J8D/jeM4a7FYEkKOL5ceWLp0aUGiVVZWliSax+PBX3rppRp+27PPPjtdLKhpamoKtre3Z53Sr776yrB58+a8LzH4GB4eVr722muCpaaGhoYgQRCFVEoGGzduDF65cqVkqevGjRvqgYEBld1uj8/NzUlIMtsNwnGc4VJMlH+yrNwhFbglxoyrUnTEXVKeDs2K039nSstG5rDyvdscLF26NNnQ0JAX7tM0jQiRzGQyJdevXx/Jba+srBQ0J3q9ngRIBwRisVhQ65UTCNA0jQQCAYx/CZXO+LDb7UmLxZJFYo/Hg1+9erVovTLXtHMgCILevXt30bISh5UrV8ZzTXchUBSFTExMyIQCj7q6ugh3KHDbugSIhN8hHxLb+iQAAGasK+2SmOvTsuY1pWWNqxI/mWgAAI8++uiCTqcrmcTEMIzZt2+fW8hMFvJbuNMoEokEM+FSqZQ2m81/k0+DAADWr1+fZ8IuXrxY8lu3XKAoyu7bt8/NmbFSEDLdPxYSiYTZu3dvJqmKYHJWturhomNKa34ZFskMNACAYt2hQDFZEaGh5XfsDQMAECt2R1Glreja5GsOBP4qoul0Ouro0aO3TCZTQTOkUqnII0eO3FqxYoUgoYRKVQAA/ISl0Ph/60+Dmpqa8syky+Ui+vr6yv4uTavVks8///ytUsV0oWf/GHk+pFIp/cQTT8zqdLos31q36+S8WFcjuE9iTVVK99CpTDQuXbk7qmz8taAGRlAJq9t50o2qllIAACKJitHu+cCF4ApBdS5d/XdB+fqnguLq6upobm4Kx/GyQ3m9Xk+9+uqrk21tbZquri6t1+vFWZYFi8WSdDgcsV27di1qtdqCYb3ZbCZra2sjueaW/yl0XV1dNBwOZ/mT/KIxB6VSSTkcjlhuey44X8lkMqVy5TmC6/V6qrGx0Z8bPY6OjsrWrFkT1el0ec9CUZRVqVSUWq2mqqur4xs2bAgL+XQSiYTJvZcf9Njt9uRdd90Vys2PcQnd5ubmAMMwcPPmTXk0GhUDpCsRVVVVsccee2yBS0PxIZLqacszfZPBP7+qj4+1Kilf+lNuYtkDEU3La3mfcmsfPL4gqfxFrJxPuYll22Kmp/omgpf+zZia7ZEyCT+KGVcn5WsP+uUNh0IAAP8PaQRnE4MgdzkAAAAASUVORK5CYII=);";
+ ret<<" width: 154px; height: 20px; }"<<endl;
+ ret<<"a#appname { margin: 0; font-size: 27px; color: #666; text-decoration: none; font-weight: bold; display: block; }"<<endl;
+ ret<<"footer { border-top: 1px solid #ddd; padding-top: 4px; font-size: 12px; }"<<endl;
+ ret<<"footer.row { margin-top: 1em; margin-bottom: 1em; }"<<endl;
+ ret<<".panel { background: #f2f2f2; border: 1px solid #e6e6e6; margin: 0 0 22px 0; padding: 20px; }"<<endl;
+ ret<<"table.data { width: 100%; border-spacing: 0; border-top: 1px solid #333; }"<<endl;
+ ret<<"table.data td { border-bottom: 1px solid #333; padding: 2px; }"<<endl;
+ ret<<"table.data tr:nth-child(2n) { background: #e2e2e2; }"<<endl;
+ ret<<"table.data tr:hover { background: white; }"<<endl;
+ ret<<".ringmeta { margin-bottom: 5px; }"<<endl;
+ ret<<".resetring {float: right; }"<<endl;
+ ret<<".resetring i { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAA/klEQVQY01XPP04UUBgE8N/33vd2XZUWEuzYuMZEG4KFCQn2NhA4AIewAOMBPIG2xhNYeAcKGqkNCdmYlVBZGBIT4FHsbuE0U8xk/kAbqm9TOfI/nicfhmwgDNhvylUT58kxCp4l31L8SfH9IetJ2ev6PwyIwyZWsdb11/gbTK55Co+r8rmJaRPTFJcpZil+pTit7C5awMpA+Zpi1sRFE9MqflYOloYCjY2uP8EdYiGU4CVGUBubxKfOOLjrtOBmzvEilbVb/aQWvhRl0unBZVXe4XdnK+bprwqnhoyTsyZ+JG8Wk0apfExxlcp7PFruXH8gdxamWB4cyW2sIO4BG3czIp78jUIAAAAASUVORK5CYII=); width: 10px; height: 10px; margin-right: 2px; display: inline-block; background-repeat: no-repeat; }"<<endl;
+ ret<<".resetring:hover i { background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAA2ElEQVQY013PMUoDcRDF4c+kEzxCsNNCrBQvIGhnlcYm11EkBxAraw8gglgIoiJpAoKIYlBcgrgopsma3c3fwt1k9cHA480M8xvQp/nMjorOWY5ov7IAYlpjQk7aYxcuWBpwFQgJnUcaYk7GhEDIGL5w+MVpKLIRyR2b4JOjvGhUKzHTv2W7iuSN479Dvu9plf1awbQ6y3x1sU5tjpVJcMbakF6Ycoas8Dl5xEHJ160wRdfqzXfa6XQ4PLDlicWUjxHxZfndL/N+RhiwNzl/Q6PDhn/qsl76H7prcApk2B1aAAAAAElFTkSuQmCC);}"<<endl;
+ ret<<".resizering {float: right;}"<<endl;
+ resp->body = ret.str();
+ resp->status = 200;
+}
+
+void AuthWebServer::webThread()
+{
+ try {
+ if(::arg().mustDo("api")) {
+ d_ws->registerApiHandler("/api/v1/servers/localhost/cache/flush", &apiServerCacheFlush);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/config", &apiServerConfig);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/search-log", &apiServerSearchLog);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/search-data", &apiServerSearchData);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/statistics", &apiServerStatistics);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/axfr-retrieve", &apiServerZoneAxfrRetrieve);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/cryptokeys/<key_id>", &apiZoneCryptokeys);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/cryptokeys", &apiZoneCryptokeys);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/export", &apiServerZoneExport);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>/notify", &apiServerZoneNotify);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones/<id>", &apiServerZoneDetail);
+ d_ws->registerApiHandler("/api/v1/servers/localhost/zones", &apiServerZones);
+ d_ws->registerApiHandler("/api/v1/servers/localhost", &apiServerDetail);
+ d_ws->registerApiHandler("/api/v1/servers", &apiServer);
+ d_ws->registerApiHandler("/api", &apiDiscovery);
+ }
+ d_ws->registerWebHandler("/style.css", boost::bind(&AuthWebServer::cssfunction, this, _1, _2));
+ d_ws->registerWebHandler("/", boost::bind(&AuthWebServer::indexfunction, this, _1, _2));
+ d_ws->go();
+ }
+ catch(...) {
+ L<<Logger::Error<<"AuthWebServer thread caught an exception, dying"<<endl;
+ exit(1);
+ }
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef WS_HH
+#define WS_HH
+#include <string>
+#include <map>
+#include <time.h>
+#include <pthread.h>
+#include "misc.hh"
+#include "namespaces.hh"
+
+class Ewma
+{
+public:
+ Ewma() : d_last(0), d_10(0), d_5(0), d_1(0), d_max(0){dt.set();}
+ void submit(int val)
+ {
+ int rate=val-d_last;
+ double difft=dt.udiff()/1000000.0;
+ dt.set();
+
+ d_10=((600.0-difft)*d_10+(difft*rate))/600.0;
+ d_5=((300.0-difft)*d_5+(difft*rate))/300.0;
+ d_1=((60.0-difft)*d_1+(difft*rate))/60.0;
+ d_max=max(d_1,d_max);
+
+ d_last=val;
+ }
+ double get10()
+ {
+ return d_10;
+ }
+ double get5()
+ {
+ return d_5;
+ }
+ double get1()
+ {
+ return d_1;
+ }
+ double getMax()
+ {
+ return d_max;
+ }
+private:
+ DTime dt;
+ int d_last;
+ double d_10, d_5, d_1, d_max;
+};
+
+class WebServer;
+class HttpRequest;
+class HttpResponse;
+
+class AuthWebServer
+{
+public:
+ AuthWebServer();
+ void go();
+ static string makePercentage(const double& val);
+
+private:
+ static void *webThreadHelper(void *);
+ static void *statThreadHelper(void *p);
+ void indexfunction(HttpRequest* req, HttpResponse* resp);
+ void cssfunction(HttpRequest* req, HttpResponse* resp);
+ void jsonstat(HttpRequest* req, HttpResponse* resp);
+ void registerApiHandler(const string& url, boost::function<void(HttpRequest*, HttpResponse*)> handler);
+ void printvars(ostringstream &ret);
+ void printargs(ostringstream &ret);
+ void webThread();
+ void statThread();
+ pthread_t d_tid;
+
+ time_t d_start;
+ double d_min10, d_min5, d_min1;
+ Ewma d_queries, d_cachehits, d_cachemisses;
+ Ewma d_qcachehits, d_qcachemisses;
+ WebServer *d_ws;
+};
+
+#endif
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+/* accepts a named.conf or a zone as parameter and outputs heaps of sql */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <string>
+#include <map>
+
+#include <iostream>
+#include <stdio.h>
+#include "namespaces.hh"
+
+#include "dns.hh"
+#include "arguments.hh"
+#include "bindparserclasses.hh"
+#include "statbag.hh"
+#include "misc.hh"
+#include "dnspacket.hh"
+#include "zoneparser-tng.hh"
+#include "dnsrecords.hh"
+#include <boost/algorithm/string.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "json11.hpp"
+
+using namespace json11;
+
+StatBag S;
+static int g_numRecords;
+
+static Json::object emitRecord(const string& zoneName, const DNSName &DNSqname, const string &qtype, const string &ocontent, int ttl)
+{
+ int prio=0;
+ string retval;
+ g_numRecords++;
+ string content(ocontent);
+ if(qtype == "MX" || qtype == "SRV") {
+ prio=pdns_stou(content);
+
+ string::size_type pos = content.find_first_not_of("0123456789");
+ if(pos != string::npos)
+ boost::erase_head(content, pos);
+ trim_left(content);
+ }
+
+ Json::object dict;
+
+ dict["name"] = DNSqname.toString();
+ dict["type"] = qtype;
+ dict["ttl"] = ttl;
+ dict["prio"] = prio;
+ dict["content"] = content;
+
+ return dict;
+}
+
+/* 2 modes of operation, either --named or --zone (the latter needs $ORIGIN)
+ 2 further modes: --mysql or --oracle
+*/
+
+ArgvMap &arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+
+int main(int argc, char **argv)
+try
+{
+ vector<string> lines;
+
+ reportAllTypes();
+#if __GNUC__ >= 3
+ std::ios_base::sync_with_stdio(false);
+#endif
+
+ ::arg().setSwitch("verbose","Verbose comments on operation")="no";
+ ::arg().setSwitch("on-error-resume-next","Continue after errors")="no";
+ ::arg().set("zone","Zonefile to parse")="";
+ ::arg().set("zone-name","Specify an $ORIGIN in case it is not present")="";
+ ::arg().set("named-conf","Bind 8/9 named.conf to parse")="";
+
+ ::arg().set("soa-minimum-ttl","Do not change")="0";
+ ::arg().set("soa-refresh-default","Do not change")="0";
+ ::arg().set("soa-retry-default","Do not change")="0";
+ ::arg().set("soa-expire-default","Do not change")="0";
+
+ ::arg().setCmd("help","Provide a helpful message");
+ ::arg().setCmd("version","Print the version");
+
+ S.declare("logmessages");
+
+ string namedfile="";
+ string zonefile="";
+
+ ::arg().parse(argc, argv);
+
+ if(::arg().mustDo("version")){
+ cerr<<"zone2json "<<VERSION<<endl;
+ exit(0);
+ }
+
+ if(::arg().mustDo("help")) {
+ cout<<"syntax:"<<endl<<endl;
+ cout<<::arg().helpstring()<<endl;
+ exit(0);
+ }
+
+ if(argc<2) {
+ cerr<<"syntax:"<<endl<<endl;
+ cerr<<::arg().helpstring()<<endl;
+ exit(1);
+ }
+
+ namedfile=::arg()["named-conf"];
+ zonefile=::arg()["zone"];
+
+ int count=0, num_domainsdone=0;
+
+ if(zonefile.empty()) {
+ BindParser BP;
+ BP.setVerbose(::arg().mustDo("verbose"));
+ BP.parse(namedfile.empty() ? "./named.conf" : namedfile);
+
+ vector<BindDomainInfo> domains=BP.getDomains();
+ struct stat st;
+ for(vector<BindDomainInfo>::iterator i=domains.begin(); i!=domains.end(); ++i) {
+ if(stat(i->filename.c_str(), &st) == 0) {
+ i->d_dev = st.st_dev;
+ i->d_ino = st.st_ino;
+ }
+ }
+
+ sort(domains.begin(), domains.end()); // put stuff in inode order
+
+ int numdomains=domains.size();
+ int tick=numdomains/100;
+ cout << "[";
+
+ for(vector<BindDomainInfo>::const_iterator i=domains.begin();
+ i!=domains.end();
+ ++i)
+ {
+ if(i->type!="master" && i->type!="slave") {
+ cerr<<" Warning! Skipping '"<<i->type<<"' zone '"<<i->name<<"'"<<endl;
+ continue;
+ }
+ lines.clear();
+ try {
+ Json::object obj;
+ Json::array recs;
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ obj["name"] = i->name.toString();
+
+ while(zpt.get(rr))
+ recs.push_back(emitRecord(i->name.toString(), rr.qname, rr.qtype.getName(), rr.content, rr.ttl));
+ obj["records"] = recs;
+ Json tmp = obj;
+ cout<<tmp.dump();
+ if(i+1 < domains.end()) cout<<",";
+ num_domainsdone++;
+ }
+ catch(std::exception &ae) {
+ if(!::arg().mustDo("on-error-resume-next"))
+ throw;
+ else
+ cerr<<endl<<ae.what()<<endl;
+ }
+ catch(PDNSException &ae) {
+ if(!::arg().mustDo("on-error-resume-next"))
+ throw;
+ else
+ cerr<<ae.reason<<endl;
+ }
+ if(!tick || !((count++)%tick))
+ cerr<<"\r"<<count*100/numdomains<<"% done ("<<i->filename<<")\033\133\113";
+ }
+ cout << "]" << endl;
+ cerr<<"\r100% done\033\133\113"<<endl;
+ }
+ else {
+ ZoneParserTNG zpt(zonefile, DNSName(::arg()["zone-name"]));
+ DNSResourceRecord rr;
+ string zname;
+ Json::object obj;
+ Json::array records;
+
+ obj["name"] = ::arg()["zone-name"];
+
+ while(zpt.get(rr))
+ records.push_back(emitRecord(::arg()["zone-name"], rr.qname, rr.qtype.getName(), rr.content, rr.ttl));
+ obj["records"] = records;
+
+ Json tmp = obj;
+
+ cout<<tmp.dump()<<endl;
+
+ num_domainsdone=1;
+ }
+ cerr<<num_domainsdone<<" domains were fully parsed, containing "<<g_numRecords<<" records\n";
+
+ return 0;
+
+}
+catch(PDNSException &ae) {
+ cerr<<"\nFatal error: "<<ae.reason<<endl;
+ return 1;
+}
+catch(std::exception &e) {
+ cerr<<"\ndied because of STL error: "<<e.what()<<endl;
+ return 1;
+}
+catch(...) {
+ cerr<<"\ndied because of unknown exception"<<endl;
+ return 1;
+}
--- /dev/null
+/*
+ * PowerDNS BIND Zone to LDAP converter
+ * Copyright (C) 2003 Norbert Sendetzky
+ * Copyright (C) 2007 bert hubert
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2
+ * the Free Software Foundation
+ *
+ * Additionally, the license of this program contains a special
+ * exception which allows to distribute the program in binary form when
+ * it is linked against OpenSSL.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <map>
+#include <string>
+#include <iostream>
+#include <stdio.h>
+#include "arguments.hh"
+#include "bindparserclasses.hh"
+#include "statbag.hh"
+#include <boost/function.hpp>
+#include "dnsrecords.hh"
+#include "misc.hh"
+#include "dns.hh"
+#include "zoneparser-tng.hh"
+
+using std::map;
+using std::string;
+using std::vector;
+
+StatBag S;
+ArgvMap args;
+bool g_dnsttl;
+string g_basedn;
+DNSName g_zonename;
+map<DNSName,bool> g_objects;
+
+static void callback_simple( unsigned int domain_id, const DNSName &domain, const string &qtype, const string &content, int ttl )
+{
+ DNSName host;
+
+ if( ! domain.isPartOf(g_zonename) )
+ {
+ cerr << "Domain '" << domain << "'' not part of '" << g_zonename << "'"<< endl;
+ return;
+ }
+
+ host = domain.makeRelative(g_zonename);
+
+ cout << "dn: dc=";
+ if( host.countLabels() ) { cout << host.toStringNoDot() << ",dc="; }
+ cout << g_zonename.toStringNoDot() << "," << g_basedn << endl;
+
+ if( host.countLabels() == 0 ) { host = g_zonename; }
+
+ if( !g_objects[domain] )
+ {
+ g_objects[domain] = true;
+
+ cout << "changetype: add" << endl;
+ cout << "objectclass: dnsdomain2" << endl;
+ cout << "objectclass: domainrelatedobject" << endl;
+ cout << "dc: " << host.toStringNoDot() << endl;
+ if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; }
+ cout << "associateddomain: " << domain.toStringNoDot() << endl;
+ }
+ else
+ {
+ cout << "changetype: modify" << endl;
+ cout << "add: " << qtype << "Record" << endl;
+ }
+
+ cout << qtype << "Record: " << stripDot( content ) << endl << endl;
+}
+
+
+
+static void callback_tree( unsigned int domain_id, const DNSName &domain, const string &qtype, const string &content, int ttl )
+{
+ unsigned int i;
+ string dn;
+ DNSName net;
+ vector<string> parts;
+
+ stringtok( parts, domain.toStringNoDot(), "." );
+ if( parts.empty() ) { return; }
+
+ for( i = parts.size() - 1; i > 0; i-- )
+ {
+ net.prependRawLabel(parts[i]);
+ dn = "dc=" + parts[i] + "," + dn;
+
+ if( !g_objects[net] )
+ {
+ g_objects[net] = true;
+
+ cout << "dn: " << dn << g_basedn << endl;
+ cout << "changetype: add" << endl;
+ cout << "objectclass: dnsdomain2" << endl;
+ cout << "objectclass: domainrelatedobject" << endl;
+ cout << "dc: " << parts[i] << endl;
+ cout << "associateddomain: " << net.toStringNoDot() << endl << endl;
+ }
+
+ }
+
+ cout << "dn: " << "dc=" << parts[0] << "," << dn << g_basedn << endl;
+
+ if( !g_objects[domain] )
+ {
+ g_objects[domain] = true;
+
+ cout << "changetype: add" << endl;
+ cout << "objectclass: dnsdomain2" << endl;
+ cout << "objectclass: domainrelatedobject" << endl;
+ cout << "dc: " << parts[0] << endl;
+ if( g_dnsttl ) { cout << "dnsttl: " << ttl << endl; }
+ cout << "associateddomain: " << domain.toStringNoDot() << endl;
+ }
+ else
+ {
+ cout << "changetype: modify" << endl;
+ cout << "add: " << qtype << "Record" << endl;
+ }
+
+ cout << qtype << "Record: " << stripDot( content ) << endl << endl;
+}
+
+
+
+int main( int argc, char* argv[] )
+{
+ BindParser BP;
+ vector<string> parts;
+
+
+ try
+ {
+#if __GNUC__ >= 3
+ std::ios_base::sync_with_stdio( false );
+#endif
+ reportAllTypes();
+ args.setCmd( "help", "Provide a helpful message" );
+ args.setCmd( "version", "Print the version" );
+ args.setSwitch( "verbose", "Verbose comments on operation" ) = "no";
+ args.setSwitch( "resume", "Continue after errors" ) = "no";
+ args.setSwitch( "dnsttl", "Add dnsttl attribute to every entry" ) = "no";
+ args.set( "named-conf", "Bind 8 named.conf to parse" ) = "";
+ args.set( "zone-file", "Zone file to parse" ) = "";
+ args.set( "zone-name", "Specify a zone name if zone is set" ) = "";
+ args.set( "basedn", "Base DN to store objects below" ) = "ou=hosts,o=mycompany,c=de";
+ args.set( "layout", "How to arrange entries in the directory (simple or as tree)" ) = "simple";
+
+ args.parse( argc, argv );
+
+ if(args.mustDo("version")) {
+ cerr<<"zone2ldap "<<VERSION<<endl;
+ exit(0);
+ }
+
+ if( args.mustDo( "help" ) )
+ {
+ cout << "Syntax:" << endl << endl;
+ cout << args.helpstring() << endl;
+ exit( 0 );
+ }
+
+ if( argc < 2 )
+ {
+ cerr << "Syntax:" << endl << endl;
+ cerr << args.helpstring() << endl;
+ exit( 1 );
+ }
+
+ g_basedn = args["basedn"];
+ g_dnsttl = args.mustDo( "dnsttl" );
+ typedef boost::function<void(unsigned int, const DNSName &, const string &, const string &, int)> callback_t;
+ callback_t callback = callback_simple;
+ if( args["layout"] == "tree" )
+ {
+ callback=callback_tree;
+ }
+
+ if( !args["named-conf"].empty() )
+ {
+ BP.setVerbose( args.mustDo( "verbose" ) );
+ BP.parse( args["named-conf"] );
+// ZP.setDirectory( BP.getDirectory() );
+ const vector<BindDomainInfo> &domains = BP.getDomains();
+
+ for( vector<BindDomainInfo>::const_iterator i = domains.begin(); i != domains.end(); i++ )
+ {
+ if(i->type!="master" && i->type!="slave") {
+ cerr<<" Warning! Skipping '"<<i->type<<"' zone '"<<i->name<<"'"<<endl;
+ continue;
+ }
+ try
+ {
+ if( i->name != DNSName(".") && i->name != DNSName("localhost") && i->name != DNSName("0.0.127.in-addr.arpa") )
+ {
+ cerr << "Parsing file: " << i->filename << ", domain: " << i->name << endl;
+ g_zonename = i->name;
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl);
+ }
+ }
+ catch( PDNSException &ae )
+ {
+ cerr << "Fatal error: " << ae.reason << endl;
+ if( !args.mustDo( "resume" ) )
+ {
+ return 1;
+ }
+ }
+ }
+ }
+ else
+ {
+ if( args["zone-file"].empty() || args["zone-name"].empty() )
+ {
+ cerr << "Error: At least zone-file and zone-name are required" << endl;
+ return 1;
+ }
+
+ g_zonename = DNSName(args["zone-name"]);
+ ZoneParserTNG zpt(args["zone-file"], g_zonename);
+ DNSResourceRecord rr;
+ while(zpt.get(rr))
+ callback(0, rr.qname, rr.qtype.getName(), rr.content, rr.ttl);
+ }
+ }
+ catch( PDNSException &ae )
+ {
+ cerr << "Fatal error: " << ae.reason << endl;
+ return 1;
+ }
+ catch( std::exception &e )
+ {
+ cerr << "Died because of STL error: " << e.what() << endl;
+ return 1;
+ }
+ catch( ... )
+ {
+ cerr << "Died because of unknown exception" << endl;
+ return 1;
+ }
+
+ return 0;
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2002 - 2011 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+/* accepts a named.conf or a zone as parameter and outputs heaps of sql */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include <unistd.h>
+#include <string>
+#include <map>
+
+#include <iostream>
+#include <stdio.h>
+#include "json11.hpp"
+#include "namespaces.hh"
+#include "dns.hh"
+#include "arguments.hh"
+#include "bindparserclasses.hh"
+#include "statbag.hh"
+#include "misc.hh"
+#include "dnspacket.hh"
+#include "zoneparser-tng.hh"
+#include "dnsrecords.hh"
+#include <boost/algorithm/string.hpp>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+
+
+StatBag S;
+
+enum dbmode_t {MYSQL, GORACLE, POSTGRES, SQLITE, MYDNS, ORACLE};
+static dbmode_t g_mode;
+static bool g_intransaction;
+static int g_numRecords;
+
+
+/* this is an official wart. We don't terminate domains on a . in PowerDNS,
+ which is fine as it goes, except for encoding the root, it would end up as '',
+ which leads to ambiguities in the content field. Therefore, if we encounter
+ the root as a . in a BIND zone, we leave it as a ., and don't replace it by
+ an empty string. Back in 1999 we made the wrong choice. */
+
+static string stripDotContent(const string& content)
+{
+ if(boost::ends_with(content, " .") || content==".")
+ return content;
+ return stripDot(content);
+}
+
+static string sqlstr(const string &name)
+{
+ if(g_mode == SQLITE || g_mode==GORACLE || g_mode==ORACLE)
+ return "'"+boost::replace_all_copy(name, "'", "''")+"'";
+
+ string a;
+
+ for(string::const_iterator i=name.begin();i!=name.end();++i) {
+ if(*i=='\'' || *i=='\\'){
+ a+='\\';
+ a+=*i;
+ }
+ else
+ a+=*i;
+ }
+ if(g_mode == POSTGRES)
+ return "E'"+a+"'";
+ else
+ return "'"+a+"'";
+}
+
+static void startNewTransaction()
+{
+ if(!::arg().mustDo("transactions"))
+ return;
+
+ if(g_intransaction) {
+ if(g_mode==POSTGRES) {
+ cout<<"COMMIT WORK;"<<endl;
+ }
+ else if(g_mode == MYSQL || g_mode == SQLITE || g_mode == MYDNS) {
+ cout<<"COMMIT;"<<endl;
+ }
+ }
+ g_intransaction=1;
+
+ if(g_mode == MYSQL || g_mode == MYDNS)
+ cout<<"BEGIN;"<<endl;
+ else if (g_mode!=GORACLE && g_mode!=ORACLE)
+ cout<<"BEGIN TRANSACTION;"<<endl;
+}
+
+static void emitDomain(const DNSName& domain, const vector<string> *masters = 0) {
+ string iDomain = domain.toStringRootDot();
+ if(!::arg().mustDo("slave")) {
+ if(g_mode==POSTGRES || g_mode==MYSQL || g_mode==SQLITE) {
+ cout<<"insert into domains (name,type) values ("<<toLower(sqlstr(iDomain))<<",'NATIVE');"<<endl;
+ }
+ else if(g_mode==GORACLE) {
+ cout<<"insert into domains (id,name,type) values (domains_id_sequence.nextval,"<<toLower(sqlstr(iDomain))<<",'NATIVE');"<<endl;
+ }
+ else if(g_mode==ORACLE) {
+ cout<<"INSERT INTO Zones (id, name, type) VALUES (zones_id_seq.nextval, "<<sqlstr(toLower(iDomain))<<", 'NATIVE');"<<endl;
+ }
+ }
+ else
+ {
+
+ if(g_mode==POSTGRES || g_mode==MYSQL || g_mode==SQLITE) {
+ string mstrs;
+ if (masters != 0 && ! masters->empty()) {
+ for(const string& mstr : *masters) {
+ mstrs.append(mstr);
+ mstrs.append(1, ' ');
+ }
+ }
+ if (mstrs.empty())
+ cout<<"insert into domains (name,type) values ("<<sqlstr(iDomain)<<",'NATIVE');"<<endl;
+ else
+ cout<<"insert into domains (name,type,master) values ("<<sqlstr(iDomain)<<",'SLAVE'"<<", '"<<mstrs<<"');"<<endl;
+ }
+ else if (g_mode == GORACLE || g_mode==ORACLE) {
+ cerr<<"Slave import mode not supported with oracle."<<endl;
+ }
+ }
+}
+
+bool g_doJSONComments;
+static void emitRecord(const DNSName& zoneName, const DNSName &DNSqname, const string &qtype, const string &ocontent, int ttl, const string& comment="")
+{
+ string qname = DNSqname.toStringRootDot();
+ string zname = zoneName.toStringRootDot();
+ int prio=0;
+ int disabled=0;
+ string recordcomment;
+
+ if(g_doJSONComments & !comment.empty()) {
+ string::size_type pos = comment.find("json={");
+ if(pos!=string::npos) {
+ string json = comment.substr(pos+5);
+ string err;
+ auto document = json11::Json::parse(json, err);
+ if(document.is_null())
+ throw runtime_error("Could not parse JSON '"+json+"': " + err);
+
+ disabled=document["disabled"].bool_value();
+ recordcomment=document["comment"].string_value();
+ }
+ }
+
+ g_numRecords++;
+ string content(ocontent);
+
+ if(qtype == "NSEC" || qtype == "NSEC3")
+ return; // NSECs do not go in the database
+
+ if((qtype == "MX" || qtype == "SRV") && g_mode!=ORACLE) {
+ prio=pdns_stou(content);
+
+ string::size_type pos = content.find_first_not_of("0123456789");
+ if(pos != string::npos)
+ boost::erase_head(content, pos);
+ trim_left(content);
+ }
+
+ bool auth = true;
+ if(qtype == "NS" && !pdns_iequals(qname, zname)) {
+ auth=false;
+ }
+
+ if(g_mode==MYSQL || g_mode==SQLITE) {
+ cout<<"insert into records (domain_id, name, type,content,ttl,prio,disabled) select id ,"<<
+ sqlstr(toLower(qname))<<", "<<
+ sqlstr(qtype)<<", "<<
+ sqlstr(stripDotContent(content))<<", "<<ttl<<", "<<prio<<", "<<disabled<<
+ " from domains where name="<<toLower(sqlstr(zname))<<";\n";
+
+ if(!recordcomment.empty()) {
+ cout<<"insert into comments (domain_id,name,type,modified_at, comment) select id, "<<toLower(sqlstr(stripDot(qname)))<<", "<<sqlstr(qtype)<<", "<<time(0)<<", "<<sqlstr(recordcomment)<<" from domains where name="<<toLower(sqlstr(zname))<<";\n";
+ }
+ }
+ else if(g_mode==POSTGRES) {
+ cout<<"insert into records (domain_id, name, ordername, auth, type,content,ttl,prio,disabled) select id ,"<<
+ sqlstr(toLower(qname))<<", "<<
+ sqlstr(toLower(labelReverse(makeRelative(qname, zname))))<<", '"<< (auth ? 't' : 'f') <<"', "<<
+ sqlstr(qtype)<<", "<<
+ sqlstr(stripDotContent(content))<<", "<<ttl<<", "<<prio<<", '"<<(disabled ? 't': 'f') <<
+ "' from domains where name="<<toLower(sqlstr(zname))<<";\n";
+ }
+ else if(g_mode==GORACLE) {
+ cout<<"insert into Records (id, domain_id, name, type, content, ttl, prio, disabled) select RECORDS_ID_SEQUENCE.nextval,id ,"<<
+ sqlstr(toLower(qname))<<", "<<
+ sqlstr(qtype)<<", "<<
+ sqlstr(stripDotContent(content))<<", "<<ttl<<", "<<prio<<", "<<disabled<<
+ " from Domains where name="<<toLower(sqlstr(zname))<<";\n";
+ }
+ else if(g_mode==ORACLE) {
+ cout<<"INSERT INTO Records (id, zone_id, fqdn, ttl, type, content) SELECT records_id_seq.nextval, id, "<<
+ sqlstr(toLower(qname))<<", "<<
+ ttl<<", "<<sqlstr(qtype)<<", "<<
+ sqlstr(stripDotContent(content))<<
+ " FROM Zones WHERE name="<<toLower(sqlstr(zname))<<";"<<endl;
+ }
+ else if (g_mode == MYDNS) {
+ string zoneNameDot = zname + ".";
+ if (qtype == "A" || qtype == "AAAA" || qtype == "CNAME" || qtype == "HINFO" || qtype == "MX" || qtype == "NAPTR" ||
+ qtype == "NS" || qtype == "PTR" || qtype == "RP" || qtype == "SRV" || qtype == "TXT")
+ {
+ if ((qtype == "MX" || qtype == "NS" || qtype == "SRV" || qtype == "CNAME") && content[content.size()-1] != '.')
+ content.append(".");
+ cout<<"INSERT INTO rr(zone, name, type, data, aux, ttl) VALUES("<<
+ "(SELECT id FROM soa WHERE origin = "<<
+ sqlstr(toLower(zoneNameDot))<<"), "<<
+ sqlstr(toLower(DNSqname.toString()))<<", "<<
+ sqlstr(qtype)<<", "<<sqlstr(content)<<", "<<prio<<", "<<ttl<<");\n";
+ }
+ else if (qtype == "SOA") {
+ //pdns CONTENT = ns1.wtest.com. ahu.example.com. 2005092501 28800 7200 604800 86400
+ vector<string> parts;
+ stringtok(parts, content);
+
+ cout<<"INSERT INTO soa(origin, ns, mbox, serial, refresh, retry, expire, minimum, ttl) VALUES("<<
+ sqlstr(toLower(zoneNameDot))<<", "<<sqlstr(parts[0])<<", "<<sqlstr(parts[1])<<", "<<pdns_stou(parts[2])<<", "<<
+ pdns_stou(parts[3])<<", "<<pdns_stou(parts[4])<<", "<<pdns_stou(parts[5])<<", "<<pdns_stou(parts[6])<<", "<<ttl<<");\n";
+ }
+ else
+ {
+ cerr<<"Record type "<<qtype<<" is not supported."<<endl;
+ }
+ }
+}
+
+
+/* 2 modes of operation, either --named or --zone (the latter needs $ORIGIN)
+ 2 further modes: --mysql, --goracle or --oracle
+*/
+
+ArgvMap &arg()
+{
+ static ArgvMap theArg;
+ return theArg;
+}
+
+
+int main(int argc, char **argv)
+try
+{
+ reportAllTypes();
+#if __GNUC__ >= 3
+ std::ios_base::sync_with_stdio(false);
+#endif
+
+ ::arg().setSwitch("gpgsql","Output in format suitable for default gpgsqlbackend")="no";
+ ::arg().setSwitch("gmysql","Output in format suitable for default gmysqlbackend")="no";
+ ::arg().setSwitch("mydns","Output in format suitable for default mydnsbackend")="no";
+ ::arg().setSwitch("goracle","Output in format suitable for the goraclebackend")="no";
+ ::arg().setSwitch("oracle","Output in format suitable for the oraclebackend")="no";
+ ::arg().setSwitch("gsqlite","Output in format suitable for default gsqlitebackend")="no";
+ ::arg().setSwitch("verbose","Verbose comments on operation")="no";
+ ::arg().setSwitch("slave","Keep BIND slaves as slaves. Only works with named-conf.")="no";
+ ::arg().setSwitch("json-comments","Parse json={} field for disabled & comments")="no";
+ ::arg().setSwitch("transactions","If target SQL supports it, use transactions")="no";
+ ::arg().setSwitch("on-error-resume-next","Continue after errors")="no";
+ ::arg().setSwitch("filter-duplicate-soa","Filter second SOA in zone")="yes";
+ ::arg().set("zone","Zonefile to parse")="";
+ ::arg().set("zone-name","Specify an $ORIGIN in case it is not present")="";
+ ::arg().set("named-conf","Bind 8/9 named.conf to parse")="";
+
+ ::arg().set("soa-minimum-ttl","Do not change")="0";
+ ::arg().set("soa-refresh-default","Do not change")="0";
+ ::arg().set("soa-retry-default","Do not change")="0";
+ ::arg().set("soa-expire-default","Do not change")="0";
+
+ ::arg().setCmd("help","Provide a helpful message");
+ ::arg().setCmd("version","Print the version");
+
+ S.declare("logmessages");
+
+ string namedfile="";
+ string zonefile="";
+
+ ::arg().parse(argc, argv);
+
+ if(::arg().mustDo("version")) {
+ cerr<<"zone2sql "<<VERSION<<endl;
+ exit(0);
+ }
+
+ if(::arg().mustDo("help")) {
+ cout<<"syntax:"<<endl<<endl;
+ cout<<::arg().helpstring()<<endl;
+ exit(0);
+ }
+
+ if(argc<2) {
+ cerr<<"syntax:"<<endl<<endl;
+ cerr<<::arg().helpstring()<<endl;
+ exit(1);
+ }
+
+ bool filterDupSOA = ::arg().mustDo("filter-duplicate-soa");
+
+ g_doJSONComments=::arg().mustDo("json-comments");
+
+ if(::arg().mustDo("gmysql"))
+ g_mode=MYSQL;
+ else if(::arg().mustDo("gpgsql"))
+ g_mode=POSTGRES;
+ else if(::arg().mustDo("gsqlite"))
+ g_mode=SQLITE;
+ else if(::arg().mustDo("goracle"))
+ g_mode=GORACLE;
+ else if(::arg().mustDo("oracle"))
+ g_mode=ORACLE;
+ else if(::arg().mustDo("mydns"))
+ g_mode=MYDNS;
+ else {
+ cerr<<"Unknown SQL mode!\n\n";
+ cerr<<"syntax:"<<endl<<endl;
+ cerr<<::arg().helpstring()<<endl;
+ exit(1);
+ }
+
+ if((g_mode==GORACLE || g_mode==ORACLE) && !::arg().mustDo("transactions"))
+ cout<<"set autocommit on;"<<endl;
+
+ namedfile=::arg()["named-conf"];
+ zonefile=::arg()["zone"];
+
+ int count=0, num_domainsdone=0;
+
+ if(zonefile.empty()) {
+ BindParser BP;
+ BP.setVerbose(::arg().mustDo("verbose"));
+ BP.parse(namedfile.empty() ? "./named.conf" : namedfile);
+
+ vector<BindDomainInfo> domains=BP.getDomains();
+ struct stat st;
+ for(vector<BindDomainInfo>::iterator i=domains.begin(); i!=domains.end(); ++i) {
+ if(stat(i->filename.c_str(), &st) == 0) {
+ i->d_dev = st.st_dev;
+ i->d_ino = st.st_ino;
+ }
+ }
+
+ sort(domains.begin(), domains.end()); // put stuff in inode order
+
+ int numdomains=domains.size();
+ int tick=numdomains/100;
+
+ for(vector<BindDomainInfo>::const_iterator i=domains.begin();
+ i!=domains.end();
+ ++i)
+ {
+ if(i->type!="master" && i->type!="slave") {
+ cerr<<" Warning! Skipping '"<<i->type<<"' zone '"<<i->name<<"'"<<endl;
+ continue;
+ }
+ try {
+ startNewTransaction();
+
+ emitDomain(i->name, &(i->masters));
+
+ ZoneParserTNG zpt(i->filename, i->name, BP.getDirectory());
+ DNSResourceRecord rr;
+ bool seenSOA=false;
+ string comment;
+ while(zpt.get(rr, &comment)) {
+ if(filterDupSOA && seenSOA && rr.qtype.getCode() == QType::SOA)
+ continue;
+ if(rr.qtype.getCode() == QType::SOA)
+ seenSOA=true;
+
+ emitRecord(i->name, rr.qname, rr.qtype.getName(), rr.content, rr.ttl, comment);
+ }
+ num_domainsdone++;
+ }
+ catch(std::exception &ae) {
+ if(!::arg().mustDo("on-error-resume-next"))
+ throw;
+ else
+ cerr<<endl<<ae.what()<<endl;
+ }
+ catch(PDNSException &ae) {
+ if(!::arg().mustDo("on-error-resume-next"))
+ throw;
+ else
+ cerr<<ae.reason<<endl;
+ }
+
+
+ if(!tick || !((count++)%tick))
+ cerr<<"\r"<<count*100/numdomains<<"% done ("<<i->filename<<")\033\133\113";
+ }
+ cerr<<"\r100% done\033\133\113"<<endl;
+ }
+ else {
+ DNSName zonename;
+ if(!::arg()["zone-name"].empty())
+ zonename = DNSName(::arg()["zone-name"]);
+
+ ZoneParserTNG zpt(zonefile, zonename);
+ DNSResourceRecord rr;
+ startNewTransaction();
+ string comment;
+ bool seenSOA=false;
+ bool haveEmittedZone = false;
+ while(zpt.get(rr, &comment)) {
+ if(filterDupSOA && seenSOA && rr.qtype.getCode() == QType::SOA)
+ continue;
+ if(rr.qtype.getCode() == QType::SOA)
+ seenSOA=true;
+ if(!haveEmittedZone) {
+ if(!zpt.getZoneName().empty()){
+ emitDomain(zpt.getZoneName());
+ haveEmittedZone = true;
+ } else {
+ // We have no zonename yet, don't emit
+ continue;
+ }
+ }
+
+ emitRecord(zpt.getZoneName(), rr.qname, rr.qtype.getName(), rr.content, rr.ttl, comment);
+ }
+ num_domainsdone=1;
+ }
+ cerr<<num_domainsdone<<" domains were fully parsed, containing "<<g_numRecords<<" records\n";
+
+ if(::arg().mustDo("transactions") && g_intransaction) {
+ if(g_mode != SQLITE)
+ cout<<"COMMIT WORK;"<<endl;
+ else
+ cout<<"COMMIT;"<<endl;
+ }
+ return 0;
+}
+catch(PDNSException &ae) {
+ cerr<<"\nFatal error: "<<ae.reason<<endl;
+ return 1;
+}
+catch(std::exception &e) {
+ cerr<<"\ndied because of STL error: "<<e.what()<<endl;
+ return 1;
+}
+catch(...) {
+ cerr<<"\ndied because of unknown exception"<<endl;
+ return 1;
+}
--- /dev/null
+/*
+ PowerDNS Versatile Database Driven Nameserver
+ Copyright (C) 2005 - 2008 PowerDNS.COM BV
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License version 2
+ as published by the Free Software Foundation
+
+ Additionally, the license of this program contains a special
+ exception which allows to distribute the program in binary form when
+ it is linked against OpenSSL.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
+*/
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+#include "dnsparser.hh"
+#include "sstuff.hh"
+#include "misc.hh"
+#include "dnswriter.hh"
+#include "dnsrecords.hh"
+#include "misc.hh"
+#include <fstream>
+#include "dns.hh"
+#include "zoneparser-tng.hh"
+#include <deque>
+#include <boost/algorithm/string.hpp>
+#include <system_error>
+
+static string g_INstr("IN");
+
+ZoneParserTNG::ZoneParserTNG(const string& fname, const DNSName& zname, const string& reldir) : d_reldir(reldir),
+ d_zonename(zname), d_defaultttl(3600),
+ d_templatecounter(0), d_templatestop(0),
+ d_templatestep(0), d_havedollarttl(false){
+ stackFile(fname);
+}
+
+ZoneParserTNG::ZoneParserTNG(const vector<string> zonedata, const DNSName& zname):
+ d_zonename(zname), d_defaultttl(3600),
+ d_templatecounter(0), d_templatestop(0),
+ d_templatestep(0), d_havedollarttl(false)
+{
+ d_zonedata = zonedata;
+ d_zonedataline = d_zonedata.begin();
+ d_fromfile = false;
+}
+
+void ZoneParserTNG::stackFile(const std::string& fname)
+{
+ FILE *fp=fopen(fname.c_str(), "r");
+ if(!fp) {
+ std::error_code ec (errno,std::generic_category());
+ throw std::system_error(ec, "Unable to open file '"+fname+"': "+stringerror());
+ }
+
+ filestate fs(fp, fname);
+ d_filestates.push(fs);
+ d_fromfile = true;
+}
+
+ZoneParserTNG::~ZoneParserTNG()
+{
+ while(!d_filestates.empty()) {
+ fclose(d_filestates.top().d_fp);
+ d_filestates.pop();
+ }
+}
+
+static string makeString(const string& line, const pair<string::size_type, string::size_type>& range)
+{
+ return string(line.c_str() + range.first, range.second - range.first);
+}
+
+static bool isTimeSpec(const string& nextpart)
+{
+ if(nextpart.empty())
+ return false;
+ for(string::const_iterator iter = nextpart.begin(); iter != nextpart.end(); ++iter) {
+ if(isdigit(*iter))
+ continue;
+ if(iter+1 != nextpart.end())
+ return false;
+ char c=tolower(*iter);
+ return (c=='s' || c=='m' || c=='h' || c=='d' || c=='w' || c=='y');
+ }
+ return true;
+}
+
+
+unsigned int ZoneParserTNG::makeTTLFromZone(const string& str)
+{
+ if(str.empty())
+ return 0;
+
+ unsigned int val;
+ try {
+ val=pdns_stou(str);
+ }
+ catch (const std::out_of_range& oor) {
+ throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
+ }
+
+ char lc=dns_tolower(str[str.length()-1]);
+ if(!isdigit(lc))
+ switch(lc) {
+ case 's':
+ break;
+ case 'm':
+ val*=60; // minutes, not months!
+ break;
+ case 'h':
+ val*=3600;
+ break;
+ case 'd':
+ val*=3600*24;
+ break;
+ case 'w':
+ val*=3600*24*7;
+ break;
+ case 'y': // ? :-)
+ val*=3600*24*365;
+ break;
+
+ default:
+ throw PDNSException("Unable to parse time specification '"+str+"' "+getLineOfFile());
+ }
+ return val;
+}
+
+bool ZoneParserTNG::getTemplateLine()
+{
+ if(d_templateparts.empty() || d_templatecounter > d_templatestop) // no template, or done with
+ return false;
+
+ string retline;
+ for(parts_t::const_iterator iter = d_templateparts.begin() ; iter != d_templateparts.end(); ++iter) {
+ if(iter != d_templateparts.begin())
+ retline+=" ";
+
+ string part=makeString(d_templateline, *iter);
+
+ /* a part can contain a 'naked' $, an escaped $ (\$), or ${offset,width,radix}, with width defaulting to 0,
+ and radix beging 'd', 'o', 'x' or 'X', defaulting to 'd'.
+
+ The width is zero-padded, so if the counter is at 1, the offset is 15, with is 3, and the radix is 'x',
+ output will be '010', from the input of ${15,3,x}
+ */
+
+ string outpart;
+ outpart.reserve(part.size()+5);
+ bool inescape=false;
+
+ for(string::size_type pos = 0; pos < part.size() ; ++pos) {
+ char c=part[pos];
+ if(inescape) {
+ outpart.append(1, c);
+ inescape=false;
+ continue;
+ }
+
+ if(part[pos]=='\\') {
+ inescape=true;
+ continue;
+ }
+ if(c=='$') {
+ if(pos + 1 == part.size() || part[pos+1]!='{') { // a trailing $, or not followed by {
+ outpart.append(std::to_string(d_templatecounter));
+ continue;
+ }
+
+ // need to deal with { case
+
+ pos+=2;
+ string::size_type startPos=pos;
+ for(; pos < part.size() && part[pos]!='}' ; ++pos)
+ ;
+
+ if(pos == part.size()) // partial spec
+ break;
+
+ // we are on the '}'
+
+ string spec(part.c_str() + startPos, part.c_str() + pos);
+ int offset=0, width=0;
+ char radix='d';
+ sscanf(spec.c_str(), "%d,%d,%c", &offset, &width, &radix); // parse format specifier
+
+ char format[12];
+ snprintf(format, sizeof(format) - 1, "%%0%d%c", width, radix); // make into printf-style format
+
+ char tmp[80];
+ snprintf(tmp, sizeof(tmp)-1, format, d_templatecounter + offset); // and do the actual printing
+ outpart+=tmp;
+ }
+ else
+ outpart.append(1, c);
+ }
+ retline+=outpart;
+ }
+ d_templatecounter+=d_templatestep;
+
+ d_line = retline;
+ return true;
+}
+
+void chopComment(string& line)
+{
+ if(line.find(';')==string::npos)
+ return;
+ string::size_type pos, len = line.length();
+ bool inQuote=false;
+ for(pos = 0 ; pos < len; ++pos) {
+ if(line[pos]=='\\')
+ pos++;
+ else if(line[pos]=='"')
+ inQuote=!inQuote;
+ else if(line[pos]==';' && !inQuote)
+ break;
+ }
+ if(pos != len)
+ line.resize(pos);
+}
+
+bool findAndElide(string& line, char c)
+{
+ string::size_type pos, len = line.length();
+ bool inQuote=false;
+ for(pos = 0 ; pos < len; ++pos) {
+ if(line[pos]=='\\')
+ pos++;
+ else if(line[pos]=='"')
+ inQuote=!inQuote;
+ else if(line[pos]==c && !inQuote)
+ break;
+ }
+ if(pos != len) {
+ line.erase(pos, 1);
+ return true;
+ }
+ return false;
+}
+
+DNSName ZoneParserTNG::getZoneName()
+{
+ return d_zonename;
+}
+
+string ZoneParserTNG::getLineOfFile()
+{
+ if (d_zonedata.size() > 0)
+ return "on line "+std::to_string(std::distance(d_zonedata.begin(), d_zonedataline))+" of given string";
+
+ if (d_filestates.empty())
+ return "";
+
+ return "on line "+std::to_string(d_filestates.top().d_lineno)+" of file '"+d_filestates.top().d_filename+"'";
+}
+
+pair<string,int> ZoneParserTNG::getLineNumAndFile()
+{
+ return {d_filestates.top().d_filename, d_filestates.top().d_lineno};
+}
+
+// ODD: this function never fills out the prio field! rest of pdns compensates though
+bool ZoneParserTNG::get(DNSResourceRecord& rr, std::string* comment)
+{
+ retry:;
+ if(!getTemplateLine() && !getLine())
+ return false;
+
+ boost::trim_right_if(d_line, is_any_of(" \t\r\n\x1a"));
+ if(comment)
+ comment->clear();
+ if(comment && d_line.find(';') != string::npos)
+ *comment = d_line.substr(d_line.find(';'));
+ parts_t parts;
+ vstringtok(parts, d_line);
+
+ if(parts.empty())
+ goto retry;
+
+ if(parts[0].first != parts[0].second && d_line[parts[0].first]==';') // line consisting of nothing but comments
+ goto retry;
+
+ if(d_line[0]=='$') {
+ string command=makeString(d_line, parts[0]);
+ if(pdns_iequals(command,"$TTL") && parts.size() > 1) {
+ d_defaultttl=makeTTLFromZone(trim_right_copy_if(makeString(d_line, parts[1]), is_any_of(";")));
+ d_havedollarttl=true;
+ }
+ else if(pdns_iequals(command,"$INCLUDE") && parts.size() > 1 && d_fromfile) {
+ string fname=unquotify(makeString(d_line, parts[1]));
+ if(!fname.empty() && fname[0]!='/' && !d_reldir.empty())
+ fname=d_reldir+"/"+fname;
+ stackFile(fname);
+ }
+ else if(pdns_iequals(command, "$ORIGIN") && parts.size() > 1) {
+ d_zonename = DNSName(makeString(d_line, parts[1]));
+ }
+ else if(pdns_iequals(command, "$GENERATE") && parts.size() > 2) {
+ // $GENERATE 1-127 $ CNAME $.0
+ string range=makeString(d_line, parts[1]);
+ d_templatestep=1;
+ d_templatestop=0;
+ sscanf(range.c_str(),"%d-%d/%d", &d_templatecounter, &d_templatestop, &d_templatestep);
+ d_templateline=d_line;
+ parts.pop_front();
+ parts.pop_front();
+
+ d_templateparts=parts;
+ goto retry;
+ }
+ else
+ throw exception("Can't parse zone line '"+d_line+"' "+getLineOfFile());
+ goto retry;
+ }
+
+ bool prevqname=false;
+ string qname = makeString(d_line, parts[0]); // Don't use DNSName here!
+ if(dns_isspace(d_line[0])) {
+ rr.qname=d_prevqname;
+ prevqname=true;
+ }else {
+ rr.qname=DNSName(qname);
+ parts.pop_front();
+ if(qname.empty() || qname[0]==';')
+ goto retry;
+ }
+ if(qname=="@")
+ rr.qname=d_zonename;
+ else if(!prevqname && !isCanonical(qname))
+ rr.qname += d_zonename;
+ d_prevqname=rr.qname;
+
+ if(parts.empty())
+ throw exception("Line with too little parts "+getLineOfFile());
+
+ string nextpart;
+
+ rr.ttl=d_defaultttl;
+ bool haveTTL=0, haveQTYPE=0;
+ pair<string::size_type, string::size_type> range;
+
+ while(!parts.empty()) {
+ range=parts.front();
+ parts.pop_front();
+ nextpart=makeString(d_line, range);
+ if(nextpart.empty())
+ break;
+
+ if(nextpart.find(';')!=string::npos) {
+ break;
+ }
+
+ // cout<<"Next part: '"<<nextpart<<"'"<<endl;
+
+ if(pdns_iequals(nextpart, g_INstr)) {
+ // cout<<"Ignoring 'IN'\n";
+ continue;
+ }
+ if(!haveTTL && !haveQTYPE && isTimeSpec(nextpart)) {
+ rr.ttl=makeTTLFromZone(nextpart);
+ haveTTL=true;
+ // cout<<"ttl is probably: "<<rr.ttl<<endl;
+ continue;
+ }
+ if(haveQTYPE)
+ break;
+
+ try {
+ rr.qtype=DNSRecordContent::TypeToNumber(nextpart);
+ // cout<<"Got qtype ("<<rr.qtype.getCode()<<")\n";
+ haveQTYPE=1;
+ continue;
+ }
+ catch(...) {
+ throw runtime_error("Parsing zone content "+getLineOfFile()+
+ ": '"+nextpart+
+ "' doesn't look like a qtype, stopping loop");
+ }
+ }
+ if(!haveQTYPE)
+ throw exception("Malformed line "+getLineOfFile()+": '"+d_line+"'");
+
+ // rr.content=d_line.substr(range.first);
+ rr.content.assign(d_line, range.first, string::npos);
+ chopComment(rr.content);
+ trim_if(rr.content, is_any_of(" \r\n\t\x1a"));
+
+ if(rr.content.size()==1 && rr.content[0]=='@')
+ rr.content=d_zonename.toString();
+
+ if(findAndElide(rr.content, '(')) { // have found a ( and elided it
+ if(!findAndElide(rr.content, ')')) {
+ while(getLine()) {
+ trim_right(d_line);
+ chopComment(d_line);
+ trim(d_line);
+
+ bool ended = findAndElide(d_line, ')');
+ rr.content+=" "+d_line;
+ if(ended)
+ break;
+ }
+ }
+ }
+ trim_if(rr.content, is_any_of(" \r\n\t\x1a"));
+
+ vector<string> recparts;
+ switch(rr.qtype.getCode()) {
+ case QType::MX:
+ stringtok(recparts, rr.content);
+ if(recparts.size()==2) {
+ if (recparts[1]!=".")
+ recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
+ rr.content=recparts[0]+" "+recparts[1];
+ }
+ break;
+
+ case QType::RP:
+ stringtok(recparts, rr.content);
+ if(recparts.size()==2) {
+ recparts[0] = toCanonic(d_zonename, recparts[0]).toStringRootDot();
+ recparts[1] = toCanonic(d_zonename, recparts[1]).toStringRootDot();
+ rr.content=recparts[0]+" "+recparts[1];
+ }
+ break;
+
+ case QType::SRV:
+ stringtok(recparts, rr.content);
+ if(recparts.size()==4) {
+ if(recparts[3]!=".")
+ recparts[3] = toCanonic(d_zonename, recparts[3]).toStringRootDot();
+ rr.content=recparts[0]+" "+recparts[1]+" "+recparts[2]+" "+recparts[3];
+ }
+ break;
+
+
+ case QType::NS:
+ case QType::CNAME:
+ case QType::DNAME:
+ case QType::PTR:
+ case QType::AFSDB:
+ rr.content=toCanonic(d_zonename, rr.content).toStringRootDot();
+ break;
+
+ case QType::SOA:
+ stringtok(recparts, rr.content);
+ if(recparts.size() > 7)
+ throw PDNSException("SOA record contents for "+rr.qname.toString()+" contains too many parts");
+ if(recparts.size() > 1) {
+ try {
+ recparts[0]=toCanonic(d_zonename, recparts[0]).toStringRootDot();
+ recparts[1]=toCanonic(d_zonename, recparts[1]).toStringRootDot();
+ } catch (runtime_error &re) {
+ throw PDNSException(re.what());
+ }
+ }
+ rr.content.clear();
+ for(string::size_type n = 0; n < recparts.size(); ++n) {
+ if(n)
+ rr.content.append(1,' ');
+
+ if(n > 1)
+ rr.content+=std::to_string(makeTTLFromZone(recparts[n]));
+ else
+ rr.content+=recparts[n];
+
+ if(n==6 && !d_havedollarttl)
+ d_defaultttl=makeTTLFromZone(recparts[n]);
+ }
+ break;
+ default:;
+ }
+
+ rr.d_place=DNSResourceRecord::ANSWER;
+ return true;
+}
+
+
+bool ZoneParserTNG::getLine()
+{
+ if (d_zonedata.size() > 0) {
+ if (d_zonedataline != d_zonedata.end()) {
+ d_line = *d_zonedataline;
+ d_zonedataline++;
+ return true;
+ }
+ return false;
+ }
+ while(!d_filestates.empty()) {
+ if(stringfgets(d_filestates.top().d_fp, d_line)) {
+ d_filestates.top().d_lineno++;
+ return true;
+ }
+ fclose(d_filestates.top().d_fp);
+ d_filestates.pop();
+ }
+ return false;
+}
--- /dev/null
+/*
+ * This file is part of PowerDNS or dnsdist.
+ * Copyright -- PowerDNS.COM B.V. and its contributors
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of version 2 of the GNU General Public License as
+ * published by the Free Software Foundation.
+ *
+ * In addition, for the avoidance of any doubt, permission is granted to
+ * link this program with OpenSSL and to (re)distribute the binaries
+ * produced as the result of such linking.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#ifndef PDNS_ZONEPARSER_TNG
+#define PDNS_ZONEPARSER_TNG
+#include <string>
+#include <cstdio>
+#include <stdexcept>
+#include <stack>
+
+#include "namespaces.hh"
+
+class ZoneParserTNG
+{
+public:
+ ZoneParserTNG(const string& fname, const DNSName& zname=DNSName("."), const string& reldir="");
+ ZoneParserTNG(const vector<string> zonedata, const DNSName& zname);
+
+ ~ZoneParserTNG();
+ bool get(DNSResourceRecord& rr, std::string* comment=0);
+ typedef runtime_error exception;
+ typedef deque<pair<string::size_type, string::size_type> > parts_t;
+ DNSName getZoneName();
+ string getLineOfFile(); // for error reporting purposes
+ pair<string,int> getLineNumAndFile(); // idem
+private:
+ bool getLine();
+ bool getTemplateLine();
+ void stackFile(const std::string& fname);
+ unsigned makeTTLFromZone(const std::string& str);
+
+ struct filestate {
+ filestate(FILE* fp, string filename) : d_fp(fp), d_filename(filename), d_lineno(0){}
+ FILE *d_fp;
+ string d_filename;
+ int d_lineno;
+ };
+
+ string d_reldir;
+ string d_line;
+ DNSName d_prevqname;
+ DNSName d_zonename;
+ string d_templateline;
+ vector<string> d_zonedata;
+ vector<string>::iterator d_zonedataline;
+ std::stack<filestate> d_filestates;
+ parts_t d_templateparts;
+ int d_defaultttl;
+ uint32_t d_templatecounter, d_templatestop, d_templatestep;
+ bool d_havedollarttl;
+ bool d_fromfile;
+};
+
+#endif
--- /dev/null
+unit.test. 300 IN SOA ns.unit.test. hostmaster.unit.test. 1 3600 1200 604800 300
+unit.test. 300 IN NS ns.unit.test.
+unit.test. 300 IN MX 30 mx.unit.test.
+unit.test. 300 IN A 1.2.3.4
+root.mx.unit.test. 300 IN MX 20 .
+root.srv.unit.test. 300 IN SRV 10 10 5060 .
+naptr-a.unit.test. 300 IN NAPTR 100 10 "" "" "/urn:cid:.+@([^\.]+\.)(.*)$/\2/i" .
+naptr-b.unit.test. 300 IN NAPTR 100 50 "s" "http+I2L+I2C+I2R" "" _http._tcp.rec.test.
+unit.test. 300 IN SOA ns.unit.test. hostmaster.unit.test. 1 3600 1200 604800 300